From 42c94922ce3594c70d477a38ff1db377f54fcbfb Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 18 Nov 2019 21:50:22 -0500 Subject: [PATCH 001/105] Basic Object3D hierarchy --- src/TSGL/Cone.cpp | 46 ++++++ src/TSGL/Cone.h | 29 ++++ src/TSGL/Cube.cpp | 82 ++++++++++ src/TSGL/Cube.h | 35 +++++ src/TSGL/Cuboid.cpp | 146 ++++++++++++++++++ src/TSGL/Cuboid.h | 43 ++++++ src/TSGL/Cylinder.cpp | 114 ++++++++++++++ src/TSGL/Cylinder.h | 39 +++++ src/TSGL/Ellipsoid.cpp | 197 ++++++++++++++++++++++++ src/TSGL/Ellipsoid.h | 50 ++++++ src/TSGL/Object3D.cpp | 335 +++++++++++++++++++++++++++++++++++++++++ src/TSGL/Object3D.h | 82 ++++++++++ src/TSGL/Prism.cpp | 137 +++++++++++++++++ src/TSGL/Prism.h | 42 ++++++ src/TSGL/Pyramid.cpp | 173 +++++++++++++++++++++ src/TSGL/Pyramid.h | 47 ++++++ src/TSGL/Sphere.cpp | 129 ++++++++++++++++ src/TSGL/Sphere.h | 42 ++++++ 18 files changed, 1768 insertions(+) create mode 100644 src/TSGL/Cone.cpp create mode 100644 src/TSGL/Cone.h create mode 100644 src/TSGL/Cube.cpp create mode 100644 src/TSGL/Cube.h create mode 100644 src/TSGL/Cuboid.cpp create mode 100644 src/TSGL/Cuboid.h create mode 100644 src/TSGL/Cylinder.cpp create mode 100644 src/TSGL/Cylinder.h create mode 100644 src/TSGL/Ellipsoid.cpp create mode 100644 src/TSGL/Ellipsoid.h create mode 100644 src/TSGL/Object3D.cpp create mode 100644 src/TSGL/Object3D.h create mode 100644 src/TSGL/Prism.cpp create mode 100644 src/TSGL/Prism.h create mode 100644 src/TSGL/Pyramid.cpp create mode 100644 src/TSGL/Pyramid.h create mode 100644 src/TSGL/Sphere.cpp create mode 100644 src/TSGL/Sphere.h diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp new file mode 100644 index 000000000..28dc99280 --- /dev/null +++ b/src/TSGL/Cone.cpp @@ -0,0 +1,46 @@ +#include "Cone.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cone. + * \details Explicit constructor for a Cone object. + * \param x The x coordinate of the center of the Cone. + * \param y The y coordinate of the center of the Cone. + * \param z The z coordinate of the center of the Cone. + * \param height The distance from the center of the base to tip of the Cone. + * \param radius The radius of the Cone's circular base. + * \param yaw The Cone's yaw. + * \param pitch The Cone's pitch. + * \param roll The Cone's roll. + * \param c A ColorFloat for the Cone's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Cone with a buffer for storing the specified numbered of vertices. + */ +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) +: Pyramid(x, y, z, height, radius, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll, c) { } + + /*! + * \brief Explicitly constructs a new Cone. + * \details Explicit constructor for a Cone object. + * \param x The x coordinate of the center of the Cone. + * \param y The y coordinate of the center of the Cone. + * \param z The z coordinate of the center of the Cone. + * \param height The distance from the center of the base to tip of the Cone. + * \param radius The radius of the Cone's circular base. + * \param yaw The Cone's yaw. + * \param pitch The Cone's pitch. + * \param roll The Cone's roll. + * \param c An array of ColorFloats containing the Cone's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Cone with a buffer for storing the specified numbered of vertices. + */ +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) +: Pyramid(x, y, z, height, radius, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll, c) { } + +/*! + * \brief Destructor for the Cone. + */ +Cone::~Cone() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cone.h b/src/TSGL/Cone.h new file mode 100644 index 000000000..41bc3410a --- /dev/null +++ b/src/TSGL/Cone.h @@ -0,0 +1,29 @@ +/* + * Cone.h extends Pyramid and provides a class for drawing a cone. + */ + +#ifndef CONE_H_ +#define CONE_H_ + +#include "Pyramid.h" // For extending our Pyramid object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cone + * \brief Draw an arbitrary Cone with colored vertices. + * \details Cone is a class for holding vertex data for a cone. + * \details Cone is a subclass of Pyramid with a base of (radius * 3) sides, minimum of 3. + */ +class Cone : public Pyramid { +public: + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); + + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Cone(); +}; + +} + +#endif /* CONE_H_ */ \ No newline at end of file diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp new file mode 100644 index 000000000..fafe0beaa --- /dev/null +++ b/src/TSGL/Cube.cpp @@ -0,0 +1,82 @@ +#include "Cube.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cube. + * \details Explicit constructor for a Cube object. + * \param x The x coordinate of the center of the Cube. + * \param y The y coordinate of the center of the Cube. + * \param z The z coordinate of the center of the Cube. + * \param sideLength The side length of the Cube. + * \param yaw The Cube's yaw. + * \param pitch The Cube's pitch. + * \param roll The Cube's roll. + * \param c A ColorFloat for the Cube's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cube with a buffer for storing the specified numbered of vertices. + */ +Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (sideLength <= 0) { + TsglDebug("Cannot have a Cube with non-positive sidelength."); + } +} + + /*! + * \brief Explicitly constructs a new Cube. + * \details Explicit constructor for a Cube object. + * \param x The x coordinate of the center of the Cube. + * \param y The y coordinate of the center of the Cube. + * \param z The z coordinate of the center of the Cube. + * \param sideLength The side length of the Cube. + * \param yaw The Cube's yaw. + * \param pitch The Cube's pitch. + * \param roll The Cube's roll. + * \param c An array of ColorFloats for the Cube's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cube with a buffer for storing the specified numbered of vertices. + */ +Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c[]) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (sideLength <= 0) { + TsglDebug("Cannot have a Cube with non-positive side length."); + } +} + +/** + * \brief Mutates the distance from the Cube's front face to its back face. + * \param height The Cube's new length. + */ +void Cube::setSideLength(float length) { + attribMutex.lock(); + if (length <= 0) { + TsglDebug("Cannot have a Cube with side length less than or equal to 0."); + attribMutex.unlock(); + return; + } + mySideLength = length; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cube's front face to its back face by the parameter amount. + * \param delta The amount by which to change the length of the Cube. + */ +void Cube::changeSideLengthBy(float delta) { + attribMutex.lock(); + if (mySideLength + delta <= 0) { + TsglDebug("Cannot have a Cube with length less than or equal to 0."); + attribMutex.unlock(); + return; + } + mySideLength += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Cube. + */ +Cube::~Cube() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h new file mode 100644 index 000000000..1fa5ef906 --- /dev/null +++ b/src/TSGL/Cube.h @@ -0,0 +1,35 @@ +/* + * Cube.h extends Prism and provides a class for drawing a Cube. + */ + +#ifndef CUBE_H_ +#define CUBE_H_ + +#include "Prism.h" // For extending our Prism object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cube + * \brief Draw an arbitrary Cube with colored vertices. + * \details Cube is a class for holding vertex data for a Cube. + * \details Cube is a subclass of Prism with all square faces. + */ +class Cube : public Prism { +protected: + float mySideLength; +public: + Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c); + + Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setSideLength(float length); + + virtual void changeSideLengthBy(float delta); + + virtual ~Cube(); +}; + +} + +#endif /* CUBE_H_ */ \ No newline at end of file diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp new file mode 100644 index 000000000..e6f2d9dcb --- /dev/null +++ b/src/TSGL/Cuboid.cpp @@ -0,0 +1,146 @@ +#include "Cuboid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cuboid. + * \details Explicit constructor for a Cuboid object. + * \param x The x coordinate of the center of the Cuboid. + * \param y The y coordinate of the center of the Cuboid. + * \param z The z coordinate of the center of the Cuboid. + * \param length The length of the Cuboid. + * \param width The width of the Cuboid. + * \param height The height of the Cuboid. + * \param yaw The Cuboid's yaw. + * \param pitch The Cuboid's pitch. + * \param roll The Cuboid's roll. + * \param c A ColorFloat for the Cuboid's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cuboid with a buffer for storing the specified numbered of vertices. + */ +Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (length <= 0 || width <= 0 || height <= 0) { + TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); + } +} + + /*! + * \brief Explicitly constructs a new Cuboid. + * \details Explicit constructor for a Cuboid object. + * \param x The x coordinate of the center of the Cuboid. + * \param y The y coordinate of the center of the Cuboid. + * \param z The z coordinate of the center of the Cuboid. + * \param length The length of the Cuboid. + * \param width The width of the Cuboid. + * \param height The height of the Cuboid. + * \param yaw The Cuboid's yaw. + * \param pitch The Cuboid's pitch. + * \param roll The Cuboid's roll. + * \param c An array of ColorFloats for the Cuboid's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cuboid with a buffer for storing the specified numbered of vertices. + */ +Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c[]) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (length <= 0 || width <= 0 || height <= 0) { + TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); + } +} + +/** + * \brief Mutates the distance from the Cuboid's front face to its back face. + * \param height The Cuboid's new length. + */ +void Cuboid::setLength(float length) { + attribMutex.lock(); + if (length <= 0) { + TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); + attribMutex.unlock(); + return; + } + myLength = length; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's front face to its back face by the parameter amount. + * \param delta The amount by which to change the length of the Cuboid. + */ +void Cuboid::changeLengthBy(float delta) { + attribMutex.lock(); + if (myLength + delta <= 0) { + TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); + attribMutex.unlock(); + return; + } + myLength += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's left face to its right face. + * \param height The Cuboid's new width. + */ +void Cuboid::setWidth(float width) { + attribMutex.lock(); + if (width <= 0) { + TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); + attribMutex.unlock(); + return; + } + myWidth = width; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the Cuboid's left face to its right face by the parameter amount. + * \param delta The amount by which to change the width of the Cuboid. + */ +void Cuboid::changeWidthBy(float delta) { + attribMutex.lock(); + if (myWidth + delta <= 0) { + TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); + attribMutex.unlock(); + return; + } + myWidth += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cuboid's base to the top. + * \param height The Cuboid's new height. + */ +void Cuboid::setHeight(float height) { + attribMutex.lock(); + if (height <= 0) { + TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cuboid's base to the top by the parameter amount. + * \param delta The amount by which to change the height of the Cuboid. + */ +void Cuboid::changeHeightBy(float delta) { + attribMutex.lock(); + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Cuboid. + */ +Cuboid::~Cuboid() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h new file mode 100644 index 000000000..7985d4e3a --- /dev/null +++ b/src/TSGL/Cuboid.h @@ -0,0 +1,43 @@ +/* + * Cuboid.h extends Prism and provides a class for drawing a Cuboid. + */ + +#ifndef CUBOID_H_ +#define CUBOID_H_ + +#include "Prism.h" // For extending our Prism object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cuboid + * \brief Draw an arbitrary Cuboid with colored vertices. + * \details Cuboid is a class for holding vertex data for a Cuboid. + * \details Cuboid is a subclass of Prism with all rectangular faces. + */ +class Cuboid : public Prism { +protected: + float myLength, myWidth, myHeight; +public: + Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c); + + Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setLength(float length); + + virtual void changeLengthBy(float delta); + + virtual void setWidth(float width); + + virtual void changeWidthBy(float delta); + + virtual void setHeight(float height); + + virtual void changeHeightBy(float delta); + + virtual ~Cuboid(); +}; + +} + +#endif /* CUBOID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp new file mode 100644 index 000000000..2c225f3ad --- /dev/null +++ b/src/TSGL/Cylinder.cpp @@ -0,0 +1,114 @@ +#include "Cylinder.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Cylinder. + * \details Explicit constructor for a Cylinder object. + * \param x The x coordinate of the center of the Cylinder. + * \param y The y coordinate of the center of the Cylinder. + * \param z The z coordinate of the center of the Cylinder. + * \param height The height of the Cylinder. + * \param radius The radius of the Cylinder's circular base. + * \param yaw The Cylinder's yaw. + * \param pitch The Cylinder's pitch. + * \param roll The Cylinder's roll. + * \param c A ColorFloat for the Cylinder's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cylinder with a buffer for storing the specified numbered of vertices. + */ +Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Cylinder with non-positive height or radius."); + } +} + + /*! + * \brief Explicitly constructs a new Cylinder. + * \details Explicit constructor for a Cylinder object. + * \param x The x coordinate of the center of the Cylinder. + * \param y The y coordinate of the center of the Cylinder. + * \param z The z coordinate of the center of the Cylinder. + * \param height The height of the Cylinder. + * \param radius The radius of the Cylinder's circular base. + * \param yaw The Cylinder's yaw. + * \param pitch The Cylinder's pitch. + * \param roll The Cylinder's roll. + * \param c An array of ColorFloats for the Cylinder's vertex colors. + * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. + * \return A new Cylinder with a buffer for storing the specified numbered of vertices. + */ +Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) +: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Cylinder with non-positive height or radius."); + } +} + +/** + * \brief Mutates the radius of the Cylinder's base. + * \param height The Cylinder's new base radius. + */ +void Cylinder::setRadius(float radius) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Cylinder with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius = radius; + attribMutex.unlock(); +} + +/** + * \brief Mutates the radius of the Cylinder's base by the parameter amount. + * \param delta The amount by which to change the radius of the Cylinder's base. + */ +void Cylinder::changeRadiusBy(float delta) { + attribMutex.lock(); + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Cylinder with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cylinder's base to the top. + * \param height The Cylinder's new height. + */ +void Cylinder::setHeight(float height) { + attribMutex.lock(); + if (height <= 0) { + TsglDebug("Cannot have a Cylinder with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Cylinder's base to the top by the parameter amount. + * \param delta The amount by which to change the height of the Cylinder. + */ +void Cylinder::changeHeightBy(float delta) { + attribMutex.lock(); + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Cylinder with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Cylinder. + */ +Cylinder::~Cylinder() { } + +} \ No newline at end of file diff --git a/src/TSGL/Cylinder.h b/src/TSGL/Cylinder.h new file mode 100644 index 000000000..6a44ad213 --- /dev/null +++ b/src/TSGL/Cylinder.h @@ -0,0 +1,39 @@ +/* + * Cylinder.h extends Prism and provides a class for drawing a Cylinder. + */ + +#ifndef CYLINDER_H_ +#define CYLINDER_H_ + +#include "Prism.h" // For extending our Prism object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Cylinder + * \brief Draw an arbitrary Cylinder with colored vertices. + * \details Cylinder is a class for holding vertex data for a Cylinder. + * \details Cylinder is a subclass of Prism with a circular base. + */ +class Cylinder : public Prism { +protected: + float myRadius, myHeight; +public: + Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); + + Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual void setRadius(float radius); + + virtual void changeRadiusBy(float delta); + + virtual void setHeight(float height); + + virtual void changeHeightBy(float delta); + + virtual ~Cylinder(); +}; + +} + +#endif /* CYLINDER_H_ */ \ No newline at end of file diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp new file mode 100644 index 000000000..8a918057c --- /dev/null +++ b/src/TSGL/Ellipsoid.cpp @@ -0,0 +1,197 @@ +#include "Ellipsoid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Ellipsoid. + * \details Explicit constructor for a Ellipsoid object. + * \param x The x coordinate of the center of the Ellipsoid. + * \param y The y coordinate of the center of the Ellipsoid. + * \param z The z coordinate of the center of the Ellipsoid. + * \param xRadius The Ellipsoid's radius on the x-axis. + * \param yRadius The Ellipsoid's radius on the y-axis. + * \param zRadius The Ellipsoid's radius on the z-axis. + * \param yaw The Ellipsoid's yaw. + * \param pitch The Ellipsoid's pitch. + * \param roll The Ellipsoid's roll. + * \param c A ColorFloat for the Ellipsoid's vertex colors. + * \warning An invariant is held where if any radius isn't positive then an error message is given. + * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. + */ +Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + } + myXRadius = xRadius; + myYRadius = yRadius; + myZRadius = zRadius; + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Ellipsoid. + * \details Explicit constructor for a Ellipsoid object. + * \param x The x coordinate of the center of the Ellipsoid. + * \param y The y coordinate of the center of the Ellipsoid. + * \param z The z coordinate of the center of the Ellipsoid. + * \param xRadius The Ellipsoid's radius on the x-axis. + * \param yRadius The Ellipsoid's radius on the y-axis. + * \param zRadius The Ellipsoid's radius on the z-axis. + * \param yaw The Ellipsoid's yaw. + * \param pitch The Ellipsoid's pitch. + * \param roll The Ellipsoid's roll. + * \param c An array of ColorFloats for the Ellipsoid's vertex colors. + * \warning An invariant is held where if any radius isn't positive then an error message is given. + * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. + */ +Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + } + myXRadius = xRadius; + myYRadius = yRadius; + myZRadius = zRadius; + attribMutex.unlock(); +} + +/** + * \brief Sets the Ellipsoid to a new color. + * \param c The new ColorFloat. + */ +void Ellipsoid::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c.R; + vertices[i*6 + 3] = c.G; + vertices[i*6 + 4] = c.B; + vertices[i*6 + 5] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Ellipsoid to an array of new colors. + * \param c An array of new ColorFloats. + */ +void Ellipsoid::setColor(ColorFloat c[]) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c[i].R; + vertices[i*6 + 3] = c[i].G; + vertices[i*6 + 4] = c[i].B; + vertices[i*6 + 5] = c[i].A; + } + attribMutex.unlock(); +} + +/** + * \brief Gets an array of the Ellipsoid's fill vertex colors. + * \return c An array of ColorFloats. + * \warning This method allocates memory. The caller is responsible for deallocating it. + */ +ColorFloat* Ellipsoid::getColor() { + ColorFloat * c = new ColorFloat[numberOfVertices]; + for(int i = 0; i < numberOfVertices; i++) { + c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); + } + return c; +} + +/** + * \brief Mutates the Ellipsoid's x-axis radius. + * \param radius The new x-axis radius of the Ellipsoid. + */ +void Ellipsoid::setXRadius(float radiusX) { + attribMutex.lock(); + if (radiusX <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myXRadius = radiusX; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Ellipsoid's x-axis radius by the parameter amount. + * \param delta The amount by which to change the x-axis radius of the Ellipsoid. + */ +void Ellipsoid::changeXRadiusBy(float delta) { + attribMutex.lock(); + if (myXRadius + delta <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myXRadius += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Ellipsoid's y-axis radius. + * \param radius The new y-axis radius of the Ellipsoid. + */ +void Ellipsoid::setYRadius(float radiusY) { + attribMutex.lock(); + if (radiusY <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myYRadius = radiusY; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Ellipsoid's y-axis radius by the parameter amount. + * \param delta The amount by which to change the y-axis radius of the Ellipsoid. + */ +void Ellipsoid::changeYRadiusBy(float delta) { + attribMutex.lock(); + if (myYRadius + delta <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myYRadius += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Ellipsoid's z-axis radius. + * \param radius The new z-axis radius of the Ellipsoid. + */ +void Ellipsoid::setZRadius(float radiusZ) { + attribMutex.lock(); + if (radiusZ <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myZRadius = radiusZ; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Ellipsoid's z-axis radius by the parameter amount. + * \param delta The amount by which to change the z-axis radius of the Ellipsoid. + */ +void Ellipsoid::changeZRadiusBy(float delta) { + attribMutex.lock(); + if (myZRadius + delta <= 0) { + TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myZRadius += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Ellipsoid. + */ +Ellipsoid::~Ellipsoid() { } + +} \ No newline at end of file diff --git a/src/TSGL/Ellipsoid.h b/src/TSGL/Ellipsoid.h new file mode 100644 index 000000000..454140e2c --- /dev/null +++ b/src/TSGL/Ellipsoid.h @@ -0,0 +1,50 @@ +/* + * Ellipsoid.h extends Object3D and provides a class for drawing a ellipsoid. + */ + +#ifndef ELLIPSOID_H_ +#define ELLIPSOID_H_ + +#include "Object3D.h" // For extending our Object3D object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Ellipsoid + * \brief Draw an arbitrary Ellipsoid with colored vertices. + * \details Ellipsoid is a class for holding vertex data for an Ellipsoid. + */ +class Ellipsoid : public Object3D { +protected: + float myXRadius, myYRadius, myZRadius; +public: + Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c); + + Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Ellipsoid(); + + virtual void draw(); + + virtual void setColor(ColorFloat c); + + virtual void setColor(ColorFloat c[]); + + virtual void setXRadius(float radiusX); + + virtual void changeXRadiusBy(float delta); + + virtual void setYRadius(float radiusY); + + virtual void changeYRadiusBy(float delta); + + virtual void setZRadius(float radiusZ); + + virtual void changeZRadiusBy(float delta); + + virtual ColorFloat* getColor(); +}; + +} + +#endif /* ELLIPSOID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp new file mode 100644 index 000000000..0e83050bf --- /dev/null +++ b/src/TSGL/Object3D.cpp @@ -0,0 +1,335 @@ +#include "Object3D.h" + +namespace tsgl { + +/*! + * \brief Constructs a new Object3D. + * \details + * - Usually vertices is filled with floating point values that represent the vertices of the Object3D to be drawn. + * - You may define other items in the constructor that pertain to the attributes of the subclass that is extending Object3D. + * - At a minimum, you *MUST* fill an array of floating point values that pertain to the vertices of the Object3D. + * \warning You must inherit the parent's constructor if you are extending Object3D. + * \note Refer to the Object3D class description for more details. + */ +Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z) : Drawable() { + isTextured = false; + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + myCenterX = x; + myCenterY = y; + myCenterZ = z; +} + +/*! + * \brief Draw the Object3D. + * \details This function actually draws the Object3D to the Canvas. + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the Object3D cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). + */ +void Object3D::draw() { + glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); +} + + /*! + * \brief Adds another vertex to a Object3D. + * \details This function initializes the next vertex in the Object3D and adds it to a Object3D buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { + if (init) { + TsglDebug("Cannot add anymore vertices."); + return; + } +// vertices[current] = x; +// vertices[current + 1] = y; +// vertices[current + 2] = color.R; +// vertices[current + 3] = color.G; +// vertices[current + 4] = color.B; +// vertices[current + 5] = color.A; +// current += 6; +// if (current == numberOfVertices*6) { +// init = true; +// attribMutex.lock(); +// float minX = 0, maxX = 0; +// float minY = 0, maxY = 0; +// minX = maxX = vertices[0]; +// //Find min and max X +// for(int i = 0; i < numberOfVertices; i++) { +// if( vertices[i*6] < minX ) +// minX = vertices[i*6]; +// else if( vertices[i*6] > maxX ) +// maxX = vertices[i*6]; +// } + +// minY = maxY = vertices[1]; +// //Find min and max X +// for(int i = 0; i < numberOfVertices; i++) { +// if( vertices[i*6+1] < minY ) +// minY = vertices[i*6+1]; +// else if( vertices[i*6+1] > maxY ) +// maxY = vertices[i*6+1]; +// } + +// myCenterX = (minX+maxX)/2; +// myCenterY = (minY+maxY)/2; +// myCenterZ = (minZ+maxZ)/2; + +// setRotationPoint(myCenterX, myCenterY, myCenterZ); + + attribMutex.unlock(); +// } +} + +/** + * \brief Sets the Object3D to a new color. + * \param c The new ColorFloat. + */ +void Object3D::setColor(ColorFloat c) { + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6 + 2] = c.R; + // vertices[i*6 + 3] = c.G; + // vertices[i*6 + 4] = c.B; + // vertices[i*6 + 5] = c.A; + // } +} + +/** + * \brief Sets the Object3D to a new array of colors. + * \param c The new array of ColorFloats. + */ +void Object3D::setColor(ColorFloat c[]) { + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6 + 2] = c[i].R; + // vertices[i*6 + 3] = c[i].G; + // vertices[i*6 + 4] = c[i].B; + // vertices[i*6 + 5] = c[i].A; + // } +} + +/** + * \brief Alters the Object3D's x position + * \param deltaX The difference between the new and old vertex x coordinates. + */ +void Object3D::changeXBy(float deltaX) { + attribMutex.lock(); + myCenterX += deltaX; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's y position + * \param deltaY The difference between the new and old vertex y coordinates. + */ +void Object3D::changeYBy(float deltaY) { + attribMutex.lock(); + myCenterY += deltaY; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's z position + * \param deltaZ The difference between the new and old vertex z coordinates. + */ +void Object3D::changeZBy(float deltaZ) { + attribMutex.lock(); + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's vertex locations. + * \param deltaX The difference between the new and old vertex x coordinates. + * \param deltaY The difference between the new and old vertex y coordinates. + * \param deltaZ The difference between the new and old vertex z coordinates. + * \warning This will also alter the Object3D's rotation point if and only if the + * old rotation point was at the Object3D's old center. + */ +void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { + attribMutex.lock(); + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6] += deltaX; //Transpose x + // vertices[(i*6)+1] += deltaY; //Transpose y + // } + // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { + // myRotationPointX += deltaX; + // myRotationPointY += deltaY; + // } + myCenterX += deltaX; + myCenterY += deltaY; + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Sets the Object3D's x position + * \param x The new center x coordinate. + */ +void Object3D::setCenterX(float x) { + attribMutex.lock(); + myCenterX = x; + attribMutex.unlock(); +} + +/** + * \brief Sets the Object3D's y position + * \param y The new center y coordinate. + */ +void Object3D::setCenterY(float y) { + attribMutex.lock(); + myCenterY = y; + attribMutex.unlock(); +} + +/** + * \brief Sets the Object3D's z position + * \param z The new center z coordinate. + */ +void Object3D::setCenterZ(float z) { + attribMutex.lock(); + myCenterZ = z; + attribMutex.unlock(); +} + +/** + * \brief Moves the Object3D to new coordinates. + * \param x The new center x coordinate. + * \param y The new center y coordinate. + * \param z The new center z coordinate. + * \warning This will also alter the Object3D's rotation point if and only if the + * old rotation point was at the Object3D's old center. + */ +void Object3D::setCenter(float x, float y, float z) { + // float deltaX = x - myCenterX; //Change for x + // float deltaY = y - myCenterY; //Change for y + attribMutex.lock(); + // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { + // myRotationPointX = x; + // myRotationPointY = y; + // } + + myCenterX = x; + myCenterY = y; + myCenterZ = z; + + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6] += deltaX; //Transpose x + // vertices[(i*6)+1] += deltaY; //Transpose y + // } + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Object3D's yaw + * \param yaw The new yaw value for Object3D. + */ +void Object3D::setYaw(float yaw) { + attribMutex.lock(); + myCurrentYaw = yaw; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Object3D's pitch + * \param pitch The new pitch value for Object3D. + */ +void Object3D::setPitch(float pitch) { + attribMutex.lock(); + myCurrentPitch = pitch; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Object3D's roll + * \param roll The new roll value for Object3D. + */ +void Object3D::setRoll(float roll) { + attribMutex.lock(); + myCurrentRoll = roll; + attribMutex.unlock(); +} + +/*! + * \brief Mutator for the yaw, pitch, and roll of the Object3D. + * \param yaw The new yaw value for Object3D. + * \param pitch The new pitch value for Object3D. + * \param roll The new roll value for Object3D. + */ +void Object3D::setYawPitchRoll(float yaw, float pitch, float roll) { + attribMutex.lock(); + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's yaw by a specified amount. + * \param deltaYaw The change in yaw value for Object3D. + */ +void Object3D::changeYawBy(float deltaYaw) { + attribMutex.lock(); + myCurrentYaw += deltaYaw; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's pitch by a specified amount. + * \param deltaPitch The change in pitch value for Object3D. + */ +void Object3D::changePitchBy(float deltaPitch) { + attribMutex.lock(); + myCurrentPitch += deltaPitch; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's roll by a specified amount. + * \param deltaRoll The change in roll value for Object3D. + */ +void Object3D::changeRollBy(float deltaRoll) { + attribMutex.lock(); + myCurrentRoll += deltaRoll; + attribMutex.unlock(); +} + +/** + * \brief Alters the Object3D's yaw, pitch, and roll by a specified amount. + * \param deltaYaw The change in yaw value for Object3D. + * \param deltaPitch The change in pitch value for Object3D. + * \param deltaRoll The change in roll value for Object3D. + */ +void Object3D::changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll) { + attribMutex.lock(); + myCurrentYaw += deltaYaw; + myCurrentPitch += deltaPitch; + myCurrentRoll += deltaRoll; + attribMutex.unlock(); +} + +/** + * \brief Sets the point around which Object3D is rotated. + * \param x The x coordinate of the new rotation point. + * \param y The y coordinate of the new rotation point. + * \param z The z coordinate of the new rotation point. + */ +void Object3D::setRotationPoint(float x, float y, float z) { + attribMutex.lock(); + myRotationPointX = x; + myRotationPointY = y; + myRotationPointZ = z; + attribMutex.unlock(); +} + +Object3D::~Object3D() { + delete[] vertices; +} + +} \ No newline at end of file diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h new file mode 100644 index 000000000..b65cba3b3 --- /dev/null +++ b/src/TSGL/Object3D.h @@ -0,0 +1,82 @@ +/* + * Object3D.h provides a base class from which to extend other drawable Object3Ds. + */ + +#ifndef OBJECT3D_H_ +#define OBJECT3D_H_ + +#include // Needed for GL function calls +#include "Color.h" // Needed for color type +#include "Drawable.h" + +namespace tsgl { + +/*! \class Object3D + * \brief A class for drawing 3D objects onto a Canvas or CartesianCanvas. + * \warning Though extending this class must be allowed due to the way the code is set up, attempting to do so + * could potentially mess up the internal GL calls the library uses. Proceed with great caution. + * \details Object3D provides a base class for drawing 3D objects to a Canvas or CartesianCanvas. + * \note Object3D is abstract, and must be extended by the user. + * \details vertices should be an array of floating point values in TSGL's vertex format. + * One face consists of 3 vertices per triangle that it is divided into, #FIXME 7? vertices per face. + * E.g., to draw a cube, you would need 6 faces, 2 triangles per face, 3 vertices per triangle, 36 vertices total. + * \details numberofvertices should be the actual integer number of vertices to be drawn (e.g., *36* for a cube). + * \details geometryType should be one of GL's primitive drawing modes. + * See https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml for further information. + * \details Theoretically, you could potentially extend the Object3D class so that you can create another Object3D class that suits your needs. + * \details However, this is not recommended for normal use of the TSGL library. + */ +class Object3D : public Drawable { + protected: + int numberOfVertices; + float* vertices; + int current = 0; + float myCurrentYaw, myCurrentPitch, myCurrentRoll; + float myCenterZ; // myCenterX and myCenterY inherited + float myRotationPointZ; // myRotationPointX and myRotationPointY inherited + GLenum geometryType; + bool init = false; + public: + Object3D(float yaw, float pitch, float roll, float x, float y, float z); + + virtual ~Object3D(); + + virtual void draw(); + + virtual void addVertex(float x, float y, float z, const ColorFloat &color = BLACK); + + virtual void setColor(ColorFloat c); + virtual void setColor(ColorFloat c[]); + + virtual void changeXBy(float deltaX); + virtual void changeYBy(float deltaY); + virtual void changeZBy(float deltaZ); + virtual void changeCenterBy(float deltaX, float deltaY, float deltaZ); + + virtual void setCenterX(float x); + virtual void setCenterY(float y); + virtual void setCenterZ(float z); + virtual void setCenter(float x, float y, float z); + + virtual void setYaw(float yaw); + virtual void setPitch(float pitch); + virtual void setRoll(float roll); + virtual void setYawPitchRoll(float yaw, float pitch, float roll); + + virtual void changeYawBy(float deltaYaw); + virtual void changePitchBy(float deltaPitch); + virtual void changeRollBy(float deltaRoll); + virtual void changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll); + + virtual void setRotationPoint(float x, float y, float z); + + /*! + * \brief Accessor that returns if Object3D is processed and ready to be drawn + * \details This function returns true only if all vertices have been inserted into an array. + */ + virtual bool isProcessed() { return init; } +}; + +} + +#endif /* OBJECT3D_H_ */ diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp new file mode 100644 index 000000000..3f17a7d47 --- /dev/null +++ b/src/TSGL/Prism.cpp @@ -0,0 +1,137 @@ +#include "Prism.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Prism. + * \details Explicit constructor for a Prism object. + * \param x The x coordinate of the center of the Prism. + * \param y The y coordinate of the center of the Prism. + * \param z The z coordinate of the center of the Prism. + * \param vertices An array of vertices for the Prism's base. + * \param sides The number of sides of the Prism's base. + * \param yaw The Prism's yaw. + * \param pitch The Prism's pitch. + * \param roll The Prism's roll. + * \param c A ColorFloat for the Prism's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. + * \return A new Prism with a buffer for storing the specified numbered of vertices. + */ +Prism::Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (sides < 3) { + TsglDebug("Cannot have a Prism with fewer than 3 sides."); + } + // FIXME make sure all vertex points are within one plane + // FIXME calculate myHeight based on vertices and xyz? + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Prism. + * \details Explicit constructor for a Prism object. + * \param x The x coordinate of the center of the Prism. + * \param y The y coordinate of the center of the Prism. + * \param z The z coordinate of the center of the Prism. + * \param vertices An array of vertices for the Prism's base. + * \param sides The number of sides of the Prism's base. + * \param yaw The Prism's yaw. + * \param pitch The Prism's pitch. + * \param roll The Prism's roll. + * \param c An array of ColorFloats for the Prism's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. + * \return A new Prism with a buffer for storing the specified numbered of vertices. + */ +Prism::Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (sides < 3) { + TsglDebug("Cannot have a Prism with fewer than 3 sides."); + } + // FIXME make sure all vertex points are within one plane + // FIXME calculate myHeight based on vertices and xyz? + attribMutex.unlock(); +} + +/** + * \brief Sets the Prism to a new color. + * \param c The new ColorFloat. + */ +void Prism::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c.R; + vertices[i*6 + 3] = c.G; + vertices[i*6 + 4] = c.B; + vertices[i*6 + 5] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Prism to an array of new colors. + * \param c An array of new ColorFloats. + */ +void Prism::setColor(ColorFloat c[]) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c[i].R; + vertices[i*6 + 3] = c[i].G; + vertices[i*6 + 4] = c[i].B; + vertices[i*6 + 5] = c[i].A; + } + attribMutex.unlock(); +} + +/** + * \brief Gets an array of the Prism's fill vertex colors. + * \return c An array of ColorFloats. + * \warning This method allocates memory. The caller is responsible for deallocating it. + */ +ColorFloat* Prism::getColor() { + ColorFloat * c = new ColorFloat[numberOfVertices]; + for(int i = 0; i < numberOfVertices; i++) { + c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); + } + return c; +} + +// /** +// * \brief Mutates the distance from the center of the Prism's base to the tip. +// * \param height The Prism's new height. +// */ +// void Prism::setHeight(float height) { +// attribMutex.lock(); +// if (height <= 0) { +// TsglDebug("Cannot have a Prism with height less than or equal to 0."); +// attribMutex.unlock(); +// return; +// } +// myHeight = height; +// attribMutex.unlock(); +// } + +// /** +// * \brief Mutates the distance from the center of the Prism's base to the tip by the parameter amount. +// * \param delta The amount by which to change the height of the Prism. +// */ +// void Prism::changeHeightBy(float delta) { +// attribMutex.lock(); +// if (myHeight + delta <= 0) { +// TsglDebug("Cannot have a Prism with height less than or equal to 0."); +// attribMutex.unlock(); +// return; +// } +// myHeight += delta; +// attribMutex.unlock(); +// } + +/*! + * \brief Destructor for the Prism. + */ +Prism::~Prism() { } + +} \ No newline at end of file diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h new file mode 100644 index 000000000..6866a06da --- /dev/null +++ b/src/TSGL/Prism.h @@ -0,0 +1,42 @@ +/* + * Prism.h extends Object3D and provides a class for drawing a prism. + */ + +#ifndef PRISM_H_ +#define PRISM_H_ + +#include "Object3D.h" // For extending our Object3D object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Prism + * \brief Draw an arbitrary Prism with colored vertices. + * \details Prism is a class for holding vertex data for a Prism with a base with at least 3 sides. + */ +class Prism : public Object3D { +protected: + // float myHeight; +public: + Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c); + + Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Prism(); + + virtual void draw(); + + virtual void setColor(ColorFloat c); + + virtual void setColor(ColorFloat c[]); + + // virtual void setHeight(float height); + + // virtual void changeHeightBy(float delta); + + virtual ColorFloat* getColor(); +}; + +} + +#endif /* PRISM_H_ */ \ No newline at end of file diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp new file mode 100644 index 000000000..c893a5a86 --- /dev/null +++ b/src/TSGL/Pyramid.cpp @@ -0,0 +1,173 @@ +#include "Pyramid.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Pyramid. + * \details Explicit constructor for a Pyramid object. + * \param x The x coordinate of the center of the Pyramid. + * \param y The y coordinate of the center of the Pyramid. + * \param z The z coordinate of the center of the Pyramid. + * \param height The distance from the center of the base to tip of the Pyramid. + * \param radius The distance from the center of the Pyramid's base to each vertex of the base. + * \param sides The number of sides of the Pyramid's base. + * \param yaw The Pyramid's yaw. + * \param pitch The Pyramid's pitch. + * \param roll The Pyramid's roll. + * \param c A ColorFloat for the Pyramid's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Pyramid with a buffer for storing the specified numbered of vertices. + */ +Pyramid::Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (sides < 3) { + TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); + } + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Pyramid with radius or height less than or equal to 0."); + } + myHeight = height; + myRadius = radius; + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Pyramid. + * \details Explicit constructor for a Pyramid object. + * \param x The x coordinate of the center of the Pyramid. + * \param y The y coordinate of the center of the Pyramid. + * \param z The z coordinate of the center of the Pyramid. + * \param height The distance from the center of the base to tip of the Pyramid. + * \param radius The distance from the center of the Pyramid's base to each vertex of the base. + * \param sides The number of sides of the Pyramid's base. + * \param yaw The Pyramid's yaw. + * \param pitch The Pyramid's pitch. + * \param roll The Pyramid's roll. + * \param c An array of ColorFloats for the Pyramid's vertex colors. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Pyramid with a buffer for storing the specified numbered of vertices. + */ +Pyramid::Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (sides < 3) { + TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); + } + if (radius <= 0) { + TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + } + myHeight = height; + myRadius = radius; + attribMutex.unlock(); +} + +/** + * \brief Sets the Pyramid to a new color. + * \param c The new ColorFloat. + */ +void Pyramid::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c.R; + vertices[i*6 + 3] = c.G; + vertices[i*6 + 4] = c.B; + vertices[i*6 + 5] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Pyramid to an array of new colors. + * \param c An array of new ColorFloats. + */ +void Pyramid::setColor(ColorFloat c[]) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c[i].R; + vertices[i*6 + 3] = c[i].G; + vertices[i*6 + 4] = c[i].B; + vertices[i*6 + 5] = c[i].A; + } + attribMutex.unlock(); +} + +/** + * \brief Gets an array of the Pyramid's fill vertex colors. + * \return c An array of ColorFloats. + * \warning This method allocates memory. The caller is responsible for deallocating it. + */ +ColorFloat* Pyramid::getColor() { + ColorFloat * c = new ColorFloat[numberOfVertices]; + for(int i = 0; i < numberOfVertices; i++) { + c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); + } + return c; +} + +/** + * \brief Mutates the Pyramid's base's radius. + * \param radius The new radius of the Pyramid's base. + */ +void Pyramid::setRadius(float radius) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius = radius; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Pyramid's base's radius by the parameter amount. + * \param delta The amount by which to change the radius of the Pyramid's base. + */ +void Pyramid::changeRadiusBy(float delta) { + attribMutex.lock(); + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Pyramid's base to the tip. + * \param height The Pyramid's new height. + */ +void Pyramid::setHeight(float height) { + attribMutex.lock(); + if (height <= 0) { + TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the center of the Pyramid's base to the tip by the parameter amount. + * \param delta The amount by which to change the height of the pyramid. + */ +void Pyramid::changeHeightBy(float delta) { + attribMutex.lock(); + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); + attribMutex.unlock(); + return; + } + myHeight += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Pyramid. + */ +Pyramid::~Pyramid() { } + +} \ No newline at end of file diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h new file mode 100644 index 000000000..65d968e70 --- /dev/null +++ b/src/TSGL/Pyramid.h @@ -0,0 +1,47 @@ +/* + * Pyramid.h extends Object3D and provides a class for drawing a pyramid. + */ + +#ifndef PYRAMID_H_ +#define PYRAMID_H_ + +#include "Object3D.h" // For extending our Object3D object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Pyramid + * \brief Draw an arbitrary Pyramid with colored vertices. + * \details Pyramid is a class for holding vertex data for a pyramid with a base with at least 3 sides. + */ +class Pyramid : public Object3D { +protected: + float myHeight; + float myRadius; +public: + Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c); + + Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Pyramid(); + + virtual void draw(); + + virtual void setColor(ColorFloat c); + + virtual void setColor(ColorFloat c[]); + + virtual void setRadius(float radius); + + virtual void changeRadiusBy(float delta); + + virtual void setHeight(float height); + + virtual void changeHeightBy(float delta); + + virtual ColorFloat* getColor(); +}; + +} + +#endif /* PYRAMID_H_ */ \ No newline at end of file diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp new file mode 100644 index 000000000..3c7670d5b --- /dev/null +++ b/src/TSGL/Sphere.cpp @@ -0,0 +1,129 @@ +#include "Sphere.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Sphere. + * \details Explicit constructor for a Sphere object. + * \param x The x coordinate of the center of the Sphere. + * \param y The y coordinate of the center of the Sphere. + * \param z The z coordinate of the center of the Sphere. + * \param radius The Sphere's radius + * \param yaw The Sphere's yaw. + * \param pitch The Sphere's pitch. + * \param roll The Sphere's roll. + * \param c A ColorFloat for the Sphere's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Sphere with a buffer for storing the specified numbered of vertices. + */ +Sphere::Sphere(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); + } + myRadius = radius; + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Sphere. + * \details Explicit constructor for a Sphere object. + * \param x The x coordinate of the center of the Sphere. + * \param y The y coordinate of the center of the Sphere. + * \param z The z coordinate of the center of the Sphere. + * \param radius The distance from the center of the Sphere's base to each vertex of the base. + * \param yaw The Sphere's yaw. + * \param pitch The Sphere's pitch. + * \param roll The Sphere's roll. + * \param c An array of ColorFloats for the Sphere's vertex colors. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \return A new Sphere with a buffer for storing the specified numbered of vertices. + */ +Sphere::Sphere(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); + } + myRadius = radius; + attribMutex.unlock(); +} + +/** + * \brief Sets the Sphere to a new color. + * \param c The new ColorFloat. + */ +void Sphere::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c.R; + vertices[i*6 + 3] = c.G; + vertices[i*6 + 4] = c.B; + vertices[i*6 + 5] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Sphere to an array of new colors. + * \param c An array of new ColorFloats. + */ +void Sphere::setColor(ColorFloat c[]) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*6 + 2] = c[i].R; + vertices[i*6 + 3] = c[i].G; + vertices[i*6 + 4] = c[i].B; + vertices[i*6 + 5] = c[i].A; + } + attribMutex.unlock(); +} + +/** + * \brief Gets an array of the Sphere's fill vertex colors. + * \return c An array of ColorFloats. + * \warning This method allocates memory. The caller is responsible for deallocating it. + */ +ColorFloat* Sphere::getColor() { + ColorFloat * c = new ColorFloat[numberOfVertices]; + for(int i = 0; i < numberOfVertices; i++) { + c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); + } + return c; +} + +/** + * \brief Mutates the Sphere's radius. + * \param radius The new radius of the Sphere. + */ +void Sphere::setRadius(float radius) { + attribMutex.lock(); + if (radius <= 0) { + TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius = radius; + attribMutex.unlock(); +} + +/** + * \brief Mutates the Sphere's radius by the parameter amount. + * \param delta The amount by which to change the radius of the Sphere. + */ +void Sphere::changeRadiusBy(float delta) { + attribMutex.lock(); + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); + attribMutex.unlock(); + return; + } + myRadius += delta; + attribMutex.unlock(); +} + +/*! + * \brief Destructor for the Sphere. + */ +Sphere::~Sphere() { } + +} \ No newline at end of file diff --git a/src/TSGL/Sphere.h b/src/TSGL/Sphere.h new file mode 100644 index 000000000..c863db2de --- /dev/null +++ b/src/TSGL/Sphere.h @@ -0,0 +1,42 @@ +/* + * Sphere.h extends Object3D and provides a class for drawing a sphere. + */ + +#ifndef SPHERE_H_ +#define SPHERE_H_ + +#include "Object3D.h" // For extending our Object3D object +#include "TsglAssert.h" // For unit testing purposes + +namespace tsgl { + +/*! \class Sphere + * \brief Draw an arbitrary Sphere with colored vertices. + * \details Sphere is a class for holding vertex data for a Sphere with non-negative radius. + */ +class Sphere : public Object3D { +protected: + float myRadius; +public: + Sphere(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat c); + + Sphere(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + + virtual ~Sphere(); + + virtual void draw(); + + virtual void setColor(ColorFloat c); + + virtual void setColor(ColorFloat c[]); + + virtual void setRadius(float radius); + + virtual void changeRadiusBy(float delta); + + virtual ColorFloat* getColor(); +}; + +} + +#endif /* SPHERE_H_ */ \ No newline at end of file From fe8820fe15e8625668efc97acbd4772f92700457 Mon Sep 17 00:00:00 2001 From: isa3 Date: Mon, 18 Nov 2019 23:00:18 -0500 Subject: [PATCH 002/105] Improved 3DObject class structure --- src/TSGL/Cube.cpp | 6 ++++-- src/TSGL/Cuboid.cpp | 6 ++++-- src/TSGL/Cylinder.cpp | 6 ++++-- src/TSGL/Ellipsoid.cpp | 4 ++-- src/TSGL/Ellipsoid.h | 2 -- src/TSGL/Object3D.cpp | 1 + src/TSGL/Prism.cpp | 29 +++++++++++++++++++++++++++-- src/TSGL/Prism.h | 7 +++---- src/TSGL/Pyramid.h | 2 -- src/TSGL/Sphere.h | 2 -- 10 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index fafe0beaa..430fd45f1 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -17,10 +17,11 @@ namespace tsgl { * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } + // add vertices based on parameters and color } /*! @@ -38,10 +39,11 @@ Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive side length."); } + // add vertices based on parameters and color } /** diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index e6f2d9dcb..10da60615 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -19,10 +19,11 @@ namespace tsgl { * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, 4, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } + // add vertices based on parameters and color } /*! @@ -42,10 +43,11 @@ Cuboid::Cuboid(float x, float y, float z, float length, float width, float heigh * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } + // add vertices based on parameters and color } /** diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index 2c225f3ad..f9f8bd75c 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -18,10 +18,11 @@ namespace tsgl { * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll) { if (radius <= 0 || height <= 0) { TsglDebug("Cannot have a Cylinder with non-positive height or radius."); } + // add vertices based on parameters and color } /*! @@ -40,10 +41,11 @@ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, 8, 4, yaw, pitch, roll, c) { // FIXME vertices +: Prism(x, y, z, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll) { // FIXME vertices if (radius <= 0 || height <= 0) { TsglDebug("Cannot have a Cylinder with non-positive height or radius."); } + // add vertices based on parameters and color } /** diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 8a918057c..5f4104109 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { attribMutex.lock(); if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); @@ -45,7 +45,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, fl * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { attribMutex.lock(); if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); diff --git a/src/TSGL/Ellipsoid.h b/src/TSGL/Ellipsoid.h index 454140e2c..fe2401913 100644 --- a/src/TSGL/Ellipsoid.h +++ b/src/TSGL/Ellipsoid.h @@ -24,8 +24,6 @@ class Ellipsoid : public Object3D { virtual ~Ellipsoid(); - virtual void draw(); - virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index 0e83050bf..dd204aca0 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -48,6 +48,7 @@ void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { TsglDebug("Cannot add anymore vertices."); return; } + attribMutex.lock(); // vertices[current] = x; // vertices[current + 1] = y; // vertices[current + 2] = color.R; diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index 3f17a7d47..b819a23de 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -19,7 +19,7 @@ namespace tsgl { * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { attribMutex.lock(); if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); @@ -46,7 +46,32 @@ Prism::Prism(float x, float y, float z, float vertices, int sides, float yaw, fl * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { + attribMutex.lock(); + if (sides < 3) { + TsglDebug("Cannot have a Prism with fewer than 3 sides."); + } + // FIXME make sure all vertex points are within one plane + // FIXME calculate myHeight based on vertices and xyz? + attribMutex.unlock(); +} + + /*! + * \brief Explicitly constructs a new Prism. Protected method. + * \details Explicit constructor for a Prism object. Intended to be called only from subclasses. + * \param x The x coordinate of the center of the Prism. + * \param y The y coordinate of the center of the Prism. + * \param z The z coordinate of the center of the Prism. + * \param sides The number of sides of the Prism's base. + * \param yaw The Prism's yaw. + * \param pitch The Prism's pitch. + * \param roll The Prism's roll. + * \warning An invariant is held where if sides is less than 3 then an error message is given. + * \warning An invariant is held where if radius isn't positive then an error message is given. + * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. + * \return A new Prism with a buffer for storing the specified numbered of vertices. + */ +Prism::Prism(float x, float y, float z, int sides, float yaw, float pitch, float roll) : Object3D(x, y, z, yaw, pitch, roll) { attribMutex.lock(); if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h index 6866a06da..8a5821375 100644 --- a/src/TSGL/Prism.h +++ b/src/TSGL/Prism.h @@ -17,15 +17,14 @@ namespace tsgl { class Prism : public Object3D { protected: // float myHeight; + Prism(float x, float y, float z, int sides, float yaw, float pitch, float roll); public: - Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c); + Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c); - Prism(float x, float y, float z, float vertices, int sides, float yaw, float pitch, float roll, ColorFloat c[]); + Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c[]); virtual ~Prism(); - virtual void draw(); - virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h index 65d968e70..46bb21ab6 100644 --- a/src/TSGL/Pyramid.h +++ b/src/TSGL/Pyramid.h @@ -25,8 +25,6 @@ class Pyramid : public Object3D { virtual ~Pyramid(); - virtual void draw(); - virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); diff --git a/src/TSGL/Sphere.h b/src/TSGL/Sphere.h index c863db2de..f966ba73d 100644 --- a/src/TSGL/Sphere.h +++ b/src/TSGL/Sphere.h @@ -24,8 +24,6 @@ class Sphere : public Object3D { virtual ~Sphere(); - virtual void draw(); - virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); From 587f7997e3acc4df39658979e9b3e7de7b6f783e Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 20 Dec 2019 14:08:07 -0500 Subject: [PATCH 003/105] Updated Object3D and Prism this is just a commit so I can change the readme on master --- src/TSGL/Object3D.cpp | 118 ++++++++++++++++++------------------------ src/TSGL/Prism.cpp | 11 +++- 2 files changed, 58 insertions(+), 71 deletions(-) diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index dd204aca0..77ea6ab61 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -29,7 +29,7 @@ Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z * if the above condition is met (vertex buffer = not full). */ void Object3D::draw() { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 7 * sizeof(float), vertices, GL_DYNAMIC_DRAW); glDrawArrays(geometryType, 0, numberOfVertices); } @@ -49,44 +49,19 @@ void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { return; } attribMutex.lock(); -// vertices[current] = x; -// vertices[current + 1] = y; -// vertices[current + 2] = color.R; -// vertices[current + 3] = color.G; -// vertices[current + 4] = color.B; -// vertices[current + 5] = color.A; -// current += 6; -// if (current == numberOfVertices*6) { -// init = true; -// attribMutex.lock(); -// float minX = 0, maxX = 0; -// float minY = 0, maxY = 0; -// minX = maxX = vertices[0]; -// //Find min and max X -// for(int i = 0; i < numberOfVertices; i++) { -// if( vertices[i*6] < minX ) -// minX = vertices[i*6]; -// else if( vertices[i*6] > maxX ) -// maxX = vertices[i*6]; -// } - -// minY = maxY = vertices[1]; -// //Find min and max X -// for(int i = 0; i < numberOfVertices; i++) { -// if( vertices[i*6+1] < minY ) -// minY = vertices[i*6+1]; -// else if( vertices[i*6+1] > maxY ) -// maxY = vertices[i*6+1]; -// } - -// myCenterX = (minX+maxX)/2; -// myCenterY = (minY+maxY)/2; -// myCenterZ = (minZ+maxZ)/2; - -// setRotationPoint(myCenterX, myCenterY, myCenterZ); - - attribMutex.unlock(); -// } + vertices[current] = x; + vertices[current + 1] = y; + vertices[current + 2] = z; + vertices[current + 3] = color.R; + vertices[current + 4] = color.G; + vertices[current + 5] = color.B; + vertices[current + 6] = color.A; + current += 7; + if (current == numberOfVertices*7) { + attribMutex.lock(); + init = true; + attribMutex.unlock(); + } } /** @@ -94,12 +69,12 @@ void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { * \param c The new ColorFloat. */ void Object3D::setColor(ColorFloat c) { - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*6 + 2] = c.R; - // vertices[i*6 + 3] = c.G; - // vertices[i*6 + 4] = c.B; - // vertices[i*6 + 5] = c.A; - // } + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c.R; + vertices[i*7 + 4] = c.G; + vertices[i*7 + 5] = c.B; + vertices[i*7 + 6] = c.A; + } } /** @@ -107,12 +82,12 @@ void Object3D::setColor(ColorFloat c) { * \param c The new array of ColorFloats. */ void Object3D::setColor(ColorFloat c[]) { - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*6 + 2] = c[i].R; - // vertices[i*6 + 3] = c[i].G; - // vertices[i*6 + 4] = c[i].B; - // vertices[i*6 + 5] = c[i].A; - // } + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c[i].R; + vertices[i*7 + 4] = c[i].G; + vertices[i*7 + 5] = c[i].B; + vertices[i*7 + 6] = c[i].A; + } } /** @@ -155,14 +130,16 @@ void Object3D::changeZBy(float deltaZ) { */ void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { attribMutex.lock(); - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*6] += deltaX; //Transpose x - // vertices[(i*6)+1] += deltaY; //Transpose y - // } - // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - // myRotationPointX += deltaX; - // myRotationPointY += deltaY; - // } + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7] += deltaX; //Transpose x + vertices[(i*7)+1] += deltaY; //Transpose y + vertices[(i*7)+2] += deltaZ; //Transpose z + } + if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + myRotationPointX += deltaX; + myRotationPointY += deltaY; + myRotationPointZ += deltaZ; + } myCenterX += deltaX; myCenterY += deltaY; myCenterZ += deltaZ; @@ -208,22 +185,25 @@ void Object3D::setCenterZ(float z) { * old rotation point was at the Object3D's old center. */ void Object3D::setCenter(float x, float y, float z) { - // float deltaX = x - myCenterX; //Change for x - // float deltaY = y - myCenterY; //Change for y + float deltaX = x - myCenterX; //Change for x + float deltaY = y - myCenterY; //Change for y + float deltaZ = z - myCenterZ; attribMutex.lock(); - // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - // myRotationPointX = x; - // myRotationPointY = y; - // } + if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + myRotationPointX = x; + myRotationPointY = y; + myRotationPointZ = z; + } myCenterX = x; myCenterY = y; myCenterZ = z; - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*6] += deltaX; //Transpose x - // vertices[(i*6)+1] += deltaY; //Transpose y - // } + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7] += deltaX; //Transpose x + vertices[(i*7)+1] += deltaY; //Transpose y + vertices[(i*7)+2] += deltaZ; //Transpose y + } attribMutex.unlock(); } diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index b819a23de..eca047d9f 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -24,6 +24,9 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } + numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; + vertices = new float[numberOfVertices * 7]; + geometryType = GL_TRIANGLES; // FIXME make sure all vertex points are within one plane // FIXME calculate myHeight based on vertices and xyz? attribMutex.unlock(); @@ -51,6 +54,9 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } + numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; + vertices = new float[numberOfVertices * 7]; + geometryType = GL_TRIANGLES; // FIXME make sure all vertex points are within one plane // FIXME calculate myHeight based on vertices and xyz? attribMutex.unlock(); @@ -76,8 +82,9 @@ Prism::Prism(float x, float y, float z, int sides, float yaw, float pitch, float if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } - // FIXME make sure all vertex points are within one plane - // FIXME calculate myHeight based on vertices and xyz? + numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; + vertices = new float[numberOfVertices * 7]; + geometryType = GL_TRIANGLES; attribMutex.unlock(); } From 5bb298ea1fc113acbe222fe5d8aed02d317151dd Mon Sep 17 00:00:00 2001 From: isa3 Date: Mon, 30 Dec 2019 23:30:07 -0500 Subject: [PATCH 004/105] Fixing tests that broke with Mac-Linux merge --- src/TSGL/Canvas.cpp | 12 +++++++++++ src/TSGL/Canvas.h | 2 ++ src/tests/DiningPhilosophers/Table.cpp | 3 +-- src/tests/DiningPhilosophers/Table.h | 1 - src/tests/Langton/AntFarm.cpp | 3 ++- src/tests/testFireworks.cpp | 29 +++++++++++++------------- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index b7bd617e8..683e938a2 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2350,6 +2350,18 @@ void Canvas::run(void (*myFunction)(Canvas&, int, int), int i1, int i2) { start(); myFunction(*this, i1, i2); wait(); } + /*! + * \brief Overload for run() + * \param myFunction The function to run on the Canvas. Must take exactly one parameter of type Canvas&, + * which is a reference to the Canvas to render to. + * \param i1 An integer argument to myFunction + * \param i2 An integer argument to myFunction + * \param i3 An integer argument to myFunction + */ +void Canvas::run(void (*myFunction)(Canvas&, int, int, int), int i1, int i2, int i3) { + start(); myFunction(*this, i1, i2, i3); wait(); +} + /*! * \brief Overload for run() * \param myFunction The function to run on the Canvas. Must take exactly one parameter of type Canvas&, diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 3ca778b2f..f66945420 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -395,6 +395,8 @@ class Canvas { virtual void run(void (*myFunction)(Canvas&, unsigned), unsigned u); virtual void run(void (*myFunction)(Canvas&, int, int), int i1, int i2); + + virtual void run(void (*myFunction)(Canvas&, int, int, int), int i1, int i2, int i3); virtual void run(void (*myFunction)(Canvas&, unsigned, unsigned), unsigned u1, unsigned u2); diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 49a562815..1cbc4e257 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -68,7 +68,6 @@ Table::~Table() { else myCan2->wait(); delete myCan2; - delete spaghetti; delete [] phils; delete [] forks; } @@ -421,7 +420,7 @@ void Table::checkStep() { * \brief Method for philosopher to act based on myAction. */ void Table::actStep() { - myCan2->sleep(); + // myCan2->sleep(); int i = omp_get_thread_num(); int left = i, right = (i+numPhils-1)%numPhils; switch(phils[i].action()) { diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h index c5c1c4401..417492154 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/tests/DiningPhilosophers/Table.h @@ -26,7 +26,6 @@ class Table { PhilMethod myMethod; std::string methodString; Canvas *myCan, *myCan2; - Image * spaghetti; Philosopher *phils; Fork *forks; TextureHandler loader; diff --git a/src/tests/Langton/AntFarm.cpp b/src/tests/Langton/AntFarm.cpp index a2bfd5910..4d687c184 100644 --- a/src/tests/Langton/AntFarm.cpp +++ b/src/tests/Langton/AntFarm.cpp @@ -25,9 +25,10 @@ AntFarm::~AntFarm() { } void AntFarm::addAnt(int x, int y, int r, int g, int b, int d) { - if (size < cap) + if (size < cap) { ants[size] = new LangtonAnt(x, y, r, g, b, d, this); size++; + } } inline void AntFarm::moveAnt(int j) { diff --git a/src/tests/testFireworks.cpp b/src/tests/testFireworks.cpp index f62ba3ad0..7de3a96f1 100644 --- a/src/tests/testFireworks.cpp +++ b/src/tests/testFireworks.cpp @@ -25,19 +25,19 @@ void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { ColorFloat col = can.getBackgroundColor(); col.A = 0.04f; const int CWW = can.getWindowWidth(), CWH = can.getWindowHeight(); - while(can.isOpen()) { - #pragma omp parallel num_threads(threads) - { - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - for (int n = 0; n < speed; ++n) { - for (int i = tid; i < numFireworks; i += nthreads) - arcs[i]->step(); - if (tid == 0) - can.drawRectangle(0,0,CWW,CWH,col); - #pragma omp barrier - } - can.sleep(); + #pragma omp parallel num_threads(threads) + { + while(can.isOpen()) { + can.sleep(); + int tid = omp_get_thread_num(); + int nthreads = omp_get_num_threads(); + for (int n = 0; n < speed; ++n) { + for (int i = tid; i < numFireworks; i += nthreads) + arcs[i]->step(); + if (tid == 0) + can.drawRectangle(0,0,CWW,CWH,col); + #pragma omp barrier + } } } for (int i = 0; i < numFireworks; i++) { @@ -56,6 +56,5 @@ int main(int argc, char* argv[]) { int s = (argc > 5) ? atoi(argv[5]) : 10; Canvas c(-1, -1, w, h, "Fireworks!"); c.setBackgroundColor(BLACK); - c.start(); - fireworkFunction(c,t,f,s); + c.run(fireworkFunction,t,f,s); } From 520734996d13eab31cb8a6c3072bc15c565ac954 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 31 Dec 2019 01:33:33 -0500 Subject: [PATCH 005/105] Minor fixes on MacOS --- src/tests/DiningPhilosophers/Table.cpp | 2 -- src/tests/testPhilosophers.cpp | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 1cbc4e257..6ce0bee2f 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -65,8 +65,6 @@ Table::Table(Canvas& can, int p, PhilMethod m) { Table::~Table() { if (myCan2->isOpen()) myCan2->stop(); - else - myCan2->wait(); delete myCan2; delete [] phils; delete [] forks; diff --git a/src/tests/testPhilosophers.cpp b/src/tests/testPhilosophers.cpp index cbdbd41e1..d00f4bda6 100644 --- a/src/tests/testPhilosophers.cpp +++ b/src/tests/testPhilosophers.cpp @@ -74,9 +74,10 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step } }); + #pragma omp parallel num_threads(philosophers) + { while(can.isOpen()) { - #pragma omp parallel num_threads(philosophers) - { + can.sleep(); if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { if(stepThrough) { philPauses[omp_get_thread_num()] = true; } t.checkStep(); @@ -88,7 +89,6 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step t.drawStep(); can.resumeDrawing(); } - can.sleep(); } } } From 69be7697ad28f8ffef962934cdd34c8aaddff91d Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 20 Mar 2020 02:09:23 -0400 Subject: [PATCH 006/105] Cube improvements - data in place. --- Makefile | 7 +- src/TSGL/Canvas.h | 4 +- src/TSGL/Color.cpp | 165 +++++++++++++++++++++++++++++++++++++++++ src/TSGL/Color.h | 43 ++++++++++- src/TSGL/Cube.cpp | 80 ++++++++++++++++++-- src/TSGL/Cube.h | 8 +- src/TSGL/Object3D.cpp | 152 +++++++++++++++++++++---------------- src/TSGL/Object3D.h | 13 ++-- src/TSGL/Prism.cpp | 53 ++++--------- src/TSGL/Prism.h | 4 - src/TSGL/gl_includes.h | 11 +++ src/tests/testCube.cpp | 28 +++++++ 12 files changed, 435 insertions(+), 133 deletions(-) create mode 100644 src/TSGL/gl_includes.h create mode 100644 src/tests/testCube.cpp diff --git a/Makefile b/Makefile index 9769728aa..f514192cb 100644 --- a/Makefile +++ b/Makefile @@ -45,11 +45,11 @@ CXXFLAGS=-O3 -g3 -ggdb3 \ -I/opt/AMDAPP/include/ \ -I/usr/include/c++/4.6/ \ -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ - -I/usr/lib/gcc/x86_64-linux-gnu/4.6/include/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ -I/usr/include/freetype2 \ -I/usr/include/freetype2/freetype \ -I./ \ - -std=c++0x -fopenmp \ + -std=c++0x -Xpreprocessor -fopenmp \ ${NOWARN} -fpermissive # -pedantic-errors @@ -58,7 +58,7 @@ LFLAGS=-Llib/ \ ${OS_EXTRA_LIB} \ -L/usr/X11/lib/ \ ${OS_LDIRS} \ - -ltsgl -lfreetype -lGLEW -l${OS_GLFW} \ + -ltsgl -lfreetype -lGLEW -lglfw -l${OS_GLFW} \ -lX11 ${OS_GL} -lXrandr -Xpreprocessor -fopenmp -lomp -I"$(brew --prefix libomp)/include" \ ${OS_LFLAGS} @@ -78,6 +78,7 @@ BINARIES= \ bin/testConstructors \ bin/testConway \ bin/testCosineIntegral \ + bin/testCube \ bin/testDumbSort \ bin/testFireworks \ bin/testForestFire \ diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index f66945420..512cfd1ca 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -13,6 +13,7 @@ #include "Array.h" // Our own array for buffering drawing operations #include "Arrow.h" // Our own array for drawing arrows #include "Color.h" // Our own interface for converting color types +#include "Cube.h" #include "TriangleStrip.h" // Our own class for drawing polygons with colored vertices #include "Ellipse.h" // Our own class for drawing ellipses #include "Circle.h" // Our own class for drawing circles @@ -44,8 +45,7 @@ #include // For spawning rendering in a different thread #endif -#include // Needed for GL function calls -#include // For window creation and management +#include "gl_includes.h" #ifdef _WIN32 #define round(x) ((x-floor(x))>0.5 ? ceil(x) : floor(x)) // round is not defined in Visual Studio diff --git a/src/TSGL/Color.cpp b/src/TSGL/Color.cpp index 6eafd1f7f..60b97a819 100644 --- a/src/TSGL/Color.cpp +++ b/src/TSGL/Color.cpp @@ -475,6 +475,171 @@ ColorHSV::operator ColorInt() { return (ColorInt)((ColorFloat)(*this)); } + +/*! + * \brief Default ColorFloat constructor method. + * \details This is the default constructor for the ColorFloat struct. + * \note R, G, B, and A are all set to 1.0f by default. + * \return A ColorFloat struct with default R, G, B, and A values. + */ +ColorGLfloat::ColorGLfloat() { + R = G = B = A = 1; +} + +/*! + * \brief Basic explicit ColorFloat constructor method. + * \details This is the basic explicit constructor for the ColorFloat struct. + * \param v The value component of the color. + * \param a The alpha component of the struct (set to 1.0f by default). + * \warning An invariant is set where if any of the specified R, G, B, or A values + * is out of the range 0 - 1 inclusive then an error message is given. + * \return A ColorFloat struct with equal R, G, and B values set to v, + * and the specified A value. + */ +ColorGLfloat::ColorGLfloat(GLfloat v, GLfloat a) { + if (clamp(v,0,1)) + TsglDebug("Out of range parameter specified for ColorFloat"); + R = v; G = v; B = v; A = a; +} + +/*! + * \brief Full explicit ColorFloat constructor method. + * \details This is the full explicit constructor for the ColorFloat struct. + * \param r The red component of the struct. + * \param g The green component of the struct. + * \param b The blue component of the struct. + * \param a The alpha component of the struct (set to 1.0f by default). + * \warning An invariant is set where if any of the specified R, G, B, or A values + * is out of the range 0 - 1 inclusive then an error message is given. + * \return A ColorFloat struct with the specified R, G, B, and A values. + */ +ColorGLfloat::ColorGLfloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { + bool oor = false; + oor |= clamp(r,0,1); + oor |= clamp(g,0,1); + oor |= clamp(b,0,1); + oor |= clamp(a,0,1); + if (oor) + TsglDebug("Out of range parameter specified for ColorFloat"); + R = r; G = g; B = b; A = a; +} + +/*! + * \brief Returns a string representation of the ColorFloat. + * \details This function returns a std::string representation of the ColorFloat. + * \return A string representation of the ColorFloat. + */ +std::string ColorGLfloat::asString() { + std::stringstream ss; + ss << R << "R," << G << "G," << B << "B," << A << "A"; + return ss.str(); +} + +//From http://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both +/*! + * \brief Implicit conversion from ColorFloat to ColorHSV. + * \details This defines the implicit conversion operator from a floating point color type (ColorFloat) to an + * HSV color type (ColorHSV). + */ +ColorGLfloat::operator ColorHSV() { + ColorHSV out; + double min, max, delta; + + min = R < G ? R : G; + min = min < B ? min : B; + + max = R > G ? R : G; + max = max > B ? max : B; + + out.V = max; // v + delta = max - min; + if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash + out.S = (delta / max); // s + } else { + // if max is 0, then r = g = b = 0 + // s = 0, v is undefined + out.S = 0.0; + out.H = NAN; // its now undefined + return out; + } + if( R >= max ) // > is bogus, just keeps compilor happy + out.H = ( G - B ) / delta; // between yellow & magenta + else + if( G >= max ) + out.H = 2.0 + ( B - R ) / delta; // between cyan & yellow + else + out.H = 4.0 + ( R - G ) / delta; // between magenta & cyan + + if( out.H < 0.0 ) + out.H += 6.0; + + return out; +} + +/*! + * \brief Implicit conversion from ColorFloat to ColorInt. + * \details This defines the implicit conversion operator from a floating point color type (ColorFloat) to an + * integer color type (ColorInt). + */ +ColorGLfloat::operator ColorInt() { + return ColorInt(R*MAX_COLOR,G*MAX_COLOR,B*MAX_COLOR,A*MAX_COLOR); +} + +/*! + * \brief Determines if two ColorFloats are equivalent. + * \details Equality operator for two ColorFloats. Determines if they are equivalent. + * \param c2 Reference to the ColorFloat struct that is the second one in the equivalence comparison. + * \note This function relies on (*this), which is a dereferenced pointer to the first ColorFloat struct in the comparison. + * (its the one on the left side of the == sign). + * \returns true if the two ColorFloats are equivalent, false if otherwise. + */ +bool ColorGLfloat::operator==(ColorGLfloat& c2) { + if((*this).R == c2.R && (*this).G == c2.G && (*this).B == c2.B) { + return true; + } else { + return false; + } +} + +/*! + * \brief Determines if two ColorFloats are *NOT* equivalent. + * \details Inequality operator for two ColorFloats. Determines if they are *NOT* equivalent. + * \param c2 Reference to the ColorFloat struct that is the second one in the inequality comparison. + * \note This function relies on (*this), which is a dereferenced pointer to the first ColorFloat struct in the inequality comparison. + * (its the one on the left side of the != sign). + * \returns true if the two ColorFloats are not equivalent, false if otherwise. + */ +bool ColorGLfloat::operator!=(ColorGLfloat& c2) { + if((*this).R == c2.R && (*this).G == c2.G && (*this).B == c2.B) { + return false; + } else { + return true; + } +} + +/*! + * \brief Multiplies the values of a ColorFloat by a float + * \details This operator multiplies each of the components of a ColorFloat + * by amount f. + * \param f Amount to multiply each component by + * \returns A new ColorFloat constructed as ColorFloat(orig.R*f, orig.G*f, orig.b*f, orig.A*f) + * \note Individual channels are clamped between 0 and 1. + */ +ColorGLfloat ColorGLfloat::operator*(float f) { + GLfloat newR = (*this).R*f; clamp(newR,0,1); + GLfloat newG = (*this).G*f; clamp(newG,0,1); + GLfloat newB = (*this).B*f; clamp(newB,0,1); + GLfloat newA = (*this).A; + return ColorGLfloat(newR,newG,newB,newA); +} + +ColorGLfloat ColorGLfloat::getContrast() { + GLfloat color = (R + G + B > 1.5) ? 0.0 : 1.0; + return ColorGLfloat(color, color, color, A); +} + + + /*! * \brief Returns an HSVA color with a hue dependent on the number of sections. * \details This function returns a ColorFloat whose hue is calculated from the provided section number and diff --git a/src/TSGL/Color.h b/src/TSGL/Color.h index 8dcf62ab0..8241dcbc9 100755 --- a/src/TSGL/Color.h +++ b/src/TSGL/Color.h @@ -9,6 +9,7 @@ #include // Needed for exceptions #include // Needed for rand() #include // Needed for Windows integer / float to string conversion +#include #include "Util.h" // Clamp() #include "Error.h" // TsglErr() / TsglDebug() @@ -18,6 +19,7 @@ namespace tsgl { struct ColorFloat; //Forward declarations struct ColorInt; struct ColorHSV; +struct ColorGLfloat; /*! * \brief Floating point RGBA color struct. @@ -29,13 +31,13 @@ struct ColorHSV; */ struct ColorFloat { public: - float R, G, B, A; + GLfloat R, G, B, A; ColorFloat(); - ColorFloat(float v, float a = 1.0f); + ColorFloat(GLfloat v, GLfloat a = 1.0f); - ColorFloat(float r, float g, float b, float a = 1.0f); + ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0f); std::string asString(); @@ -43,7 +45,7 @@ struct ColorFloat { operator ColorInt(); - ColorFloat operator*(float f); + ColorFloat operator*(GLfloat f); bool operator==(ColorFloat& c2); @@ -106,6 +108,39 @@ struct ColorHSV { std::string asString(); }; +/*! + * \brief Floating point RGBA color struct. + * \details ColorFloat defines a color with floating point red, green, blue, and alpha components. + * \param R Red component, between 0 and 1 inclusive. + * \param G Green component, between 0 and 1 inclusive. + * \param B Blue component, between 0 and 1 inclusive. + * \param A Alpha component, between 0 and 1 inclusive. + */ +struct ColorGLfloat { + public: + float R, G, B, A; + + ColorGLfloat(); + + ColorGLfloat(float v, float a = 1.0f); + + ColorGLfloat(float r, float g, float b, float a = 1.0f); + + std::string asString(); + + operator ColorHSV(); + + operator ColorInt(); + + ColorGLfloat operator*(float f); + + bool operator==(ColorGLfloat& c2); + + bool operator!=(ColorGLfloat& c2); + + ColorGLfloat getContrast(); +}; + /*! * \brief The various ColorFloat constants used throughout TSGL. */ diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 430fd45f1..8f97e9a00 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -12,16 +12,45 @@ namespace tsgl { * \param yaw The Cube's yaw. * \param pitch The Cube's pitch. * \param roll The Cube's roll. - * \param c A ColorFloat for the Cube's vertex colors. + * \param c A ColorGLfloat for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. */ -Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c) +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c) : Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } - // add vertices based on parameters and color + mySideLength = sideLength; + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); + + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); + + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); + + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); + + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); + + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); } /*! @@ -34,23 +63,52 @@ Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, * \param yaw The Cube's yaw. * \param pitch The Cube's pitch. * \param roll The Cube's roll. - * \param c An array of ColorFloats for the Cube's vertex colors. + * \param c An array of ColorGLfloats for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. */ -Cube::Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c[]) +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]) : Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive side length."); } - // add vertices based on parameters and color + mySideLength = sideLength; + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + + addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); + + addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); + addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); } /** * \brief Mutates the distance from the Cube's front face to its back face. * \param height The Cube's new length. */ -void Cube::setSideLength(float length) { +void Cube::setSideLength(GLfloat length) { attribMutex.lock(); if (length <= 0) { TsglDebug("Cannot have a Cube with side length less than or equal to 0."); @@ -59,13 +117,14 @@ void Cube::setSideLength(float length) { } mySideLength = length; attribMutex.unlock(); + // FIXME alter vertices } /** * \brief Mutates the distance from the Cube's front face to its back face by the parameter amount. * \param delta The amount by which to change the length of the Cube. */ -void Cube::changeSideLengthBy(float delta) { +void Cube::changeSideLengthBy(GLfloat delta) { attribMutex.lock(); if (mySideLength + delta <= 0) { TsglDebug("Cannot have a Cube with length less than or equal to 0."); @@ -74,6 +133,11 @@ void Cube::changeSideLengthBy(float delta) { } mySideLength += delta; attribMutex.unlock(); + // FIXME alter vertices +} + +void Cube::setRotation(float radians) { + } /*! diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 1fa5ef906..8d80c5cf0 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -17,16 +17,18 @@ namespace tsgl { */ class Cube : public Prism { protected: - float mySideLength; + GLfloat mySideLength; public: - Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c); + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c); - Cube(float x, float y, float z, float sideLength, float yaw, float pitch, float roll, ColorFloat c[]); + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]); virtual void setSideLength(float length); virtual void changeSideLengthBy(float delta); + virtual void setRotation(float radians); + virtual ~Cube(); }; diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index 77ea6ab61..c38949fd1 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -29,8 +29,28 @@ Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z * if the above condition is met (vertex buffer = not full). */ void Object3D::draw() { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 7 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); + // glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 7 * sizeof(float), vertices, GL_DYNAMIC_DRAW); + // glDrawArrays(geometryType, 0, numberOfVertices); + + glPushMatrix(); + glRotatef(myCurrentYaw, 1, 0, 0); + glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentRoll, 0, 0, 1); + + /* We have a color array and a vertex array */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_FLOAT, 0, colors); + + /* Send data : 24 vertices */ + glDrawArrays(geometryType, 0, 24); + + glPopMatrix(); + + /* Cleanup states */ + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); } /*! @@ -43,21 +63,23 @@ void Object3D::draw() { * \note This function does nothing if the vertex buffer is already full. * \note A message is given indicating that the vertex buffer is full. */ -void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { +void Object3D::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &color) { if (init) { TsglDebug("Cannot add anymore vertices."); return; } attribMutex.lock(); - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = z; - vertices[current + 3] = color.R; - vertices[current + 4] = color.G; - vertices[current + 5] = color.B; - vertices[current + 6] = color.A; - current += 7; - if (current == numberOfVertices*7) { + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + currentVertex += 3; + colors[currentColor] = color.R; + colors[currentColor+1] = color.G; + colors[currentColor+2] = color.B; + colors[currentColor+3] = color.A; + currentColor += 4; + attribMutex.unlock(); + if (currentVertex == numberOfVertices*3) { attribMutex.lock(); init = true; attribMutex.unlock(); @@ -66,28 +88,32 @@ void Object3D::addVertex(float x, float y, float z, const ColorFloat &color) { /** * \brief Sets the Object3D to a new color. - * \param c The new ColorFloat. + * \param c The new ColorGLfloat. */ -void Object3D::setColor(ColorFloat c) { +void Object3D::setColor(ColorGLfloat c) { + attribMutex.lock(); for(int i = 0; i < numberOfVertices; i++) { - vertices[i*7 + 3] = c.R; - vertices[i*7 + 4] = c.G; - vertices[i*7 + 5] = c.B; - vertices[i*7 + 6] = c.A; + colors[i*4] = c.R; + colors[i*4 + 1] = c.G; + colors[i*4 + 2] = c.B; + colors[i*4 + 3] = c.A; } + attribMutex.unlock(); } /** * \brief Sets the Object3D to a new array of colors. - * \param c The new array of ColorFloats. + * \param c The new array of ColorGLfloats. */ -void Object3D::setColor(ColorFloat c[]) { +void Object3D::setColor(ColorGLfloat c[]) { + attribMutex.lock(); for(int i = 0; i < numberOfVertices; i++) { - vertices[i*7 + 3] = c[i].R; - vertices[i*7 + 4] = c[i].G; - vertices[i*7 + 5] = c[i].B; - vertices[i*7 + 6] = c[i].A; + colors[i*4] = c[i].R; + colors[i*6 + 1] = c[i].G; + colors[i*6 + 2] = c[i].B; + colors[i*6 + 3] = c[i].A; } + attribMutex.unlock(); } /** @@ -129,21 +155,21 @@ void Object3D::changeZBy(float deltaZ) { * old rotation point was at the Object3D's old center. */ void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*7] += deltaX; //Transpose x - vertices[(i*7)+1] += deltaY; //Transpose y - vertices[(i*7)+2] += deltaZ; //Transpose z - } - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - myRotationPointZ += deltaZ; - } - myCenterX += deltaX; - myCenterY += deltaY; - myCenterZ += deltaZ; - attribMutex.unlock(); + // attribMutex.lock(); + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*7] += deltaX; //Transpose x + // vertices[(i*7)+1] += deltaY; //Transpose y + // vertices[(i*7)+2] += deltaZ; //Transpose z + // } + // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + // myRotationPointX += deltaX; + // myRotationPointY += deltaY; + // myRotationPointZ += deltaZ; + // } + // myCenterX += deltaX; + // myCenterY += deltaY; + // myCenterZ += deltaZ; + // attribMutex.unlock(); } /** @@ -151,9 +177,9 @@ void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { * \param x The new center x coordinate. */ void Object3D::setCenterX(float x) { - attribMutex.lock(); - myCenterX = x; - attribMutex.unlock(); + // attribMutex.lock(); + // myCenterX = x; + // attribMutex.unlock(); } /** @@ -161,9 +187,9 @@ void Object3D::setCenterX(float x) { * \param y The new center y coordinate. */ void Object3D::setCenterY(float y) { - attribMutex.lock(); - myCenterY = y; - attribMutex.unlock(); + // attribMutex.lock(); + // myCenterY = y; + // attribMutex.unlock(); } /** @@ -171,9 +197,9 @@ void Object3D::setCenterY(float y) { * \param z The new center z coordinate. */ void Object3D::setCenterZ(float z) { - attribMutex.lock(); - myCenterZ = z; - attribMutex.unlock(); + // attribMutex.lock(); + // myCenterZ = z; + // attribMutex.unlock(); } /** @@ -188,23 +214,23 @@ void Object3D::setCenter(float x, float y, float z) { float deltaX = x - myCenterX; //Change for x float deltaY = y - myCenterY; //Change for y float deltaZ = z - myCenterZ; - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { - myRotationPointX = x; - myRotationPointY = y; - myRotationPointZ = z; - } + // attribMutex.lock(); + // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + // myRotationPointX = x; + // myRotationPointY = y; + // myRotationPointZ = z; + // } - myCenterX = x; - myCenterY = y; - myCenterZ = z; + // myCenterX = x; + // myCenterY = y; + // myCenterZ = z; - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*7] += deltaX; //Transpose x - vertices[(i*7)+1] += deltaY; //Transpose y - vertices[(i*7)+2] += deltaZ; //Transpose y - } - attribMutex.unlock(); + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*7] += deltaX; //Transpose x + // vertices[(i*7)+1] += deltaY; //Transpose y + // vertices[(i*7)+2] += deltaZ; //Transpose y + // } + // attribMutex.unlock(); } /** diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h index b65cba3b3..cc88a62ba 100644 --- a/src/TSGL/Object3D.h +++ b/src/TSGL/Object3D.h @@ -5,7 +5,6 @@ #ifndef OBJECT3D_H_ #define OBJECT3D_H_ -#include // Needed for GL function calls #include "Color.h" // Needed for color type #include "Drawable.h" @@ -29,8 +28,10 @@ namespace tsgl { class Object3D : public Drawable { protected: int numberOfVertices; - float* vertices; - int current = 0; + GLfloat* vertices; + GLfloat* colors; + int currentVertex = 0; + int currentColor = 0; float myCurrentYaw, myCurrentPitch, myCurrentRoll; float myCenterZ; // myCenterX and myCenterY inherited float myRotationPointZ; // myRotationPointX and myRotationPointY inherited @@ -43,10 +44,10 @@ class Object3D : public Drawable { virtual void draw(); - virtual void addVertex(float x, float y, float z, const ColorFloat &color = BLACK); + virtual void addVertex(float x, float y, float z, const ColorGLfloat &color = ColorGLfloat(1,1,1,1)); - virtual void setColor(ColorFloat c); - virtual void setColor(ColorFloat c[]); + virtual void setColor(ColorGLfloat c); + virtual void setColor(ColorGLfloat c[]); virtual void changeXBy(float deltaX); virtual void changeYBy(float deltaY); diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index eca047d9f..b67e96b2d 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -24,9 +24,10 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } - numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; - vertices = new float[numberOfVertices * 7]; - geometryType = GL_TRIANGLES; + numberOfVertices = sides * 6; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + geometryType = GL_QUADS; // FIXME make sure all vertex points are within one plane // FIXME calculate myHeight based on vertices and xyz? attribMutex.unlock(); @@ -54,9 +55,10 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } - numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; - vertices = new float[numberOfVertices * 7]; - geometryType = GL_TRIANGLES; + numberOfVertices = sides * 6; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + geometryType = GL_QUADS; // FIXME make sure all vertex points are within one plane // FIXME calculate myHeight based on vertices and xyz? attribMutex.unlock(); @@ -82,39 +84,10 @@ Prism::Prism(float x, float y, float z, int sides, float yaw, float pitch, float if (sides < 3) { TsglDebug("Cannot have a Prism with fewer than 3 sides."); } - numberOfVertices = sides * 3 * 2 + (sides - 2) * 2; - vertices = new float[numberOfVertices * 7]; - geometryType = GL_TRIANGLES; - attribMutex.unlock(); -} - -/** - * \brief Sets the Prism to a new color. - * \param c The new ColorFloat. - */ -void Prism::setColor(ColorFloat c) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; - } - attribMutex.unlock(); -} - -/** - * \brief Sets the Prism to an array of new colors. - * \param c An array of new ColorFloats. - */ -void Prism::setColor(ColorFloat c[]) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; - } + numberOfVertices = sides * 6; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + geometryType = GL_QUADS; attribMutex.unlock(); } @@ -126,7 +99,7 @@ void Prism::setColor(ColorFloat c[]) { ColorFloat* Prism::getColor() { ColorFloat * c = new ColorFloat[numberOfVertices]; for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); + c[i] = ColorFloat(colors[i*4], colors[i*4 + 1], colors[i*4 + 2], colors[i*4 + 3]); } return c; } diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h index 8a5821375..83147d342 100644 --- a/src/TSGL/Prism.h +++ b/src/TSGL/Prism.h @@ -25,10 +25,6 @@ class Prism : public Object3D { virtual ~Prism(); - virtual void setColor(ColorFloat c); - - virtual void setColor(ColorFloat c[]); - // virtual void setHeight(float height); // virtual void changeHeightBy(float delta); diff --git a/src/TSGL/gl_includes.h b/src/TSGL/gl_includes.h new file mode 100644 index 000000000..9c11ab497 --- /dev/null +++ b/src/TSGL/gl_includes.h @@ -0,0 +1,11 @@ +/* + * gl_includes.h + */ + +#ifndef GL_INCLUDES_H_ +#define GL_INCLUDES_H_ + +#include // Needed for GL function calls +#include // For window creation and management + +#endif /* GL_INCLUDES_H_ */ \ No newline at end of file diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp new file mode 100644 index 000000000..155bfa5eb --- /dev/null +++ b/src/tests/testCube.cpp @@ -0,0 +1,28 @@ +/* + * testCube.cpp + * + * Usage: ./testCube + */ + +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + Cube * testCube = new Cube(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, ColorGLfloat(0,0,0,1)); + printf("Cube completed.\n"); + // can.add(testCube); + // while (can.isOpen()) { + // can.sleep(); + // } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Fancy Rectangles"); + c.setBackgroundColor(BLACK); + c.run(cubeFunction); +} \ No newline at end of file From ff7a7e5dc00d0cf5e1b8a07e5f447ae61a7aa8bf Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 20 Mar 2020 02:19:22 -0400 Subject: [PATCH 007/105] Minor fixes --- src/TSGL/Color.cpp | 2 +- src/TSGL/Color.h | 12 ++++++------ src/tests/testCube.cpp | 13 ++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/TSGL/Color.cpp b/src/TSGL/Color.cpp index 60b97a819..edd21d3aa 100644 --- a/src/TSGL/Color.cpp +++ b/src/TSGL/Color.cpp @@ -625,7 +625,7 @@ bool ColorGLfloat::operator!=(ColorGLfloat& c2) { * \returns A new ColorFloat constructed as ColorFloat(orig.R*f, orig.G*f, orig.b*f, orig.A*f) * \note Individual channels are clamped between 0 and 1. */ -ColorGLfloat ColorGLfloat::operator*(float f) { +ColorGLfloat ColorGLfloat::operator*(GLfloat f) { GLfloat newR = (*this).R*f; clamp(newR,0,1); GLfloat newG = (*this).G*f; clamp(newG,0,1); GLfloat newB = (*this).B*f; clamp(newB,0,1); diff --git a/src/TSGL/Color.h b/src/TSGL/Color.h index 8241dcbc9..30e4ff422 100755 --- a/src/TSGL/Color.h +++ b/src/TSGL/Color.h @@ -35,9 +35,9 @@ struct ColorFloat { ColorFloat(); - ColorFloat(GLfloat v, GLfloat a = 1.0f); + ColorFloat(float v, float a = 1.0f); - ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0f); + ColorFloat(float r, float g, float b, float a = 1.0f); std::string asString(); @@ -45,7 +45,7 @@ struct ColorFloat { operator ColorInt(); - ColorFloat operator*(GLfloat f); + ColorFloat operator*(float f); bool operator==(ColorFloat& c2); @@ -122,9 +122,9 @@ struct ColorGLfloat { ColorGLfloat(); - ColorGLfloat(float v, float a = 1.0f); + ColorGLfloat(GLfloat v, GLfloat a = 1.0f); - ColorGLfloat(float r, float g, float b, float a = 1.0f); + ColorGLfloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1); std::string asString(); @@ -132,7 +132,7 @@ struct ColorGLfloat { operator ColorInt(); - ColorGLfloat operator*(float f); + ColorGLfloat operator*(GLfloat f); bool operator==(ColorGLfloat& c2); diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 155bfa5eb..3efab81c9 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -9,12 +9,11 @@ using namespace tsgl; void cubeFunction(Canvas& can) { - Cube * testCube = new Cube(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, ColorGLfloat(0,0,0,1)); - printf("Cube completed.\n"); - // can.add(testCube); - // while (can.isOpen()) { - // can.sleep(); - // } + Cube * testCube = new Cube(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, ColorGLfloat(0.196,0.321,0.482,1)); + can.add(testCube); + while (can.isOpen()) { + can.sleep(); + } } int main(int argc, char* argv[]) { @@ -22,7 +21,7 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Fancy Rectangles"); + Canvas c(-1, -1, w, h, "Basic Cube"); c.setBackgroundColor(BLACK); c.run(cubeFunction); } \ No newline at end of file From 226bed3d154cefbbefe4e9941bd72fa00b4db26d Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 24 Mar 2020 19:15:09 -0400 Subject: [PATCH 008/105] Updates w/ gcc 9.3 --- Makefile | 2 +- install-mac | 12 ++++++++---- src/TSGL/Canvas.cpp | 10 +++++++--- src/TSGL/Object3D.cpp | 1 + src/tests/testCube.cpp | 2 +- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index f514192cb..0c8ac93ae 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ CXXFLAGS=-O3 -g3 -ggdb3 \ -I/usr/include/freetype2 \ -I/usr/include/freetype2/freetype \ -I./ \ - -std=c++0x -Xpreprocessor -fopenmp \ + -std=c++0x -fopenmp \ ${NOWARN} -fpermissive # -pedantic-errors diff --git a/install-mac b/install-mac index 2472d2756..3c92c4357 100755 --- a/install-mac +++ b/install-mac @@ -86,13 +86,17 @@ fi if grep --quiet clang check.txt; then echo "Installing g++...this may take a while!" brew install gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/gcc-9 /usr/local/bin/gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 /usr/local/bin/g++ + sudo rm /usr/local/bin/gcc + sudo rm /usr/local/bin/g++ + sudo ln -s /usr/local/Cellar/gcc/9.3.0/bin/gcc-9 /usr/local/bin/gcc + sudo ln -s /usr/local/Cellar/gcc/9.3.0/bin/g++-9 /usr/local/bin/g++ else echo "Installing g++...this may take a while!2" brew install gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/gcc-9 /usr/local/bin/gcc - sudo ln -s /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 /usr/local/bin/g++ + sudo rm /usr/local/bin/gcc + sudo rm /usr/local/bin/g++ + sudo ln -s /usr/local/Cellar/gcc/9.3.0/bin/gcc-9 /usr/local/bin/gcc + sudo ln -s /usr/local/Cellar/gcc/9.3.0/bin/g++-9 /usr/local/bin/g++ fi #Symlinks diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 683e938a2..b64573708 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2031,9 +2031,13 @@ void Canvas::initGl() { #endif // Enable and disable necessary stuff - glDisable(GL_DEPTH_TEST); // Disable depth testing because we're not drawing in 3d - glDisable(GL_DITHER); // Disable dithering because pixels do not (generally) overlap - glDisable(GL_CULL_FACE); // Disable culling because the camera is stationary + glEnable(GL_DEPTH_TEST); // Depth Testing + glDepthFunc(GL_LEQUAL); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + // glDisable(GL_DEPTH_TEST); // Disable depth testing because we're not drawing in 3d + // glDisable(GL_DITHER); // Disable dithering because pixels do not (generally) overlap + // glDisable(GL_CULL_FACE); // Disable culling because the camera is stationary glEnable(GL_BLEND); // Enable blending glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Set blending mode to standard alpha blending diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index c38949fd1..85cac1952 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -33,6 +33,7 @@ void Object3D::draw() { // glDrawArrays(geometryType, 0, numberOfVertices); glPushMatrix(); + glTranslatef(myCenterX, myCenterY, myCenterZ); glRotatef(myCurrentYaw, 1, 0, 0); glRotatef(myCurrentPitch, 0, 1, 0); glRotatef(myCurrentRoll, 0, 0, 1); diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 3efab81c9..933565159 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -22,6 +22,6 @@ int main(int argc, char* argv[]) { if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value Canvas c(-1, -1, w, h, "Basic Cube"); - c.setBackgroundColor(BLACK); + // c.setBackgroundColor(BLACK); c.run(cubeFunction); } \ No newline at end of file From 27b8e6724636fde021d40a58b660a4d724812c5b Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 26 Mar 2020 16:32:58 -0400 Subject: [PATCH 009/105] Cube drawing, once. Struggling to update instance variables and have it be reflected on the Canvas, but at least it renders once. --- src/TSGL/Canvas.cpp | 134 ++++++++++++++++++++++++++++++++--------- src/TSGL/Cube.cpp | 124 +++++++++++++++++++------------------- src/TSGL/Drawable.h | 12 ++++ src/TSGL/Object3D.cpp | 94 ++++++++++++++++------------- src/TSGL/Object3D.h | 31 ++++++++++ src/tests/testCube.cpp | 17 +++++- 6 files changed, 276 insertions(+), 136 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index b64573708..49a19a522 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -201,7 +201,77 @@ void Canvas::clearObjectBuffer(bool shouldFreeMemory) { objectBuffer.clear(); } -void Canvas::draw() { +void Canvas::draw( ) +{ + printf("Entered draw()\n"); + glfwMakeContextCurrent(window); + // Reset the window + glfwSetWindowShouldClose(window, GL_FALSE); + while(!glfwWindowShouldClose(window)) + { + #ifdef __APPLE__ + // leftWindowIndex = 0; + windowMutex.lock(); + #endif + // Scale to window size + GLint windowWidth, windowHeight; + glfwGetWindowSize(window, &windowWidth, &windowHeight); + glViewport(0, 0, windowWidth, windowHeight); + + // Draw stuff + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION_MATRIX); + glLoadIdentity(); + gluPerspective( 60, (double)windowWidth / (double)windowHeight, 0.1, 100 ); + + glMatrixMode(GL_MODELVIEW_MATRIX); + glTranslatef(0,0,-5); + + /* commented out stuff really only seems to + need to be called once per draw cycle tbh */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + if (objectBuffer.size() > 0) { + for (unsigned int i = 0; i < objectBuffer.size(); i++) { + Drawable* d = objectBuffer[i]; + d->draw(); + // if(d->isProcessed()) { + // if (!d->getIsTextured()) { + // d->draw(); + // } else { + // textureShaders(true); + // d->draw(); + // textureShaders(false); + // } + // } + } + } else { + objectBufferEmpty = true; + } + /* Cleanup states */ + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + // Update Screen + glfwSwapBuffers(window); + + #ifndef __APPLE__ + glfwPollEvents(); // Handle any I/O + #endif + glfwGetCursorPos(window, &mouseX, &mouseY); + glfwMakeContextCurrent(NULL); // We're drawing to window as soon as it's created + #ifdef __APPLE__ + windowMutex.unlock(); + #endif + + syncMutex.unlock(); + + if (toClose) glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +/* void Canvas::draw() { // Reset the window glfwSetWindowShouldClose(window, GL_FALSE); @@ -345,7 +415,7 @@ void Canvas::draw() { myDrawables->clear(); // Clear our buffer of shapes to be drawn } - /* not sure what the point of this chunk is. */ + // not sure what the point of this chunk is. if (hasEXTFramebuffer) glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); else @@ -359,9 +429,9 @@ void Canvas::draw() { --toRecord; } - /* very vital */ + // very vital glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - /* apparently not very vital at all */ + // apparently not very vital at all glDrawBuffer(drawBuffer); textureShaders(true); @@ -372,13 +442,13 @@ void Canvas::draw() { winWidth,winHeight,1,1,1,1,1,0 }; glBindTexture(GL_TEXTURE_2D,renderedTexture); - /* these 5 lines don't seem to do anything */ + // these 5 lines don't seem to do anything glPixelStorei(GL_UNPACK_ALIGNMENT,4); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - /* next two lines are very essential */ + // next two lines are very essential glBufferData(GL_ARRAY_BUFFER,32*sizeof(float),vertices,GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLE_STRIP,0,4); glFlush(); // Flush buffer data to the actual draw buffer @@ -399,7 +469,7 @@ void Canvas::draw() { if (toClose) glfwSetWindowShouldClose(window, GL_TRUE); } -} +} */ /*! * \brief Draws a monocolored arrow. @@ -1913,18 +1983,18 @@ int Canvas::getWindowY() { void Canvas::glDestroy() { // Free up our resources - glDetachShader(shaderProgram, shaderFragment); - glDetachShader(shaderProgram, shaderVertex); - glDeleteShader(shaderFragment); - glDeleteShader(shaderVertex); - glDeleteProgram(shaderProgram); - glDetachShader(textureShaderProgram, textureShaderFragment); - glDetachShader(textureShaderProgram, textureShaderVertex); - glDeleteShader(textureShaderFragment); - glDeleteShader(textureShaderVertex); - glDeleteProgram(textureShaderProgram); - glDeleteBuffers(1, &vertexBuffer); - glDeleteVertexArrays(1, &vertexArray); + // glDetachShader(shaderProgram, shaderFragment); + // glDetachShader(shaderProgram, shaderVertex); + // glDeleteShader(shaderFragment); + // glDeleteShader(shaderVertex); + // glDeleteProgram(shaderProgram); + // glDetachShader(textureShaderProgram, textureShaderFragment); + // glDetachShader(textureShaderProgram, textureShaderVertex); + // glDeleteShader(textureShaderFragment); + // glDeleteShader(textureShaderVertex); + // glDeleteProgram(textureShaderProgram); + // glDeleteBuffers(1, &vertexBuffer); + // glDeleteVertexArrays(1, &vertexArray); } /*! @@ -2016,12 +2086,15 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti initGlfw(); #ifndef _WIN32 initWindow(); - initGlew(); + printf("initGlew disabled.\n"); + printf("Also check glDestroy.\n"); + // initGlew(); glfwMakeContextCurrent(NULL); // Reset the context #endif } void Canvas::initGl() { + printf("Entered initGl.\n"); #ifdef _WIN32 initWindow(); initGlew(); @@ -2055,6 +2128,7 @@ void Canvas::initGl() { hasBackbuffer = ((int)dbuff[0] > 0); glfwMakeContextCurrent(NULL); // Reset the context + printf("Exiting initGl.\n"); } void Canvas::initGlew() { @@ -2187,6 +2261,7 @@ void Canvas::initGlfw() { } void Canvas::initWindow() { + printf("Entered initWindow.\n"); glfwSetErrorCallback(errorCallback); // Create a Window and the Context @@ -2195,15 +2270,15 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); // Set target GL minor version to 2.0 glfwWindowHint(GLFW_CLIENT_API,GLFW_OPENGL_ES_API); // Pi uses OpenGL ES #else - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Set target GL major version to 3 - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Set target GL minor version to 3.2 - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version + // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Set target GL major version to 3 + // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Set target GL minor version to 3.2 + // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile + // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window - glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer - glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first + // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window + // glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer + // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer + // glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); glfwMutex.lock(); // GLFW crashes if you try to make more than once window at once @@ -2226,12 +2301,13 @@ void Canvas::initWindow() { glfwSetWindowPos(window, monitorX, monitorY); glfwMakeContextCurrent(window); - glfwShowWindow(window); // Show the window + // glfwShowWindow(window); // Show the window glfwSetWindowUserPointer(window, this); glfwSetMouseButtonCallback(window, buttonCallback); glfwSetKeyCallback(window, keyCallback); glfwSetScrollCallback(window, scrollCallback); + printf("Exiting initWindow.\n"); } void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 8f97e9a00..83d75fbb1 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -9,9 +9,9 @@ namespace tsgl { * \param y The y coordinate of the center of the Cube. * \param z The z coordinate of the center of the Cube. * \param sideLength The side length of the Cube. - * \param yaw The Cube's yaw. - * \param pitch The Cube's pitch. - * \param roll The Cube's roll. + * \param yaw The Cube's yaw, in degrees. + * \param pitch The Cube's pitch, in degrees. + * \param roll The Cube's roll, in degrees. * \param c A ColorGLfloat for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. @@ -22,35 +22,35 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch TsglDebug("Cannot have a Cube with non-positive sidelength."); } mySideLength = sideLength; - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); + addVertex(-1*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); - - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); - - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); - - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c); - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c); - - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); } /*! @@ -60,9 +60,9 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \param y The y coordinate of the center of the Cube. * \param z The z coordinate of the center of the Cube. * \param sideLength The side length of the Cube. - * \param yaw The Cube's yaw. - * \param pitch The Cube's pitch. - * \param roll The Cube's roll. + * \param yaw The Cube's yaw, in degrees. + * \param pitch The Cube's pitch, in degrees. + * \param roll The Cube's roll, in degrees. * \param c An array of ColorGLfloats for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. @@ -73,35 +73,35 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch TsglDebug("Cannot have a Cube with non-positive side length."); } mySideLength = sideLength; - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); - - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); - - addVertex(-1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - addVertex(-1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, -1*mySideLength, c[0]); - addVertex(1*mySideLength, -1*mySideLength, -1*mySideLength, c[0]); - - addVertex(-1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); - addVertex(-1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, 1*mySideLength, 1*mySideLength, c[0]); - addVertex(1*mySideLength, -1*mySideLength, 1*mySideLength, c[0]); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); + + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); + addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); + addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); + addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); + + addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); + addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); + addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); + addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); } /** diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 30bf34ec2..00506a463 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -79,6 +79,18 @@ namespace tsgl { * \details Returns the value of the myCenterY private variable. */ virtual float getCenterY() { return myCenterY; } + + /*! + * \brief Accessor for the rotation x-coordinate of the Drawable. + * \details Returns the value of the myRotationPointX private variable. + */ + virtual float getRotationPointX() { return myRotationPointX; } + + /*! + * \brief Accessor for the rotation y-coordinate of the Drawable. + * \details Returns the value of the myRotationPointY private variable. + */ + virtual float getRotationPointY() { return myRotationPointY; } }; }; diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index 85cac1952..c64e658a2 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -11,7 +11,7 @@ namespace tsgl { * \warning You must inherit the parent's constructor if you are extending Object3D. * \note Refer to the Object3D class description for more details. */ -Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z) : Drawable() { +Object3D::Object3D(float x, float y, float z, float yaw, float pitch, float roll) : Drawable() { isTextured = false; myCurrentYaw = yaw; myCurrentPitch = pitch; @@ -19,6 +19,9 @@ Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z myCenterX = x; myCenterY = y; myCenterZ = z; + myRotationPointX = myCenterX; + myRotationPointY = myCenterY; + myRotationPointZ = myCenterZ; } /*! @@ -29,14 +32,13 @@ Object3D::Object3D(float yaw, float pitch, float roll, float x, float y, float z * if the above condition is met (vertex buffer = not full). */ void Object3D::draw() { - // glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 7 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - // glDrawArrays(geometryType, 0, numberOfVertices); - + printf("Drawbuffer Pitch: %f\n", getCenterZ()); glPushMatrix(); glTranslatef(myCenterX, myCenterY, myCenterZ); - glRotatef(myCurrentYaw, 1, 0, 0); - glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentPitch, 1, 0, 0); + glRotatef(myCurrentYaw, 0, 1, 0); glRotatef(myCurrentRoll, 0, 0, 1); + // glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); /* We have a color array and a vertex array */ glEnableClientState(GL_VERTEX_ARRAY); @@ -87,6 +89,11 @@ void Object3D::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &co } } +///////////////////////////////////////////////// +// MUTATORS +///////////////////////////////////////////////// + + /** * \brief Sets the Object3D to a new color. * \param c The new ColorGLfloat. @@ -123,6 +130,9 @@ void Object3D::setColor(ColorGLfloat c[]) { */ void Object3D::changeXBy(float deltaX) { attribMutex.lock(); + // if (myCenterX == myRotationPointX) { + // myRotationPointX += deltaX; + // } myCenterX += deltaX; attribMutex.unlock(); } @@ -133,6 +143,9 @@ void Object3D::changeXBy(float deltaX) { */ void Object3D::changeYBy(float deltaY) { attribMutex.lock(); + // if (myCenterY == myRotationPointY) { + // myRotationPointY += deltaY; + // } myCenterY += deltaY; attribMutex.unlock(); } @@ -143,6 +156,9 @@ void Object3D::changeYBy(float deltaY) { */ void Object3D::changeZBy(float deltaZ) { attribMutex.lock(); + // if (myCenterZ == myRotationPointZ) { + // myRotationPointZ += deltaZ; + // } myCenterZ += deltaZ; attribMutex.unlock(); } @@ -156,21 +172,16 @@ void Object3D::changeZBy(float deltaZ) { * old rotation point was at the Object3D's old center. */ void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { - // attribMutex.lock(); - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*7] += deltaX; //Transpose x - // vertices[(i*7)+1] += deltaY; //Transpose y - // vertices[(i*7)+2] += deltaZ; //Transpose z - // } - // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + attribMutex.lock(); + // if (myCenterX == myRotationPointX && myCenterY == myRotationPointY && myCenterZ == myRotationPointZ) { // myRotationPointX += deltaX; // myRotationPointY += deltaY; // myRotationPointZ += deltaZ; // } - // myCenterX += deltaX; - // myCenterY += deltaY; - // myCenterZ += deltaZ; - // attribMutex.unlock(); + myCenterX += deltaX; + myCenterY += deltaY; + myCenterZ += deltaZ; + attribMutex.unlock(); } /** @@ -178,9 +189,12 @@ void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { * \param x The new center x coordinate. */ void Object3D::setCenterX(float x) { - // attribMutex.lock(); - // myCenterX = x; - // attribMutex.unlock(); + attribMutex.lock(); + // if (myCenterX == myRotationPointX) { + // myRotationPointX = x; + // } + myCenterX = x; + attribMutex.unlock(); } /** @@ -188,9 +202,12 @@ void Object3D::setCenterX(float x) { * \param y The new center y coordinate. */ void Object3D::setCenterY(float y) { - // attribMutex.lock(); - // myCenterY = y; - // attribMutex.unlock(); + attribMutex.lock(); + // if (myCenterY == myRotationPointY) { + // myRotationPointY = y; + // } + myCenterY = y; + attribMutex.unlock(); } /** @@ -198,9 +215,12 @@ void Object3D::setCenterY(float y) { * \param z The new center z coordinate. */ void Object3D::setCenterZ(float z) { - // attribMutex.lock(); - // myCenterZ = z; - // attribMutex.unlock(); + attribMutex.lock(); + // if (myCenterZ == myRotationPointZ) { + // myRotationPointZ = z; + // } + myCenterZ = z; + attribMutex.unlock(); } /** @@ -212,26 +232,16 @@ void Object3D::setCenterZ(float z) { * old rotation point was at the Object3D's old center. */ void Object3D::setCenter(float x, float y, float z) { - float deltaX = x - myCenterX; //Change for x - float deltaY = y - myCenterY; //Change for y - float deltaZ = z - myCenterZ; - // attribMutex.lock(); - // if(myRotationPointX == myCenterX && myRotationPointY == myCenterY && myRotationPointZ == myCenterZ) { + attribMutex.lock(); + // if (myCenterX == myRotationPointX && myCenterY == myRotationPointY && myCenterZ == myRotationPointZ) { // myRotationPointX = x; // myRotationPointY = y; // myRotationPointZ = z; // } - - // myCenterX = x; - // myCenterY = y; - // myCenterZ = z; - - // for(int i = 0; i < numberOfVertices; i++) { - // vertices[i*7] += deltaX; //Transpose x - // vertices[(i*7)+1] += deltaY; //Transpose y - // vertices[(i*7)+2] += deltaZ; //Transpose y - // } - // attribMutex.unlock(); + myCenterX = x; + myCenterY = y; + myCenterZ = z; + attribMutex.unlock(); } /** diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h index cc88a62ba..66368cb12 100644 --- a/src/TSGL/Object3D.h +++ b/src/TSGL/Object3D.h @@ -71,6 +71,37 @@ class Object3D : public Drawable { virtual void setRotationPoint(float x, float y, float z); + /*! + * \brief Accessor for the center z-coordinate of the Object3D. + * \details Returns the value of the myCenterZ private variable. + */ + virtual float getCenterZ() { return myCenterZ; } // getCenterX, getCenterY inherited + + /*! + * \brief Accessor for the Yaw of the Object3D. + * \details Returns the value of the myCurrentYaw private variable. + */ + virtual float getYaw() { return myCurrentYaw; } + + /*! + * \brief Accessor for the Pitch of the Object3D. + * \details Returns the value of the myCurrentPitch private variable. + */ + virtual float getPitch() { return myCurrentPitch; } + + /*! + * \brief Accessor for the Roll of the Drawable. + * \details Returns the value of the myCurrentRoll private variable. + */ + virtual float getRoll() { return myCurrentRoll; } + + /*! + * \brief Accessor for the rotation z-coordinate of the Drawable. + * \details Returns the value of the myRotationPointZ private variable. + */ + virtual float getRotationPointZ() { return myRotationPointZ; } + + /*! * \brief Accessor that returns if Object3D is processed and ready to be drawn * \details This function returns true only if all vertices have been inserted into an array. diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 933565159..3ddf8b0ce 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -9,10 +9,21 @@ using namespace tsgl; void cubeFunction(Canvas& can) { - Cube * testCube = new Cube(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, ColorGLfloat(0.196,0.321,0.482,1)); + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; + Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); + // Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); can.add(testCube); + // can.add(testCube2); + float rotation = 0.0f; while (can.isOpen()) { can.sleep(); + testCube->setCenterZ(rotation); + //testCube2->setRoll(rotation); + rotation+=0.1; + printf("CenterZ %f\n", testCube->getCenterZ()); + // printf("Roll %f\n", testCube2->getRoll()); } } @@ -21,7 +32,7 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Basic Cube"); - // c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Cube"); + c.setBackgroundColor(BLACK); c.run(cubeFunction); } \ No newline at end of file From 922d6546792e7e4064eb5039d6217bdc4af739d5 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Sun, 29 Mar 2020 13:21:34 -0400 Subject: [PATCH 010/105] All known Cube functionality complete! --- src/TSGL/Canvas.cpp | 3 ++- src/TSGL/Cube.cpp | 18 ++++++++++++++++-- src/TSGL/Cube.h | 2 ++ src/TSGL/Object3D.cpp | 7 +++---- src/tests/testCube.cpp | 26 ++++++++++++++++++++------ 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 49a19a522..39e683528 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -201,7 +201,7 @@ void Canvas::clearObjectBuffer(bool shouldFreeMemory) { objectBuffer.clear(); } -void Canvas::draw( ) +void Canvas::draw() { printf("Entered draw()\n"); glfwMakeContextCurrent(window); @@ -213,6 +213,7 @@ void Canvas::draw( ) // leftWindowIndex = 0; windowMutex.lock(); #endif + glfwMakeContextCurrent(window); // Scale to window size GLint windowWidth, windowHeight; glfwGetWindowSize(window, &windowWidth, &windowHeight); diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 83d75fbb1..c0f0a2f55 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -105,8 +105,8 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch } /** - * \brief Mutates the distance from the Cube's front face to its back face. - * \param height The Cube's new length. + * \brief Mutates the distance between the Cube's opposite faces. + * \param length The Cube's new side length. */ void Cube::setSideLength(GLfloat length) { attribMutex.lock(); @@ -115,7 +115,11 @@ void Cube::setSideLength(GLfloat length) { attribMutex.unlock(); return; } + GLfloat ratio = length/mySideLength; mySideLength = length; + for(int i = 0; i < numberOfVertices * 3; i++) { + vertices[i] *= ratio; + } attribMutex.unlock(); // FIXME alter vertices } @@ -132,10 +136,20 @@ void Cube::changeSideLengthBy(GLfloat delta) { return; } mySideLength += delta; + for(int i = 0; i < numberOfVertices * 3; i++) { + if (vertices[i] > 0) + vertices[i] += delta/2; + else + vertices[i] -= delta/2; + } attribMutex.unlock(); // FIXME alter vertices } +GLfloat Cube::getSideLength() { + return mySideLength; +} + void Cube::setRotation(float radians) { } diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 8d80c5cf0..98bf623ae 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -27,6 +27,8 @@ class Cube : public Prism { virtual void changeSideLengthBy(float delta); + virtual GLfloat getSideLength(); + virtual void setRotation(float radians); virtual ~Cube(); diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index c64e658a2..ee17830e8 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -32,12 +32,11 @@ Object3D::Object3D(float x, float y, float z, float yaw, float pitch, float roll * if the above condition is met (vertex buffer = not full). */ void Object3D::draw() { - printf("Drawbuffer Pitch: %f\n", getCenterZ()); glPushMatrix(); glTranslatef(myCenterX, myCenterY, myCenterZ); - glRotatef(myCurrentPitch, 1, 0, 0); - glRotatef(myCurrentYaw, 0, 1, 0); - glRotatef(myCurrentRoll, 0, 0, 1); + glRotatef(myCurrentYaw, 0, 0, 1); + glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentRoll, 1, 0, 0); // glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); /* We have a color array and a vertex array */ diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 3ddf8b0ce..9bddbc61e 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -5,6 +5,7 @@ */ #include +#include using namespace tsgl; @@ -12,17 +13,30 @@ void cubeFunction(Canvas& can) { ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); - // Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); + Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCube); - // can.add(testCube2); + can.add(testCube2); float rotation = 0.0f; + // GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); - testCube->setCenterZ(rotation); + // testCube->setCenterX(sin(rotation)*2); + // testCube->setCenterY(cos(rotation)*2); + // testCube->setCenterZ(sin(rotation)); + // testCube->setYaw(rotation*45); + // testCube->setPitch(rotation*45); + // testCube->setRoll(rotation*45); + // testCube->setSideLength(cos(rotation)+1.01); + // if(testCube->getSideLength() >= 2) { + // delta = -0.05; + // } + // if(testCube->getSideLength() <= 0.05) { + // delta = 0.05; + // } + // testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); - rotation+=0.1; - printf("CenterZ %f\n", testCube->getCenterZ()); + rotation+=0.01; // printf("Roll %f\n", testCube2->getRoll()); } } From 445ad2487d3c125942217c38f1f416aedc243637 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 30 Mar 2020 00:13:10 -0400 Subject: [PATCH 011/105] Cuboid working, cylinder not working --- Makefile | 2 + src/TSGL/Canvas.h | 4 +- src/TSGL/Cube.cpp | 12 ++-- src/TSGL/Cube.h | 2 - src/TSGL/Cuboid.cpp | 118 +++++++++++++++++++++++++++++++++---- src/TSGL/Cuboid.h | 24 +++++--- src/TSGL/Cylinder.cpp | 23 +++++--- src/TSGL/Cylinder.h | 8 ++- src/TSGL/Object3D.cpp | 4 ++ src/TSGL/Object3D.h | 3 + src/TSGL/Prism.cpp | 11 ++-- src/tests/testCuboid.cpp | 68 +++++++++++++++++++++ src/tests/testCylinder.cpp | 55 +++++++++++++++++ 13 files changed, 288 insertions(+), 46 deletions(-) create mode 100644 src/tests/testCuboid.cpp create mode 100644 src/tests/testCylinder.cpp diff --git a/Makefile b/Makefile index 0c8ac93ae..2b774ac3e 100644 --- a/Makefile +++ b/Makefile @@ -79,6 +79,8 @@ BINARIES= \ bin/testConway \ bin/testCosineIntegral \ bin/testCube \ + bin/testCuboid \ + bin/testCylinder \ bin/testDumbSort \ bin/testFireworks \ bin/testForestFire \ diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 512cfd1ca..cf4a99e55 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -13,7 +13,9 @@ #include "Array.h" // Our own array for buffering drawing operations #include "Arrow.h" // Our own array for drawing arrows #include "Color.h" // Our own interface for converting color types -#include "Cube.h" +#include "Cube.h" // Our own class for drawing cubes +#include "Cuboid.h" // Our own class for drawing cuboids +#include "Cylinder.h" // Our own class for drawing cylinders #include "TriangleStrip.h" // Our own class for drawing polygons with colored vertices #include "Ellipse.h" // Our own class for drawing ellipses #include "Circle.h" // Our own class for drawing circles diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index c0f0a2f55..399bfccb3 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -17,12 +17,13 @@ namespace tsgl { * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c) -: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices +: Prism(x, y, z, 24, yaw, pitch, roll) { // FIXME vertices + geometryType = GL_QUADS; if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } mySideLength = sideLength; - addVertex(-1*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); @@ -68,7 +69,8 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices +: Prism(x, y, z, 24, yaw, pitch, roll) { // FIXME vertices + geometryType = GL_QUADS; if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive side length."); } @@ -150,10 +152,6 @@ GLfloat Cube::getSideLength() { return mySideLength; } -void Cube::setRotation(float radians) { - -} - /*! * \brief Destructor for the Cube. */ diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 98bf623ae..0c82ed8ae 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -29,8 +29,6 @@ class Cube : public Prism { virtual GLfloat getSideLength(); - virtual void setRotation(float radians); - virtual ~Cube(); }; diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 10da60615..88a3bf5e9 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -18,12 +18,44 @@ namespace tsgl { * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ -Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, 4, yaw, pitch, roll) { +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c) +: Prism(x, y, z, 24, yaw, pitch, roll) { + geometryType = GL_QUADS; if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } - // add vertices based on parameters and color + myLength = length; + myWidth = width; + myHeight = height; + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); + + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); } /*! @@ -42,26 +74,62 @@ Cuboid::Cuboid(float x, float y, float z, float length, float width, float heigh * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ -Cuboid::Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, 4, yaw, pitch, roll) { // FIXME vertices +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]) +: Prism(x, y, z, 24, yaw, pitch, roll) { + geometryType = GL_QUADS; if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } - // add vertices based on parameters and color + myLength = length; + myWidth = width; + myHeight = height; + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); + + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); + + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); + + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); + + addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); + addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); + addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); + addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); + + addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); + addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); + addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); + addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); } /** * \brief Mutates the distance from the Cuboid's front face to its back face. * \param height The Cuboid's new length. */ -void Cuboid::setLength(float length) { +void Cuboid::setLength(GLfloat length) { attribMutex.lock(); if (length <= 0) { TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); attribMutex.unlock(); return; } + GLfloat ratio = length/myLength; myLength = length; + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*3 + 2] *= ratio; + } attribMutex.unlock(); } @@ -69,7 +137,7 @@ void Cuboid::setLength(float length) { * \brief Mutates the distance from the Cuboid's front face to its back face by the parameter amount. * \param delta The amount by which to change the length of the Cuboid. */ -void Cuboid::changeLengthBy(float delta) { +void Cuboid::changeLengthBy(GLfloat delta) { attribMutex.lock(); if (myLength + delta <= 0) { TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); @@ -77,6 +145,12 @@ void Cuboid::changeLengthBy(float delta) { return; } myLength += delta; + for(int i = 0; i < numberOfVertices; i++) { + if (vertices[i*3 + 2] > 0) + vertices[i*3 + 2] += delta/2; + else + vertices[i*3 + 2] -= delta/2; + } attribMutex.unlock(); } @@ -84,14 +158,18 @@ void Cuboid::changeLengthBy(float delta) { * \brief Mutates the distance from the Cuboid's left face to its right face. * \param height The Cuboid's new width. */ -void Cuboid::setWidth(float width) { +void Cuboid::setWidth(GLfloat width) { attribMutex.lock(); if (width <= 0) { TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); attribMutex.unlock(); return; } + GLfloat ratio = width/myWidth; myWidth = width; + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*3] *= ratio; + } attribMutex.unlock(); } @@ -99,7 +177,7 @@ void Cuboid::setWidth(float width) { * \brief Mutates the distance from the Cuboid's left face to its right face by the parameter amount. * \param delta The amount by which to change the width of the Cuboid. */ -void Cuboid::changeWidthBy(float delta) { +void Cuboid::changeWidthBy(GLfloat delta) { attribMutex.lock(); if (myWidth + delta <= 0) { TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); @@ -107,6 +185,12 @@ void Cuboid::changeWidthBy(float delta) { return; } myWidth += delta; + for(int i = 0; i < numberOfVertices; i++) { + if (vertices[i*3] > 0) + vertices[i*3] += delta/2; + else + vertices[i*3] -= delta/2; + } attribMutex.unlock(); } @@ -114,14 +198,18 @@ void Cuboid::changeWidthBy(float delta) { * \brief Mutates the distance from the center of the Cuboid's base to the top. * \param height The Cuboid's new height. */ -void Cuboid::setHeight(float height) { +void Cuboid::setHeight(GLfloat height) { attribMutex.lock(); if (height <= 0) { TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); attribMutex.unlock(); return; } + GLfloat ratio = height/myHeight; myHeight = height; + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*3 + 1] *= ratio; + } attribMutex.unlock(); } @@ -129,7 +217,7 @@ void Cuboid::setHeight(float height) { * \brief Mutates the distance from the center of the Cuboid's base to the top by the parameter amount. * \param delta The amount by which to change the height of the Cuboid. */ -void Cuboid::changeHeightBy(float delta) { +void Cuboid::changeHeightBy(GLfloat delta) { attribMutex.lock(); if (myHeight + delta <= 0) { TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); @@ -137,6 +225,12 @@ void Cuboid::changeHeightBy(float delta) { return; } myHeight += delta; + for(int i = 0; i < numberOfVertices; i++) { + if (vertices[i*3 + 1] > 0) + vertices[i*3 + 1] += delta/2; + else + vertices[i*3 + 1] -= delta/2; + } attribMutex.unlock(); } diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index 7985d4e3a..d142a0c0f 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -17,23 +17,29 @@ namespace tsgl { */ class Cuboid : public Prism { protected: - float myLength, myWidth, myHeight; + GLfloat myLength, myWidth, myHeight; public: - Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c); + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c); - Cuboid(float x, float y, float z, float length, float width, float height, float yaw, float pitch, float roll, ColorFloat c[]); + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]); - virtual void setLength(float length); + virtual void setLength(GLfloat length); - virtual void changeLengthBy(float delta); + virtual void changeLengthBy(GLfloat delta); - virtual void setWidth(float width); + virtual void setWidth(GLfloat width); - virtual void changeWidthBy(float delta); + virtual void changeWidthBy(GLfloat delta); - virtual void setHeight(float height); + virtual void setHeight(GLfloat height); - virtual void changeHeightBy(float delta); + virtual void changeHeightBy(GLfloat delta); + + virtual GLfloat getLength() { return myLength; } + + virtual GLfloat getHeight() { return myHeight; } + + virtual GLfloat getWidth() { return myWidth; } virtual ~Cuboid(); }; diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index f9f8bd75c..e57619b0a 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -17,12 +17,14 @@ namespace tsgl { * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ -Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll) { +Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) +: Prism(x, y, z, 2 * ( (radius > 1) ? radius * 6 : 6), yaw, pitch, roll) { if (radius <= 0 || height <= 0) { TsglDebug("Cannot have a Cylinder with non-positive height or radius."); } - // add vertices based on parameters and color + myRadius = radius; + myHeight = height; + geometryType = GL_TRIANGLES; } /*! @@ -40,12 +42,15 @@ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ -Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll) { // FIXME vertices - if (radius <= 0 || height <= 0) { +Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) +: Prism(x, y, z, 2 * ( (radius > 1) ? radius * 6 : 6), yaw, pitch, roll) { // FIXME vertices + if (radius <= 0 || height <= 0) { TsglDebug("Cannot have a Cylinder with non-positive height or radius."); } - // add vertices based on parameters and color + myRadius = radius; + myHeight = height; + geometryType = GL_TRIANGLES; + } /** @@ -61,6 +66,7 @@ void Cylinder::setRadius(float radius) { } myRadius = radius; attribMutex.unlock(); + // fix vertices } /** @@ -76,6 +82,7 @@ void Cylinder::changeRadiusBy(float delta) { } myRadius += delta; attribMutex.unlock(); + // fix vertices } /** @@ -91,6 +98,7 @@ void Cylinder::setHeight(float height) { } myHeight = height; attribMutex.unlock(); + // fix vertices } /** @@ -106,6 +114,7 @@ void Cylinder::changeHeightBy(float delta) { } myHeight += delta; attribMutex.unlock(); + // fix vertices } /*! diff --git a/src/TSGL/Cylinder.h b/src/TSGL/Cylinder.h index 6a44ad213..269e38b90 100644 --- a/src/TSGL/Cylinder.h +++ b/src/TSGL/Cylinder.h @@ -19,9 +19,9 @@ class Cylinder : public Prism { protected: float myRadius, myHeight; public: - Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c); - Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]); virtual void setRadius(float radius); @@ -31,6 +31,10 @@ class Cylinder : public Prism { virtual void changeHeightBy(float delta); + virtual GLfloat getRadius() { return myRadius; } + + virtual GLfloat getHeight() { return myHeight; } + virtual ~Cylinder(); }; diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index ee17830e8..6bcdc0ff3 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -345,6 +345,10 @@ void Object3D::setRotationPoint(float x, float y, float z) { attribMutex.unlock(); } +void Object3D::setRotation(float radians) { + +} + Object3D::~Object3D() { delete[] vertices; } diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h index 66368cb12..99086f3f1 100644 --- a/src/TSGL/Object3D.h +++ b/src/TSGL/Object3D.h @@ -101,6 +101,9 @@ class Object3D : public Drawable { */ virtual float getRotationPointZ() { return myRotationPointZ; } + virtual void setRotation(float radians); + + /*! * \brief Accessor that returns if Object3D is processed and ready to be drawn diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index b67e96b2d..9f66a9f7a 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -70,7 +70,7 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, * \param x The x coordinate of the center of the Prism. * \param y The y coordinate of the center of the Prism. * \param z The z coordinate of the center of the Prism. - * \param sides The number of sides of the Prism's base. + * \param numVertices The number of vertices of the Prism. * \param yaw The Prism's yaw. * \param pitch The Prism's pitch. * \param roll The Prism's roll. @@ -79,15 +79,14 @@ Prism::Prism(float x, float y, float z, float vertices[], int sides, float yaw, * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, int sides, float yaw, float pitch, float roll) : Object3D(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, int numVertices, float yaw, float pitch, float roll) : Object3D(x, y, z, yaw, pitch, roll) { attribMutex.lock(); - if (sides < 3) { - TsglDebug("Cannot have a Prism with fewer than 3 sides."); + if (numVertices < 12) { + TsglDebug("Cannot have a Prism with fewer than 12 vertices."); } - numberOfVertices = sides * 6; + numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; - geometryType = GL_QUADS; attribMutex.unlock(); } diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp new file mode 100644 index 000000000..59a479142 --- /dev/null +++ b/src/tests/testCuboid.cpp @@ -0,0 +1,68 @@ +/* + * testCuboid.cpp + * + * Usage: ./testCuboid + */ + +#include +#include + +using namespace tsgl; + +void cuboidFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, colors); + // Cuboid * testCuboid2 = new Cuboid(-3.0, 0.0, 0.0, 1, 3, 2, 0.0, 0.0, 0.0, colors); + can.add(testCuboid); + // can.add(testCuboid2); + float rotation = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testCuboid->setCenterX(sin(rotation)*2); + // testCuboid->setCenterY(cos(rotation)*2); + // testCuboid->setCenterZ(sin(rotation)); + // testCuboid->setYaw(rotation*45); + // testCuboid->setPitch(rotation*45); + // testCuboid->setRoll(rotation*45); + // testCuboid->setWidth(cos(rotation)+1.01); + // testCuboid->setHeight(cos(rotation)+3.01); + // testCuboid->setLength(cos(rotation)+2.01); + // if(testCuboid->getWidth() >= 2) { + // delta = -0.05; + // } + // if(testCuboid->getWidth() <= 0.05) { + // delta = 0.05; + // } + // testCuboid->changeWidthBy(delta); + + // if(testCuboid->getHeight() >= 5) { + // delta = -0.05; + // } + // if(testCuboid->getHeight() <= 3) { + // delta = 0.05; + // } + // testCuboid->changeHeightBy(delta); + + // if(testCuboid->getLength() >= 3) { + // delta = -0.05; + // } + // if(testCuboid->getLength() <= 1) { + // delta = 0.05; + // } + // testCuboid->changeLengthBy(delta); + // rotation+=0.01; + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cuboid"); + c.setBackgroundColor(BLACK); + c.run(cuboidFunction); +} \ No newline at end of file diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp new file mode 100644 index 000000000..dc76998d1 --- /dev/null +++ b/src/tests/testCylinder.cpp @@ -0,0 +1,55 @@ +/* + * testCylinder.cpp + * + * Usage: ./testCylinder + */ + +#include +#include + +using namespace tsgl; + +void cylinderFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0,0.5,0.5,0.8), + ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0,0.5,0.8) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 3, 0.0, 0.0, 0.0, colors); + // Cylinder * testCylinder2 = new Cylinder(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + can.add(testCylinder); + // can.add(testCylinder2); + // float rotation = 0.0f; + // GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testCylinder->setCenterX(sin(rotation)*2); + // testCylinder->setCenterY(cos(rotation)*2); + // testCylinder->setCenterZ(sin(rotation)); + // testCylinder->setYaw(rotation*45); + // testCylinder->setPitch(rotation*45); + // testCylinder->setRoll(rotation*45); + // testCylinder->setSideLength(cos(rotation)+1.01); + // if(testCylinder->getSideLength() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getSideLength() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeSideLengthBy(delta); + //testCylinder2->setRoll(rotation); + // rotation+=0.01; + // printf("Roll %f\n", testCylinder2->getRoll()); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cylinder"); + c.setBackgroundColor(BLACK); + c.run(cylinderFunction); +} \ No newline at end of file From 377b8cb0b1992acd5a9924f470585f1ea56281de Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 2 Apr 2020 17:09:15 -0400 Subject: [PATCH 012/105] Basic versions of all 3D Objects complete. --- Makefile | 3 + src/TSGL/Canvas.h | 2 + src/TSGL/Cube.cpp | 26 ++-- src/TSGL/Cube.h | 6 +- src/TSGL/Cuboid.cpp | 40 +++--- src/TSGL/Cuboid.h | 6 +- src/TSGL/Cylinder.cpp | 87 +------------ src/TSGL/Cylinder.h | 14 --- src/TSGL/Ellipsoid.cpp | 162 ++++++++++++++++-------- src/TSGL/Ellipsoid.h | 31 +++-- src/TSGL/Object3D.cpp | 3 +- src/TSGL/Prism.cpp | 239 ++++++++++++++++++++++++------------ src/TSGL/Prism.h | 23 ++-- src/TSGL/Sphere.cpp | 118 ++++++++++++------ src/TSGL/Sphere.h | 15 ++- src/TSGL/Util.h | 2 + src/tests/testCylinder.cpp | 36 +++--- src/tests/testEllipsoid.cpp | 80 ++++++++++++ src/tests/testPrism.cpp | 62 ++++++++++ src/tests/testSphere.cpp | 53 ++++++++ 20 files changed, 670 insertions(+), 338 deletions(-) create mode 100644 src/tests/testEllipsoid.cpp create mode 100644 src/tests/testPrism.cpp create mode 100644 src/tests/testSphere.cpp diff --git a/Makefile b/Makefile index 2b774ac3e..d0d174f14 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ BINARIES= \ bin/testCuboid \ bin/testCylinder \ bin/testDumbSort \ + bin/testEllipsoid \ bin/testFireworks \ bin/testForestFire \ bin/testFunction \ @@ -102,6 +103,7 @@ BINARIES= \ bin/testPhilosophers \ bin/testProducerConsumer \ bin/testPong \ + bin/testPrism \ bin/testProgressBar \ bin/testProjectiles \ bin/testReaderWriter \ @@ -111,6 +113,7 @@ BINARIES= \ bin/testSmartSort \ bin/testSpectrogram \ bin/testSpectrum \ + bin/testSphere \ bin/testStar \ bin/testText \ bin/testTextCart \ diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index cf4a99e55..a33a506b4 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -18,6 +18,7 @@ #include "Cylinder.h" // Our own class for drawing cylinders #include "TriangleStrip.h" // Our own class for drawing polygons with colored vertices #include "Ellipse.h" // Our own class for drawing ellipses +#include "Ellipsoid.h" // Our own class for drawing ellipsoids #include "Circle.h" // Our own class for drawing circles #include "ConcavePolygon.h" // Our own class for concave polygons with colored vertices #include "ConvexPolygon.h" // Our own class for convex polygons with colored vertices @@ -28,6 +29,7 @@ #include "ProgressBar.h" // Our own class for drawing progress bars #include "Rectangle.h" // Our own class for drawing rectangles #include "RegularPolygon.h" // Our own class for drawing regular polygons +#include "Sphere.h" // Our own class for drawing spheres #include "Square.h" // Our own class for drawing squares #include "Star.h" // Our own class for drawing stars #include "Text.h" // Our own class for drawing text diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 399bfccb3..a742f8954 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -17,12 +17,17 @@ namespace tsgl { * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c) -: Prism(x, y, z, 24, yaw, pitch, roll) { // FIXME vertices - geometryType = GL_QUADS; +: Object3D(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } + attribMutex.lock(); + geometryType = GL_QUADS; mySideLength = sideLength; + numberOfVertices = 24; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + attribMutex.unlock(); addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); @@ -69,12 +74,17 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Prism(x, y, z, 24, yaw, pitch, roll) { // FIXME vertices - geometryType = GL_QUADS; +: Object3D(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { - TsglDebug("Cannot have a Cube with non-positive side length."); + TsglDebug("Cannot have a Cube with non-positive sidelength."); } + attribMutex.lock(); + geometryType = GL_QUADS; mySideLength = sideLength; + numberOfVertices = 24; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + attribMutex.unlock(); addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); @@ -111,12 +121,11 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \param length The Cube's new side length. */ void Cube::setSideLength(GLfloat length) { - attribMutex.lock(); if (length <= 0) { TsglDebug("Cannot have a Cube with side length less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); GLfloat ratio = length/mySideLength; mySideLength = length; for(int i = 0; i < numberOfVertices * 3; i++) { @@ -131,12 +140,11 @@ void Cube::setSideLength(GLfloat length) { * \param delta The amount by which to change the length of the Cube. */ void Cube::changeSideLengthBy(GLfloat delta) { - attribMutex.lock(); if (mySideLength + delta <= 0) { TsglDebug("Cannot have a Cube with length less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); mySideLength += delta; for(int i = 0; i < numberOfVertices * 3; i++) { if (vertices[i] > 0) diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 0c82ed8ae..a16df6779 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -5,7 +5,7 @@ #ifndef CUBE_H_ #define CUBE_H_ -#include "Prism.h" // For extending our Prism object +#include "Object3D.h" // For extending our Prism object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cube * \brief Draw an arbitrary Cube with colored vertices. * \details Cube is a class for holding vertex data for a Cube. - * \details Cube is a subclass of Prism with all square faces. + * \details Cube is a 6-sided subclass of Object3D with all square faces. */ -class Cube : public Prism { +class Cube : public Object3D { protected: GLfloat mySideLength; public: diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 88a3bf5e9..60ac4b916 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -14,19 +14,24 @@ namespace tsgl { * \param yaw The Cuboid's yaw. * \param pitch The Cuboid's pitch. * \param roll The Cuboid's roll. - * \param c A ColorFloat for the Cuboid's vertex colors. + * \param c A ColorGLfloat for the Cuboid's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c) -: Prism(x, y, z, 24, yaw, pitch, roll) { - geometryType = GL_QUADS; +: Object3D(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } + attribMutex.lock(); + geometryType = GL_QUADS; myLength = length; myWidth = width; myHeight = height; + numberOfVertices = 24; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + attribMutex.unlock(); addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); @@ -70,19 +75,24 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat * \param yaw The Cuboid's yaw. * \param pitch The Cuboid's pitch. * \param roll The Cuboid's roll. - * \param c An array of ColorFloats for the Cuboid's vertex colors. + * \param c An array of ColorGLfloats for the Cuboid's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Prism(x, y, z, 24, yaw, pitch, roll) { - geometryType = GL_QUADS; +: Object3D(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } + attribMutex.lock(); + geometryType = GL_QUADS; myLength = length; myWidth = width; myHeight = height; + numberOfVertices = 24; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + attribMutex.unlock(); addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); @@ -119,12 +129,11 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat * \param height The Cuboid's new length. */ void Cuboid::setLength(GLfloat length) { - attribMutex.lock(); if (length <= 0) { TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); GLfloat ratio = length/myLength; myLength = length; for(int i = 0; i < numberOfVertices; i++) { @@ -138,12 +147,11 @@ void Cuboid::setLength(GLfloat length) { * \param delta The amount by which to change the length of the Cuboid. */ void Cuboid::changeLengthBy(GLfloat delta) { - attribMutex.lock(); if (myLength + delta <= 0) { TsglDebug("Cannot have a Cuboid with length less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); myLength += delta; for(int i = 0; i < numberOfVertices; i++) { if (vertices[i*3 + 2] > 0) @@ -159,12 +167,11 @@ void Cuboid::changeLengthBy(GLfloat delta) { * \param height The Cuboid's new width. */ void Cuboid::setWidth(GLfloat width) { - attribMutex.lock(); if (width <= 0) { TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); GLfloat ratio = width/myWidth; myWidth = width; for(int i = 0; i < numberOfVertices; i++) { @@ -178,12 +185,11 @@ void Cuboid::setWidth(GLfloat width) { * \param delta The amount by which to change the width of the Cuboid. */ void Cuboid::changeWidthBy(GLfloat delta) { - attribMutex.lock(); if (myWidth + delta <= 0) { TsglDebug("Cannot have a Cuboid with width less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); myWidth += delta; for(int i = 0; i < numberOfVertices; i++) { if (vertices[i*3] > 0) @@ -199,12 +205,11 @@ void Cuboid::changeWidthBy(GLfloat delta) { * \param height The Cuboid's new height. */ void Cuboid::setHeight(GLfloat height) { - attribMutex.lock(); if (height <= 0) { TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); GLfloat ratio = height/myHeight; myHeight = height; for(int i = 0; i < numberOfVertices; i++) { @@ -218,12 +223,11 @@ void Cuboid::setHeight(GLfloat height) { * \param delta The amount by which to change the height of the Cuboid. */ void Cuboid::changeHeightBy(GLfloat delta) { - attribMutex.lock(); if (myHeight + delta <= 0) { TsglDebug("Cannot have a Cuboid with height less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); myHeight += delta; for(int i = 0; i < numberOfVertices; i++) { if (vertices[i*3 + 1] > 0) diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index d142a0c0f..979a8d844 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -5,7 +5,7 @@ #ifndef CUBOID_H_ #define CUBOID_H_ -#include "Prism.h" // For extending our Prism object +#include "Object3D.h" // For extending our Prism object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cuboid * \brief Draw an arbitrary Cuboid with colored vertices. * \details Cuboid is a class for holding vertex data for a Cuboid. - * \details Cuboid is a subclass of Prism with all rectangular faces. + * \details Cuboid is a 6-sided subclass of Object3D with all rectangular faces. */ -class Cuboid : public Prism { +class Cuboid : public Object3D { protected: GLfloat myLength, myWidth, myHeight; public: diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index e57619b0a..c2a3e3f21 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -13,19 +13,12 @@ namespace tsgl { * \param yaw The Cylinder's yaw. * \param pitch The Cylinder's pitch. * \param roll The Cylinder's roll. - * \param c A ColorFloat for the Cylinder's vertex colors. + * \param c A ColorGLfloat for the Cylinder's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) -: Prism(x, y, z, 2 * ( (radius > 1) ? radius * 6 : 6), yaw, pitch, roll) { - if (radius <= 0 || height <= 0) { - TsglDebug("Cannot have a Cylinder with non-positive height or radius."); - } - myRadius = radius; - myHeight = height; - geometryType = GL_TRIANGLES; -} +: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { } /*! * \brief Explicitly constructs a new Cylinder. @@ -38,84 +31,12 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl * \param yaw The Cylinder's yaw. * \param pitch The Cylinder's pitch. * \param roll The Cylinder's roll. - * \param c An array of ColorFloats for the Cylinder's vertex colors. + * \param c An array of ColorGLfloats for the Cylinder's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Prism(x, y, z, 2 * ( (radius > 1) ? radius * 6 : 6), yaw, pitch, roll) { // FIXME vertices - if (radius <= 0 || height <= 0) { - TsglDebug("Cannot have a Cylinder with non-positive height or radius."); - } - myRadius = radius; - myHeight = height; - geometryType = GL_TRIANGLES; - -} - -/** - * \brief Mutates the radius of the Cylinder's base. - * \param height The Cylinder's new base radius. - */ -void Cylinder::setRadius(float radius) { - attribMutex.lock(); - if (radius <= 0) { - TsglDebug("Cannot have a Cylinder with radius less than or equal to 0."); - attribMutex.unlock(); - return; - } - myRadius = radius; - attribMutex.unlock(); - // fix vertices -} - -/** - * \brief Mutates the radius of the Cylinder's base by the parameter amount. - * \param delta The amount by which to change the radius of the Cylinder's base. - */ -void Cylinder::changeRadiusBy(float delta) { - attribMutex.lock(); - if (myRadius + delta <= 0) { - TsglDebug("Cannot have a Cylinder with radius less than or equal to 0."); - attribMutex.unlock(); - return; - } - myRadius += delta; - attribMutex.unlock(); - // fix vertices -} - -/** - * \brief Mutates the distance from the center of the Cylinder's base to the top. - * \param height The Cylinder's new height. - */ -void Cylinder::setHeight(float height) { - attribMutex.lock(); - if (height <= 0) { - TsglDebug("Cannot have a Cylinder with height less than or equal to 0."); - attribMutex.unlock(); - return; - } - myHeight = height; - attribMutex.unlock(); - // fix vertices -} - -/** - * \brief Mutates the distance from the center of the Cylinder's base to the top by the parameter amount. - * \param delta The amount by which to change the height of the Cylinder. - */ -void Cylinder::changeHeightBy(float delta) { - attribMutex.lock(); - if (myHeight + delta <= 0) { - TsglDebug("Cannot have a Cylinder with height less than or equal to 0."); - attribMutex.unlock(); - return; - } - myHeight += delta; - attribMutex.unlock(); - // fix vertices -} +: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { } /*! * \brief Destructor for the Cylinder. diff --git a/src/TSGL/Cylinder.h b/src/TSGL/Cylinder.h index 269e38b90..c288f7e9a 100644 --- a/src/TSGL/Cylinder.h +++ b/src/TSGL/Cylinder.h @@ -16,25 +16,11 @@ namespace tsgl { * \details Cylinder is a subclass of Prism with a circular base. */ class Cylinder : public Prism { -protected: - float myRadius, myHeight; public: Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c); Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]); - virtual void setRadius(float radius); - - virtual void changeRadiusBy(float delta); - - virtual void setHeight(float height); - - virtual void changeHeightBy(float delta); - - virtual GLfloat getRadius() { return myRadius; } - - virtual GLfloat getHeight() { return myHeight; } - virtual ~Cylinder(); }; diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 5f4104109..5503fb276 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -14,19 +14,33 @@ namespace tsgl { * \param yaw The Ellipsoid's yaw. * \param pitch The Ellipsoid's pitch. * \param roll The Ellipsoid's roll. - * \param c A ColorFloat for the Ellipsoid's vertex colors. + * \param c A ColorGLfloat for the Ellipsoid's vertex colors. * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, float xRadius, float yRadius, float zRadius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { - attribMutex.lock(); +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + verticalSections = 36; + horizontalSections = 20; + numberOfVertices = verticalSections*horizontalSections*2; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; myXRadius = xRadius; myYRadius = yRadius; myZRadius = zRadius; attribMutex.unlock(); + for(int b=0;b 0) + vertices[i*3 + 1] += delta/2; + else + vertices[i*3 + 1] -= delta/2; + } + attribMutex.unlock(); } -// /** -// * \brief Mutates the distance from the center of the Prism's base to the tip. -// * \param height The Prism's new height. -// */ -// void Prism::setHeight(float height) { -// attribMutex.lock(); -// if (height <= 0) { -// TsglDebug("Cannot have a Prism with height less than or equal to 0."); -// attribMutex.unlock(); -// return; -// } -// myHeight = height; -// attribMutex.unlock(); -// } +/** + * \brief Mutates the distance from the center of the Prism's base to the tip. + * \param height The Prism's new height. + */ +void Prism::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + GLfloat ratio = radius/myRadius; + myRadius = radius; + for (int i = 0; i < numberOfVertices; i++) { + vertices[i*3] *= ratio; + vertices[i*3 + 2] *= ratio; + } + attribMutex.unlock(); +} -// /** -// * \brief Mutates the distance from the center of the Prism's base to the tip by the parameter amount. -// * \param delta The amount by which to change the height of the Prism. -// */ -// void Prism::changeHeightBy(float delta) { -// attribMutex.lock(); -// if (myHeight + delta <= 0) { -// TsglDebug("Cannot have a Prism with height less than or equal to 0."); -// attribMutex.unlock(); -// return; -// } -// myHeight += delta; -// attribMutex.unlock(); -// } +/** + * \brief Mutates the distance from the center of the Prism's base to the tip by the parameter amount. + * \param delta The amount by which to change the height of the Prism. + */ +void Prism::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Prism with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + for (int i = 0; i < mySides; i++) { + // 0, 2 + vertices[i*36 + 3] = myRadius * cos(TWOPI * i / mySides); + vertices[i*36 + 5] = myRadius * sin(TWOPI * i / mySides); + + vertices[i*36 + 6] = myRadius * cos(TWOPI * (i + 1) / mySides); + vertices[i*36 + 8] = myRadius * sin(TWOPI * (i + 1) / mySides); + + vertices[i*36 + 9] = myRadius * cos(TWOPI * i / mySides); + vertices[i*36 + 11] = myRadius * sin(TWOPI * i / mySides); + + vertices[i*36 + 12] = myRadius * cos(TWOPI * (i + 1) / mySides); + vertices[i*36 + 14] = myRadius * sin(TWOPI * (i + 1) / mySides); + + vertices[i*36 + 15] = myRadius * cos(TWOPI * i / mySides); + vertices[i*36 + 17] = myRadius * sin(TWOPI * i / mySides); + + vertices[i*36 + 18] = myRadius * cos(TWOPI * (i + 1) / mySides); + vertices[i*36 + 20] = myRadius * sin(TWOPI * (i + 1) / mySides); + + vertices[i*36 + 21] = myRadius * cos(TWOPI * i / mySides); + vertices[i*36 + 23] = myRadius * sin(TWOPI * i / mySides); + + vertices[i*36 + 24] = myRadius * cos(TWOPI * (i + 1) / mySides); + vertices[i*36 + 26] = myRadius * sin(TWOPI * (i + 1) / mySides); + + vertices[i*36 + 27] = myRadius * cos(TWOPI * i / mySides); + vertices[i*36 + 29] = myRadius * sin(TWOPI * i / mySides); + + vertices[i*36 + 30] = myRadius * cos(TWOPI * (i + 1) / mySides); + vertices[i*36 + 32] = myRadius * sin(TWOPI * (i + 1) / mySides); + + // 33, 35 + } + attribMutex.unlock(); +} /*! * \brief Destructor for the Prism. diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h index 83147d342..ab84adaa4 100644 --- a/src/TSGL/Prism.h +++ b/src/TSGL/Prism.h @@ -16,20 +16,29 @@ namespace tsgl { */ class Prism : public Object3D { protected: - // float myHeight; - Prism(float x, float y, float z, int sides, float yaw, float pitch, float roll); + GLfloat myHeight; + GLfloat myRadius; + int mySides; public: - Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c); + Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c); - Prism(float x, float y, float z, float vertices[], int sides, float yaw, float pitch, float roll, ColorFloat c[]); + Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]); virtual ~Prism(); - // virtual void setHeight(float height); + virtual void setHeight(GLfloat height); - // virtual void changeHeightBy(float delta); + virtual void changeHeightBy(GLfloat delta); - virtual ColorFloat* getColor(); + virtual void setRadius(GLfloat radius); + + virtual void changeRadiusBy(GLfloat delta); + + virtual GLfloat getRadius() { return myRadius; } + + virtual GLfloat getHeight() { return myHeight; } + + // virtual ColorGLfloat* getColor(); }; } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 3c7670d5b..ad0dde0a2 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -12,17 +12,31 @@ namespace tsgl { * \param yaw The Sphere's yaw. * \param pitch The Sphere's pitch. * \param roll The Sphere's roll. - * \param c A ColorFloat for the Sphere's vertex colors. + * \param c A ColorGLfloat for the Sphere's vertex colors. * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ -Sphere::Sphere(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { - attribMutex.lock(); +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + verticalSections = 36; + horizontalSections = 20; + numberOfVertices = verticalSections*horizontalSections*2; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; myRadius = radius; attribMutex.unlock(); + for(int b=0;bsetCenterX(sin(rotation)*2); @@ -30,17 +29,24 @@ void cylinderFunction(Canvas& can) { // testCylinder->setYaw(rotation*45); // testCylinder->setPitch(rotation*45); // testCylinder->setRoll(rotation*45); - // testCylinder->setSideLength(cos(rotation)+1.01); - // if(testCylinder->getSideLength() >= 2) { + // testCylinder->setHeight(sin(rotation)+1.01); + // testCylinder->setRadius(sin(rotation)+1.01); + if(testCylinder->getHeight() >= 2) { + delta = -0.05; + } + if(testCylinder->getHeight() <= 0.05) { + delta = 0.05; + } + testCylinder->changeHeightBy(delta); + rotation+=0.01; + // if(testCylinder->getRadius() >= 2) { // delta = -0.05; // } - // if(testCylinder->getSideLength() <= 0.05) { + // if(testCylinder->getRadius() <= 0.05) { // delta = 0.05; // } - // testCylinder->changeSideLengthBy(delta); - //testCylinder2->setRoll(rotation); + // testCylinder->changeRadiusBy(delta); // rotation+=0.01; - // printf("Roll %f\n", testCylinder2->getRoll()); } } diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp new file mode 100644 index 000000000..136f5e230 --- /dev/null +++ b/src/tests/testEllipsoid.cpp @@ -0,0 +1,80 @@ +/* + * testEllipsoid.cpp + * + * Usage: ./testEllipsoid + */ + +#include +#include + +using namespace tsgl; + +void ellipsoidFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 0.1, 0.1, 0.1, 0.0, 0.0, 0.0, colors); + // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); + can.add(testEllipsoid); + // can.add(testEllipsoid2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + // testEllipsoid->setXRadius(1.5); + // testEllipsoid->setYRadius(1.5); + // testEllipsoid->setZRadius(1.5); + // testEllipsoid->changeXRadiusBy(1.4); + // testEllipsoid->changeYRadiusBy(1.4); + // testEllipsoid->changeZRadiusBy(1.4); + while (can.isOpen()) { + can.sleep(); + // testEllipsoid->setCenterX(sin(rotation)); + // testEllipsoid->setCenterY(cos(rotation)); + // testEllipsoid->setCenterZ(sin(rotation)); + // testEllipsoid->setYaw(rotation*45); + // testEllipsoid->setPitch(rotation*45); + // testEllipsoid2->setPitch(rotation*45); + // testEllipsoid->setRoll(rotation*45); + // testEllipsoid->setXRadius(cos(rotation)+1.01); + // testEllipsoid2->setYRadius(sin(rotation)+2.01); + // testEllipsoid2->setZRadius(sin(rotation)+3.01); + // if(testEllipsoid->getXRadius() >= 2) { + // delta = -0.05; + // } + // if(testEllipsoid->getXRadius() <= 0.05) { + // delta = 0.05; + // } + // testEllipsoid->changeXRadiusBy(delta); + + // if(testEllipsoid->getYRadius() >= 5) { + // delta = -0.05; + // } + // if(testEllipsoid->getYRadius() <= 3) { + // delta = 0.05; + // } + // testEllipsoid->changeYRadiusBy(delta); + + // if(testEllipsoid->getZRadius() >= 3) { + // delta = -0.05; + // } + // if(testEllipsoid->getZRadius() <= 1) { + // delta = 0.05; + // } + // testEllipsoid->changeZRadiusBy(delta); + rotation+=0.01; + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid"); + c.setBackgroundColor(BLACK); + c.run(ellipsoidFunction); +} \ No newline at end of file diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp new file mode 100644 index 000000000..901679965 --- /dev/null +++ b/src/tests/testPrism.cpp @@ -0,0 +1,62 @@ +/* + * testPrism.cpp + * + * Usage: ./testPrism + */ + +#include +#include + +using namespace tsgl; + +void prismFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), + ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), + ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), + ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), + ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, colors); + Prism * testPrism2 = new Prism(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); + Prism * testPrism3 = new Prism(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); + can.add(testPrism); + can.add(testPrism2); + can.add(testPrism3); + float rotation = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testPrism->setCenterX(sin(rotation)*2); + // testPrism->setCenterY(cos(rotation)*2); + // testPrism->setCenterZ(sin(rotation)); + // testPrism->setYaw(rotation*45); + // testPrism->setPitch(rotation*45); + // testPrism->setRoll(rotation*45); + // testPrism->setHeight(sin(rotation)+1.01); + // testPrism->setRadius(sin(rotation)+1.01); + // if(testPrism->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testPrism->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testPrism->changeHeightBy(delta); + if(testPrism->getRadius() >= 2) { + delta = -0.05; + } + if(testPrism->getRadius() <= 0.05) { + delta = 0.05; + } + testPrism->changeRadiusBy(delta); + rotation+=0.01; + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Prism"); + c.setBackgroundColor(BLACK); + c.run(prismFunction); +} \ No newline at end of file diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp new file mode 100644 index 000000000..b317269ac --- /dev/null +++ b/src/tests/testSphere.cpp @@ -0,0 +1,53 @@ +/* + * testSphere.cpp + * + * Usage: ./testSphere + */ + +#include +#include + +using namespace tsgl; + +void sphereFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 1.5, 0.0, 0.0, 0.0, colors); + can.add(testSphere); + float rotation = 0.0f; + // GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testSphere->setCenterX(sin(rotation)); + // testSphere->setCenterY(cos(rotation)); + // testSphere->setCenterZ(sin(rotation)); + // testSphere->setYaw(rotation*45); + // testSphere->setPitch(rotation*45); + // testSphere->setRoll(rotation*45); + testSphere->setRadius(cos(rotation)+1.01); + // if(testSphere->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testSphere->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testSphere->changeRadiusBy(delta); + rotation+=0.01; + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Sphere"); + c.setBackgroundColor(BLACK); + c.run(sphereFunction); +} \ No newline at end of file From 70917d192c66428ae66ec18a78104e06acda2891 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 9 Apr 2020 02:58:32 -0400 Subject: [PATCH 013/105] Rotation around arbitrary point, mutators update --- Makefile | 1 + src/TSGL/Cube.cpp | 136 +++++++++++++++---------------- src/TSGL/Cuboid.cpp | 154 ++++++++++++++++------------------- src/TSGL/Drawable.cpp | 18 ++++ src/TSGL/Drawable.h | 4 + src/TSGL/Ellipsoid.cpp | 56 ++++--------- src/TSGL/Object3D.cpp | 94 +++++++++++++-------- src/TSGL/Object3D.h | 15 +++- src/TSGL/Prism.cpp | 101 ++++++++--------------- src/TSGL/Sphere.cpp | 28 +++---- src/tests/test3DRotation.cpp | 44 ++++++++++ src/tests/testCube.cpp | 19 +++-- src/tests/testCuboid.cpp | 18 ++-- src/tests/testCylinder.cpp | 23 +++--- src/tests/testEllipsoid.cpp | 24 +++--- src/tests/testPrism.cpp | 4 + src/tests/testSphere.cpp | 6 +- 17 files changed, 389 insertions(+), 356 deletions(-) create mode 100644 src/tests/test3DRotation.cpp diff --git a/Makefile b/Makefile index d0d174f14..4df245c6a 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,7 @@ DEPFLAGS=-MMD -MP BINARIES= \ bin/test_specs \ + bin/test3DRotation \ bin/testAlphaRectangle \ bin/testArrows \ bin/testAura \ diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index a742f8954..841aaf5df 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -24,39 +24,42 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch attribMutex.lock(); geometryType = GL_QUADS; mySideLength = sideLength; + myXScale = sideLength; + myYScale = sideLength; + myZScale = sideLength; numberOfVertices = 24; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, 0.5, -0.5, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); } /*! @@ -81,39 +84,42 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch attribMutex.lock(); geometryType = GL_QUADS; mySideLength = sideLength; + myXScale = sideLength; + myYScale = sideLength; + myZScale = sideLength; numberOfVertices = 24; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, 0.5, -0.5, c[3]); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); - - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[0]); - addVertex(-0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[3]); - addVertex(0.5*mySideLength, 0.5*mySideLength, -0.5*mySideLength, c[7]); - addVertex(0.5*mySideLength, -0.5*mySideLength, -0.5*mySideLength, c[4]); - - addVertex(-0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[1]); - addVertex(-0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[2]); - addVertex(0.5*mySideLength, 0.5*mySideLength, 0.5*mySideLength, c[6]); - addVertex(0.5*mySideLength, -0.5*mySideLength, 0.5*mySideLength, c[5]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, 0.5, c[5]); } /** @@ -126,13 +132,11 @@ void Cube::setSideLength(GLfloat length) { return; } attribMutex.lock(); - GLfloat ratio = length/mySideLength; + myXScale = length; + myYScale = length; + myZScale = length; mySideLength = length; - for(int i = 0; i < numberOfVertices * 3; i++) { - vertices[i] *= ratio; - } attribMutex.unlock(); - // FIXME alter vertices } /** @@ -146,14 +150,10 @@ void Cube::changeSideLengthBy(GLfloat delta) { } attribMutex.lock(); mySideLength += delta; - for(int i = 0; i < numberOfVertices * 3; i++) { - if (vertices[i] > 0) - vertices[i] += delta/2; - else - vertices[i] -= delta/2; - } + myXScale += delta; + myYScale += delta; + myZScale += delta; attribMutex.unlock(); - // FIXME alter vertices } GLfloat Cube::getSideLength() { diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 60ac4b916..2abacd2ac 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -28,39 +28,42 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myLength = length; myWidth = width; myHeight = height; + myXScale = width; + myYScale = height; + myZScale = length; numberOfVertices = 24; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, 0.5, -0.5, c); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); - - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); - - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c); - - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); + + addVertex(-0.5, -0.5, 0.5, c); + addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, 0.5, c); } /*! @@ -89,39 +92,42 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myLength = length; myWidth = width; myHeight = height; + myXScale = width; + myYScale = height; + myZScale = length; numberOfVertices = 24; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, 0.5, -0.5, c[3]); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); - - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); - - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); - - addVertex(-0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[0]); - addVertex(-0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[3]); - addVertex(0.5*myWidth, 0.5*myHeight, -0.5*myLength, c[7]); - addVertex(0.5*myWidth, -0.5*myHeight, -0.5*myLength, c[4]); - - addVertex(-0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[1]); - addVertex(-0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[2]); - addVertex(0.5*myWidth, 0.5*myHeight, 0.5*myLength, c[6]); - addVertex(0.5*myWidth, -0.5*myHeight, 0.5*myLength, c[5]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, 0.5, c[5]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, 0.5, -0.5, c[7]); + + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, -0.5, c[3]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); + + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, 0.5, c[5]); } /** @@ -134,11 +140,8 @@ void Cuboid::setLength(GLfloat length) { return; } attribMutex.lock(); - GLfloat ratio = length/myLength; myLength = length; - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*3 + 2] *= ratio; - } + myZScale = length; attribMutex.unlock(); } @@ -153,12 +156,7 @@ void Cuboid::changeLengthBy(GLfloat delta) { } attribMutex.lock(); myLength += delta; - for(int i = 0; i < numberOfVertices; i++) { - if (vertices[i*3 + 2] > 0) - vertices[i*3 + 2] += delta/2; - else - vertices[i*3 + 2] -= delta/2; - } + myZScale += delta; attribMutex.unlock(); } @@ -172,11 +170,8 @@ void Cuboid::setWidth(GLfloat width) { return; } attribMutex.lock(); - GLfloat ratio = width/myWidth; myWidth = width; - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*3] *= ratio; - } + myXScale = width; attribMutex.unlock(); } @@ -191,12 +186,7 @@ void Cuboid::changeWidthBy(GLfloat delta) { } attribMutex.lock(); myWidth += delta; - for(int i = 0; i < numberOfVertices; i++) { - if (vertices[i*3] > 0) - vertices[i*3] += delta/2; - else - vertices[i*3] -= delta/2; - } + myXScale += delta; attribMutex.unlock(); } @@ -210,11 +200,8 @@ void Cuboid::setHeight(GLfloat height) { return; } attribMutex.lock(); - GLfloat ratio = height/myHeight; myHeight = height; - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*3 + 1] *= ratio; - } + myYScale = height; attribMutex.unlock(); } @@ -229,12 +216,7 @@ void Cuboid::changeHeightBy(GLfloat delta) { } attribMutex.lock(); myHeight += delta; - for(int i = 0; i < numberOfVertices; i++) { - if (vertices[i*3 + 1] > 0) - vertices[i*3 + 1] += delta/2; - else - vertices[i*3 + 1] -= delta/2; - } + myYScale += delta; attribMutex.unlock(); } diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index 5f78d790d..ff9804839 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -57,4 +57,22 @@ void Drawable::setRotationPoint(float x, float y) { myRotationPointY = y; } +/*! + * \brief Virtual mutator that changes the rotation point of the Drawable's x value. + * \details Alters myRotationPointX; + * \param x myRotationPointX's new float value. + */ +void Drawable::setRotationPointX(float x) { + myRotationPointX = x; +} + +/*! + * \brief Virtual mutator that changes the rotation point of the Drawable's y value. + * \details Alters myRotationPointY; + * \param y myRotationPointY's new float value. + */ +void Drawable::setRotationPointY(float y) { + myRotationPointY = y; +} + } \ No newline at end of file diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 00506a463..b6a6c8010 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -68,6 +68,10 @@ namespace tsgl { virtual void setRotationPoint(float x, float y); + virtual void setRotationPointX(float x); + + virtual void setRotationPointY(float y); + /*! * \brief Accessor for the center x-coordinate of the Drawable. * \details Returns the value of the myCenterX private variable. diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 5503fb276..d43b5fc42 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -32,13 +32,16 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius myXRadius = xRadius; myYRadius = yRadius; myZRadius = zRadius; + myXScale = xRadius; + myYScale = yRadius; + myZScale = zRadius; attribMutex.unlock(); for(int b=0;b 0) - vertices[i*3 + 1] += delta/2; - else - vertices[i*3 + 1] -= delta/2; - } + myYScale += delta; attribMutex.unlock(); } @@ -161,12 +159,9 @@ void Prism::setRadius(GLfloat radius) { return; } attribMutex.lock(); - GLfloat ratio = radius/myRadius; myRadius = radius; - for (int i = 0; i < numberOfVertices; i++) { - vertices[i*3] *= ratio; - vertices[i*3 + 2] *= ratio; - } + myXScale = radius; + myZScale = radius; attribMutex.unlock(); } @@ -181,40 +176,8 @@ void Prism::changeRadiusBy(GLfloat delta) { } attribMutex.lock(); myRadius += delta; - for (int i = 0; i < mySides; i++) { - // 0, 2 - vertices[i*36 + 3] = myRadius * cos(TWOPI * i / mySides); - vertices[i*36 + 5] = myRadius * sin(TWOPI * i / mySides); - - vertices[i*36 + 6] = myRadius * cos(TWOPI * (i + 1) / mySides); - vertices[i*36 + 8] = myRadius * sin(TWOPI * (i + 1) / mySides); - - vertices[i*36 + 9] = myRadius * cos(TWOPI * i / mySides); - vertices[i*36 + 11] = myRadius * sin(TWOPI * i / mySides); - - vertices[i*36 + 12] = myRadius * cos(TWOPI * (i + 1) / mySides); - vertices[i*36 + 14] = myRadius * sin(TWOPI * (i + 1) / mySides); - - vertices[i*36 + 15] = myRadius * cos(TWOPI * i / mySides); - vertices[i*36 + 17] = myRadius * sin(TWOPI * i / mySides); - - vertices[i*36 + 18] = myRadius * cos(TWOPI * (i + 1) / mySides); - vertices[i*36 + 20] = myRadius * sin(TWOPI * (i + 1) / mySides); - - vertices[i*36 + 21] = myRadius * cos(TWOPI * i / mySides); - vertices[i*36 + 23] = myRadius * sin(TWOPI * i / mySides); - - vertices[i*36 + 24] = myRadius * cos(TWOPI * (i + 1) / mySides); - vertices[i*36 + 26] = myRadius * sin(TWOPI * (i + 1) / mySides); - - vertices[i*36 + 27] = myRadius * cos(TWOPI * i / mySides); - vertices[i*36 + 29] = myRadius * sin(TWOPI * i / mySides); - - vertices[i*36 + 30] = myRadius * cos(TWOPI * (i + 1) / mySides); - vertices[i*36 + 32] = myRadius * sin(TWOPI * (i + 1) / mySides); - - // 33, 35 - } + myXScale += delta; + myZScale += delta; attribMutex.unlock(); } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index ad0dde0a2..fc4a6b9b0 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -28,6 +28,9 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = radius; attribMutex.unlock(); for(int b=0;b +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; + Cube * testCube = new Cube(2.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); + testCube->setRotationPoint(0,0,0); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 90.0, colors); + Sphere * testSphere = new Sphere(4, 0, 0, 1, 0.0, 0.0, 0.0, colors); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + can.add(testCube); + can.add(testPrism); + can.add(testSphere); + float rotation = 0.0f; + // GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + testCube->setYaw(rotation); + testPrism->setYaw(-rotation); + // testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setPitch(rotation); + rotation += 1; + } + + delete testCube; + delete testPrism; + delete testSphere; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Rotation"); + c.setBackgroundColor(BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 9bddbc61e..a083501be 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -18,7 +18,7 @@ void cubeFunction(Canvas& can) { can.add(testCube); can.add(testCube2); float rotation = 0.0f; - // GLfloat delta = 0.05; + GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); // testCube->setCenterX(sin(rotation)*2); @@ -28,17 +28,20 @@ void cubeFunction(Canvas& can) { // testCube->setPitch(rotation*45); // testCube->setRoll(rotation*45); // testCube->setSideLength(cos(rotation)+1.01); - // if(testCube->getSideLength() >= 2) { - // delta = -0.05; - // } - // if(testCube->getSideLength() <= 0.05) { - // delta = 0.05; - // } - // testCube->changeSideLengthBy(delta); + if(testCube->getSideLength() >= 2) { + delta = -0.05; + } + if(testCube->getSideLength() <= 0.05) { + delta = 0.05; + } + testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); rotation+=0.01; // printf("Roll %f\n", testCube2->getRoll()); } + + delete testCube; + delete testCube2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index 59a479142..61bb6f2d3 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -46,15 +46,17 @@ void cuboidFunction(Canvas& can) { // } // testCuboid->changeHeightBy(delta); - // if(testCuboid->getLength() >= 3) { - // delta = -0.05; - // } - // if(testCuboid->getLength() <= 1) { - // delta = 0.05; - // } - // testCuboid->changeLengthBy(delta); - // rotation+=0.01; + if(testCuboid->getLength() >= 3) { + delta = -0.05; + } + if(testCuboid->getLength() <= 1) { + delta = 0.05; + } + testCuboid->changeLengthBy(delta); + rotation+=0.01; } + + delete testCuboid; } int main(int argc, char* argv[]) { diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index 557daaecd..f842021ab 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -31,23 +31,24 @@ void cylinderFunction(Canvas& can) { // testCylinder->setRoll(rotation*45); // testCylinder->setHeight(sin(rotation)+1.01); // testCylinder->setRadius(sin(rotation)+1.01); - if(testCylinder->getHeight() >= 2) { + // if(testCylinder->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeHeightBy(delta); + if(testCylinder->getRadius() >= 2) { delta = -0.05; } - if(testCylinder->getHeight() <= 0.05) { + if(testCylinder->getRadius() <= 0.05) { delta = 0.05; } - testCylinder->changeHeightBy(delta); + testCylinder->changeRadiusBy(delta); rotation+=0.01; - // if(testCylinder->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeRadiusBy(delta); - // rotation+=0.01; } + + delete testCylinder; } int main(int argc, char* argv[]) { diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 136f5e230..3ec3fbb68 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -18,12 +18,12 @@ void ellipsoidFunction(Canvas& can) { ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 0.1, 0.1, 0.1, 0.0, 0.0, 0.0, colors); + Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); can.add(testEllipsoid); // can.add(testEllipsoid2); float rotation = 0.0f; - // GLfloat delta = 0.05; + GLfloat delta = 0.05; // testEllipsoid->setXRadius(1.5); // testEllipsoid->setYRadius(1.5); // testEllipsoid->setZRadius(1.5); @@ -40,8 +40,8 @@ void ellipsoidFunction(Canvas& can) { // testEllipsoid2->setPitch(rotation*45); // testEllipsoid->setRoll(rotation*45); // testEllipsoid->setXRadius(cos(rotation)+1.01); - // testEllipsoid2->setYRadius(sin(rotation)+2.01); - // testEllipsoid2->setZRadius(sin(rotation)+3.01); + // testEllipsoid->setYRadius(sin(rotation)+2.01); + // testEllipsoid->setZRadius(sin(rotation)+3.01); // if(testEllipsoid->getXRadius() >= 2) { // delta = -0.05; // } @@ -58,15 +58,17 @@ void ellipsoidFunction(Canvas& can) { // } // testEllipsoid->changeYRadiusBy(delta); - // if(testEllipsoid->getZRadius() >= 3) { - // delta = -0.05; - // } - // if(testEllipsoid->getZRadius() <= 1) { - // delta = 0.05; - // } - // testEllipsoid->changeZRadiusBy(delta); + if(testEllipsoid->getZRadius() >= 3) { + delta = -0.05; + } + if(testEllipsoid->getZRadius() <= 1) { + delta = 0.05; + } + testEllipsoid->changeZRadiusBy(delta); rotation+=0.01; } + + delete testEllipsoid; } int main(int argc, char* argv[]) { diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index 901679965..df5506db9 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -49,6 +49,10 @@ void prismFunction(Canvas& can) { testPrism->changeRadiusBy(delta); rotation+=0.01; } + + delete testPrism; + delete testPrism2; + delete testPrism3; } int main(int argc, char* argv[]) { diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index b317269ac..e5830e147 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -21,7 +21,7 @@ void sphereFunction(Canvas& can) { Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 1.5, 0.0, 0.0, 0.0, colors); can.add(testSphere); float rotation = 0.0f; - // GLfloat delta = 0.05; + GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); // testSphere->setCenterX(sin(rotation)); @@ -30,7 +30,7 @@ void sphereFunction(Canvas& can) { // testSphere->setYaw(rotation*45); // testSphere->setPitch(rotation*45); // testSphere->setRoll(rotation*45); - testSphere->setRadius(cos(rotation)+1.01); + // testSphere->setRadius(cos(rotation)+1.01); // if(testSphere->getRadius() >= 2) { // delta = -0.05; // } @@ -40,6 +40,8 @@ void sphereFunction(Canvas& can) { // testSphere->changeRadiusBy(delta); rotation+=0.01; } + + delete testSphere; } int main(int argc, char* argv[]) { From c0fe67317e44c13e11faee4025442d0d17f0d5af Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 9 Apr 2020 13:56:04 -0400 Subject: [PATCH 014/105] Forgot Cone and Pyramid. Now added. --- Makefile | 2 + src/TSGL/Canvas.h | 2 + src/TSGL/Cone.cpp | 8 +-- src/TSGL/Cone.h | 4 +- src/TSGL/Pyramid.cpp | 110 ++++++++++++++++++++++++++------------ src/TSGL/Pyramid.h | 19 ++++--- src/tests/testCone.cpp | 62 +++++++++++++++++++++ src/tests/testPyramid.cpp | 62 +++++++++++++++++++++ 8 files changed, 221 insertions(+), 48 deletions(-) create mode 100644 src/tests/testCone.cpp create mode 100644 src/tests/testPyramid.cpp diff --git a/Makefile b/Makefile index 4df245c6a..e552e1bff 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ BINARIES= \ bin/testColorPoints \ bin/testColorWheel \ bin/testConcavePolygon \ + bin/testCone \ bin/testConstructors \ bin/testConway \ bin/testCosineIntegral \ @@ -107,6 +108,7 @@ BINARIES= \ bin/testPrism \ bin/testProgressBar \ bin/testProjectiles \ + bin/testPyramid \ bin/testReaderWriter \ bin/testRotation \ bin/testScreenshot \ diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index a33a506b4..827349979 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -13,6 +13,7 @@ #include "Array.h" // Our own array for buffering drawing operations #include "Arrow.h" // Our own array for drawing arrows #include "Color.h" // Our own interface for converting color types +#include "Cone.h" // Our own class for drawing cones #include "Cube.h" // Our own class for drawing cubes #include "Cuboid.h" // Our own class for drawing cuboids #include "Cylinder.h" // Our own class for drawing cylinders @@ -27,6 +28,7 @@ #include "Line.h" // Our own class for drawing straight lines #include "Polyline.h" // Our own class for drawing polylines #include "ProgressBar.h" // Our own class for drawing progress bars +#include "Pyramid.h" // Our own class for drawing pyramids #include "Rectangle.h" // Our own class for drawing rectangles #include "RegularPolygon.h" // Our own class for drawing regular polygons #include "Sphere.h" // Our own class for drawing spheres diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 28dc99280..885d18600 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -17,8 +17,8 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Cone with a buffer for storing the specified numbered of vertices. */ -Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Pyramid(x, y, z, height, radius, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll, c) { } +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c) +: Pyramid(x, y, z, 12, height, radius, yaw, pitch, roll, c) { } /*! * \brief Explicitly constructs a new Cone. @@ -35,8 +35,8 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Cone with a buffer for storing the specified numbered of vertices. */ -Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Pyramid(x, y, z, height, radius, (radius > 1) ? radius * 3 : 3, yaw, pitch, roll, c) { } +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) +: Pyramid(x, y, z, 12, height, radius, yaw, pitch, roll, c) { } /*! * \brief Destructor for the Cone. diff --git a/src/TSGL/Cone.h b/src/TSGL/Cone.h index 41bc3410a..2f2f77fd6 100644 --- a/src/TSGL/Cone.h +++ b/src/TSGL/Cone.h @@ -17,9 +17,9 @@ namespace tsgl { */ class Cone : public Pyramid { public: - Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c); - Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]); virtual ~Cone(); }; diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index c893a5a86..9da5912e5 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -19,17 +19,35 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c) : Object3D(x, y, z, yaw, pitch, roll) { - attribMutex.lock(); +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } if (radius <= 0 || height <= 0) { TsglDebug("Cannot have a Pyramid with radius or height less than or equal to 0."); } + attribMutex.lock(); myHeight = height; + myYScale = height; myRadius = radius; + myXScale = radius; + myZScale = radius; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 6; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); + GLfloat half = myHeight/2; + for (int i = 0; i < mySides; i++) { + addVertex(0,half,0, c); + addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c); + + addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c); + addVertex(0,-half,0, c); + } } /*! @@ -49,47 +67,65 @@ Pyramid::Pyramid(float x, float y, float z, float height, float radius, int side * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { - attribMutex.lock(); +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } - if (radius <= 0) { - TsglDebug("Cannot have a Pyramid with radius less than or equal to 0."); + if (radius <= 0 || height <= 0) { + TsglDebug("Cannot have a Pyramid with radius or height less than or equal to 0."); } + attribMutex.lock(); myHeight = height; + myYScale = height; myRadius = radius; + myXScale = radius; + myZScale = radius; + mySides = sides; + geometryType = GL_TRIANGLES; + numberOfVertices = mySides * 6; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); + GLfloat half = myHeight/2; + for (int i = 0; i < mySides; i++) { + addVertex(0,half,0, c[0]); + addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c[i]); + addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c[i+1]); + + addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c[i]); + addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c[i+1]); + addVertex(0,-half,0, c[mySides+1]); + } } /** * \brief Sets the Pyramid to a new color. * \param c The new ColorFloat. */ -void Pyramid::setColor(ColorFloat c) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; - } - attribMutex.unlock(); +void Pyramid::setColor(ColorGLfloat c) { + // attribMutex.lock(); + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6 + 2] = c.R; + // vertices[i*6 + 3] = c.G; + // vertices[i*6 + 4] = c.B; + // vertices[i*6 + 5] = c.A; + // } + // attribMutex.unlock(); } /** * \brief Sets the Pyramid to an array of new colors. * \param c An array of new ColorFloats. */ -void Pyramid::setColor(ColorFloat c[]) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; - } - attribMutex.unlock(); +void Pyramid::setColor(ColorGLfloat c[]) { + // attribMutex.lock(); + // for(int i = 0; i < numberOfVertices; i++) { + // vertices[i*6 + 2] = c[i].R; + // vertices[i*6 + 3] = c[i].G; + // vertices[i*6 + 4] = c[i].B; + // vertices[i*6 + 5] = c[i].A; + // } + // attribMutex.unlock(); } /** @@ -97,13 +133,13 @@ void Pyramid::setColor(ColorFloat c[]) { * \return c An array of ColorFloats. * \warning This method allocates memory. The caller is responsible for deallocating it. */ -ColorFloat* Pyramid::getColor() { - ColorFloat * c = new ColorFloat[numberOfVertices]; - for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); - } - return c; -} +// ColorFloat* Pyramid::getColor() { +// ColorFloat * c = new ColorFloat[numberOfVertices]; +// for(int i = 0; i < numberOfVertices; i++) { +// c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); +// } +// return c; +// } /** * \brief Mutates the Pyramid's base's radius. @@ -117,6 +153,8 @@ void Pyramid::setRadius(float radius) { return; } myRadius = radius; + myXScale = radius; + myZScale = radius; attribMutex.unlock(); } @@ -132,6 +170,8 @@ void Pyramid::changeRadiusBy(float delta) { return; } myRadius += delta; + myXScale += delta; + myZScale += delta; attribMutex.unlock(); } @@ -140,13 +180,13 @@ void Pyramid::changeRadiusBy(float delta) { * \param height The Pyramid's new height. */ void Pyramid::setHeight(float height) { - attribMutex.lock(); if (height <= 0) { TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); myHeight = height; + myYScale = height; attribMutex.unlock(); } @@ -155,13 +195,13 @@ void Pyramid::setHeight(float height) { * \param delta The amount by which to change the height of the pyramid. */ void Pyramid::changeHeightBy(float delta) { - attribMutex.lock(); if (myHeight + delta <= 0) { TsglDebug("Cannot have a Pyramid with height less than or equal to 0."); - attribMutex.unlock(); return; } + attribMutex.lock(); myHeight += delta; + myYScale += delta; attribMutex.unlock(); } diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h index 46bb21ab6..6ed18d7d6 100644 --- a/src/TSGL/Pyramid.h +++ b/src/TSGL/Pyramid.h @@ -16,18 +16,19 @@ namespace tsgl { */ class Pyramid : public Object3D { protected: - float myHeight; - float myRadius; + GLfloat myHeight; + GLfloat myRadius; + int mySides; public: - Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c); + Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c); - Pyramid(float x, float y, float z, float height, float radius, int sides, float yaw, float pitch, float roll, ColorFloat c[]); + Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]); virtual ~Pyramid(); - virtual void setColor(ColorFloat c); + virtual void setColor(ColorGLfloat c); - virtual void setColor(ColorFloat c[]); + virtual void setColor(ColorGLfloat c[]); virtual void setRadius(float radius); @@ -37,7 +38,11 @@ class Pyramid : public Object3D { virtual void changeHeightBy(float delta); - virtual ColorFloat* getColor(); + virtual GLfloat getHeight() { return myHeight; } + + virtual GLfloat getRadius() { return myRadius; } + + // virtual ColorFloat* getColor(); }; } diff --git a/src/tests/testCone.cpp b/src/tests/testCone.cpp new file mode 100644 index 000000000..4f9f99969 --- /dev/null +++ b/src/tests/testCone.cpp @@ -0,0 +1,62 @@ +/* + * testCone.cpp + * + * Usage: ./testCone + */ + +#include +#include + +using namespace tsgl; + +void coneFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), + ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), + ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), + ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), + ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; + Cone * testCone = new Cone(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 0.0, colors); + // Cone * testCone2 = new Cone(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + can.add(testCone); + // can.add(testCone2); + float rotation = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testCone->setCenterX(sin(rotation)*2); + // testCone->setCenterY(cos(rotation)*2); + // testCone->setCenterZ(sin(rotation)); + // testCone->setYaw(rotation*45); + // testCone->setPitch(rotation*45); + // testCone->setRoll(rota tion*45); + // testCone->setHeight(sin(rotation)+1.01); + // testCone->setRadius(sin(rotation)+1.01); + // if(testCone->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCone->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeHeightBy(delta); + if(testCone->getRadius() >= 2) { + delta = -0.05; + } + if(testCone->getRadius() <= 0.05) { + delta = 0.05; + } + testCone->changeRadiusBy(delta); + rotation+=0.01; + } + + delete testCone; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cone"); + c.setBackgroundColor(BLACK); + c.run(coneFunction); +} \ No newline at end of file diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp new file mode 100644 index 000000000..6ed5fe25b --- /dev/null +++ b/src/tests/testPyramid.cpp @@ -0,0 +1,62 @@ +/* + * testPyramid.cpp + * + * Usage: ./testPyramid + */ + +#include +#include + +using namespace tsgl; + +void pyramidFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), + ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), + ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), + ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), + ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid2 = new Pyramid(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); + can.add(testPyramid); + can.add(testPyramid2); + can.add(testPyramid3); + float rotation = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // testPyramid->setCenterX(sin(rotation)*2); + // testPyramid->setCenterY(cos(rotation)*2); + // testPyramid->setCenterZ(sin(rotation)); + // testPyramid->setYaw(rotation*45); + // testPyramid->setPitch(rotation*45); + // testPyramid->setRoll(rotation*45); + // testPyramid->setHeight(sin(rotation)+1.01); + // testPyramid->setRadius(sin(rotation)+1.01); + // if(testPyramid->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testPyramid->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testPyramid->changeHeightBy(delta); + // if(testPyramid->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testPyramid->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testPyramid->changeRadiusBy(delta); + rotation+=0.01; + } + + delete testPyramid; + delete testPyramid2; + delete testPyramid3; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Basic Pyramid"); + c.setBackgroundColor(BLACK); + c.run(pyramidFunction); +} \ No newline at end of file From d106b230f8f1a33f4367a70ce77e55e37e5831da Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 15 Apr 2020 01:30:10 -0400 Subject: [PATCH 015/105] Coloring changes; edges and edgeless objects fix --- src/TSGL/Cone.cpp | 14 +++++++++-- src/TSGL/Cube.cpp | 14 ++++++----- src/TSGL/Cuboid.cpp | 14 ++++++----- src/TSGL/Cylinder.cpp | 14 +++++++++-- src/TSGL/Ellipsoid.cpp | 16 +++++++----- src/TSGL/Object3D.cpp | 49 ++++++++++++++++++++++++++++++++++++- src/TSGL/Object3D.h | 28 ++++++++++++--------- src/TSGL/Prism.cpp | 24 ++++++++++++------ src/TSGL/Pyramid.cpp | 16 +++++++++--- src/TSGL/Sphere.cpp | 22 ++++++++++------- src/tests/testCone.cpp | 23 +++++++++-------- src/tests/testCube.cpp | 18 +++++++------- src/tests/testCuboid.cpp | 18 +++++++------- src/tests/testCylinder.cpp | 18 +++++++------- src/tests/testEllipsoid.cpp | 18 +++++++------- src/tests/testPrism.cpp | 18 +++++++------- src/tests/testPyramid.cpp | 6 +++-- src/tests/testSphere.cpp | 4 +-- 18 files changed, 220 insertions(+), 114 deletions(-) diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 885d18600..85844f325 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -18,7 +18,12 @@ namespace tsgl { * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c) -: Pyramid(x, y, z, 12, height, radius, yaw, pitch, roll, c) { } +: Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { + outlineStride = 6; + numberOfOutlineVertices = mySides; + outlineFirstIndex = 0; + outlineGeometryType = GL_LINE_LOOP; +} /*! * \brief Explicitly constructs a new Cone. @@ -36,7 +41,12 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Pyramid(x, y, z, 12, height, radius, yaw, pitch, roll, c) { } +: Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { + outlineStride = 6; + numberOfOutlineVertices = mySides; + outlineFirstIndex = 0; + outlineGeometryType = GL_LINE_LOOP; +} /*! * \brief Destructor for the Cone. diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 841aaf5df..b65c194b5 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -27,7 +27,8 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = 24; + numberOfVertices = numberOfOutlineVertices = 24; + outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); @@ -41,15 +42,15 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); - addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); - addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); @@ -87,7 +88,8 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = 24; + numberOfVertices = numberOfOutlineVertices = 24; + outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); @@ -101,15 +103,15 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, -0.5, 0.5, c[5]); - addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); - addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, 0.5, -0.5, c[3]); diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 2abacd2ac..ff7bd8135 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -31,7 +31,8 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = 24; + numberOfVertices = numberOfOutlineVertices = 24; + outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); @@ -45,15 +46,15 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); + addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); - addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); - addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); @@ -95,7 +96,8 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = 24; + numberOfVertices = numberOfOutlineVertices = 24; + outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); @@ -109,15 +111,15 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, -0.5, 0.5, c[5]); - addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); - addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, 0.5, -0.5, c[3]); diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index c2a3e3f21..9893c2dbc 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -18,7 +18,12 @@ namespace tsgl { * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) -: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { } +: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { + outlineStride = 3; + numberOfOutlineVertices = mySides * 4; + outlineFirstIndex = 0; + outlineGeometryType = GL_LINES; +} /*! * \brief Explicitly constructs a new Cylinder. @@ -36,7 +41,12 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { } +: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { + outlineStride = 3; + numberOfOutlineVertices = mySides * 4; + outlineFirstIndex = 0; + outlineGeometryType = GL_LINES; +} /*! * \brief Destructor for the Cylinder. diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index d43b5fc42..7db006525 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -26,7 +26,8 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius geometryType = GL_TRIANGLE_STRIP; verticalSections = 36; horizontalSections = 20; - numberOfVertices = verticalSections*horizontalSections*2; + numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; + edgesOutlined = false; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; myXRadius = xRadius; @@ -36,14 +37,15 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius myYScale = yRadius; myZScale = zRadius; attribMutex.unlock(); - for(int b=0;bsetCenterZ(sin(rotation)); // testCone->setYaw(rotation*45); // testCone->setPitch(rotation*45); - // testCone->setRoll(rota tion*45); + testCone->setRoll(rotation*45); // testCone->setHeight(sin(rotation)+1.01); // testCone->setRadius(sin(rotation)+1.01); // if(testCone->getHeight() >= 2) { @@ -38,13 +41,13 @@ void coneFunction(Canvas& can) { // delta = 0.05; // } // testCone->changeHeightBy(delta); - if(testCone->getRadius() >= 2) { - delta = -0.05; - } - if(testCone->getRadius() <= 0.05) { - delta = 0.05; - } - testCone->changeRadiusBy(delta); + // if(testCone->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCone->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeRadiusBy(delta); rotation+=0.01; } diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index a083501be..90940a020 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -13,7 +13,7 @@ void cubeFunction(Canvas& can) { ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, ColorGLfloat(1,0,0,1)); Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCube); can.add(testCube2); @@ -25,16 +25,16 @@ void cubeFunction(Canvas& can) { // testCube->setCenterY(cos(rotation)*2); // testCube->setCenterZ(sin(rotation)); // testCube->setYaw(rotation*45); - // testCube->setPitch(rotation*45); + testCube->setPitch(rotation*45); // testCube->setRoll(rotation*45); // testCube->setSideLength(cos(rotation)+1.01); - if(testCube->getSideLength() >= 2) { - delta = -0.05; - } - if(testCube->getSideLength() <= 0.05) { - delta = 0.05; - } - testCube->changeSideLengthBy(delta); + // if(testCube->getSideLength() >= 2) { + // delta = -0.05; + // } + // if(testCube->getSideLength() <= 0.05) { + // delta = 0.05; + // } + // testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); rotation+=0.01; // printf("Roll %f\n", testCube2->getRoll()); diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index 61bb6f2d3..8fbb1336c 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -13,7 +13,7 @@ void cuboidFunction(Canvas& can) { ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, colors); + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, ColorGLfloat(1,0,0,1)); // Cuboid * testCuboid2 = new Cuboid(-3.0, 0.0, 0.0, 1, 3, 2, 0.0, 0.0, 0.0, colors); can.add(testCuboid); // can.add(testCuboid2); @@ -25,7 +25,7 @@ void cuboidFunction(Canvas& can) { // testCuboid->setCenterY(cos(rotation)*2); // testCuboid->setCenterZ(sin(rotation)); // testCuboid->setYaw(rotation*45); - // testCuboid->setPitch(rotation*45); + testCuboid->setPitch(rotation*45); // testCuboid->setRoll(rotation*45); // testCuboid->setWidth(cos(rotation)+1.01); // testCuboid->setHeight(cos(rotation)+3.01); @@ -46,13 +46,13 @@ void cuboidFunction(Canvas& can) { // } // testCuboid->changeHeightBy(delta); - if(testCuboid->getLength() >= 3) { - delta = -0.05; - } - if(testCuboid->getLength() <= 1) { - delta = 0.05; - } - testCuboid->changeLengthBy(delta); + // if(testCuboid->getLength() >= 3) { + // delta = -0.05; + // } + // if(testCuboid->getLength() <= 1) { + // delta = 0.05; + // } + // testCuboid->changeLengthBy(delta); rotation+=0.01; } diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index f842021ab..5bdf6ba52 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -15,7 +15,7 @@ void cylinderFunction(Canvas& can) { ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 45.0, colors); + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); // Cylinder * testCylinder2 = new Cylinder(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCylinder); // can.add(testCylinder2); @@ -27,7 +27,7 @@ void cylinderFunction(Canvas& can) { // testCylinder->setCenterY(cos(rotation)*2); // testCylinder->setCenterZ(sin(rotation)); // testCylinder->setYaw(rotation*45); - // testCylinder->setPitch(rotation*45); + testCylinder->setPitch(rotation*45); // testCylinder->setRoll(rotation*45); // testCylinder->setHeight(sin(rotation)+1.01); // testCylinder->setRadius(sin(rotation)+1.01); @@ -38,13 +38,13 @@ void cylinderFunction(Canvas& can) { // delta = 0.05; // } // testCylinder->changeHeightBy(delta); - if(testCylinder->getRadius() >= 2) { - delta = -0.05; - } - if(testCylinder->getRadius() <= 0.05) { - delta = 0.05; - } - testCylinder->changeRadiusBy(delta); + // if(testCylinder->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeRadiusBy(delta); rotation+=0.01; } diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 3ec3fbb68..a3ad4960b 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -18,7 +18,7 @@ void ellipsoidFunction(Canvas& can) { ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); + Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 2, 2, 2, 0.0, 0.0, 0.0, colors/* ColorGLfloat(1,0,0,1) */); // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); can.add(testEllipsoid); // can.add(testEllipsoid2); @@ -38,7 +38,7 @@ void ellipsoidFunction(Canvas& can) { // testEllipsoid->setYaw(rotation*45); // testEllipsoid->setPitch(rotation*45); // testEllipsoid2->setPitch(rotation*45); - // testEllipsoid->setRoll(rotation*45); + testEllipsoid->setRoll(rotation*45); // testEllipsoid->setXRadius(cos(rotation)+1.01); // testEllipsoid->setYRadius(sin(rotation)+2.01); // testEllipsoid->setZRadius(sin(rotation)+3.01); @@ -58,13 +58,13 @@ void ellipsoidFunction(Canvas& can) { // } // testEllipsoid->changeYRadiusBy(delta); - if(testEllipsoid->getZRadius() >= 3) { - delta = -0.05; - } - if(testEllipsoid->getZRadius() <= 1) { - delta = 0.05; - } - testEllipsoid->changeZRadiusBy(delta); + // if(testEllipsoid->getZRadius() >= 3) { + // delta = -0.05; + // } + // if(testEllipsoid->getZRadius() <= 1) { + // delta = 0.05; + // } + // testEllipsoid->changeZRadiusBy(delta); rotation+=0.01; } diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index df5506db9..6bd9ac8eb 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -15,7 +15,7 @@ void prismFunction(Canvas& can) { ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, colors); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); Prism * testPrism2 = new Prism(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); Prism * testPrism3 = new Prism(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); can.add(testPrism); @@ -29,7 +29,7 @@ void prismFunction(Canvas& can) { // testPrism->setCenterY(cos(rotation)*2); // testPrism->setCenterZ(sin(rotation)); // testPrism->setYaw(rotation*45); - // testPrism->setPitch(rotation*45); + testPrism->setPitch(rotation*45); // testPrism->setRoll(rotation*45); // testPrism->setHeight(sin(rotation)+1.01); // testPrism->setRadius(sin(rotation)+1.01); @@ -40,13 +40,13 @@ void prismFunction(Canvas& can) { // delta = 0.05; // } // testPrism->changeHeightBy(delta); - if(testPrism->getRadius() >= 2) { - delta = -0.05; - } - if(testPrism->getRadius() <= 0.05) { - delta = 0.05; - } - testPrism->changeRadiusBy(delta); + // if(testPrism->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testPrism->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testPrism->changeRadiusBy(delta); rotation+=0.01; } diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 6ed5fe25b..644d86efb 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -15,7 +15,7 @@ void pyramidFunction(Canvas& can) { ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); Pyramid * testPyramid2 = new Pyramid(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); Pyramid * testPyramid3 = new Pyramid(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); can.add(testPyramid); @@ -29,7 +29,9 @@ void pyramidFunction(Canvas& can) { // testPyramid->setCenterY(cos(rotation)*2); // testPyramid->setCenterZ(sin(rotation)); // testPyramid->setYaw(rotation*45); - // testPyramid->setPitch(rotation*45); + testPyramid->setPitch(rotation*45); + testPyramid2->setPitch(rotation*45); + testPyramid3->setPitch(rotation*45); // testPyramid->setRoll(rotation*45); // testPyramid->setHeight(sin(rotation)+1.01); // testPyramid->setRadius(sin(rotation)+1.01); diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index e5830e147..30d9b291c 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -18,7 +18,7 @@ void sphereFunction(Canvas& can) { ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 1.5, 0.0, 0.0, 0.0, colors); + Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors /* ColorGLfloat(1,0.1,0.5,1) */); can.add(testSphere); float rotation = 0.0f; GLfloat delta = 0.05; @@ -29,7 +29,7 @@ void sphereFunction(Canvas& can) { // testSphere->setCenterZ(sin(rotation)); // testSphere->setYaw(rotation*45); // testSphere->setPitch(rotation*45); - // testSphere->setRoll(rotation*45); + testSphere->setRoll(rotation*45); // testSphere->setRadius(cos(rotation)+1.01); // if(testSphere->getRadius() >= 2) { // delta = -0.05; From 72585d649ea0a06b27f4e042de78a8a7b82653f7 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 16 Apr 2020 01:46:43 -0400 Subject: [PATCH 016/105] Added color and edge color change capabilities --- src/TSGL/Cube.cpp | 49 +++++++++++++- src/TSGL/Cube.h | 10 ++- src/TSGL/Cuboid.cpp | 49 ++++++++++++++ src/TSGL/Cuboid.h | 16 +++++ src/TSGL/Ellipsoid.cpp | 102 ++++++++++++++++------------ src/TSGL/Ellipsoid.h | 8 +-- src/TSGL/Object3D.cpp | 24 +++---- src/TSGL/Object3D.h | 14 +++- src/TSGL/Prism.cpp | 54 +++++++++++---- src/TSGL/Prism.h | 12 +++- src/TSGL/Pyramid.cpp | 130 ++++++++++++++++++++---------------- src/TSGL/Pyramid.h | 16 +++-- src/TSGL/Sphere.cpp | 100 +++++++++++++++------------ src/TSGL/Sphere.h | 8 +-- src/tests/testCone.cpp | 15 ++++- src/tests/testCube.cpp | 11 ++- src/tests/testCuboid.cpp | 10 +++ src/tests/testCylinder.cpp | 17 ++++- src/tests/testEllipsoid.cpp | 21 +++++- src/tests/testPrism.cpp | 14 ++++ src/tests/testPyramid.cpp | 10 +++ src/tests/testSphere.cpp | 21 +++++- 22 files changed, 511 insertions(+), 200 deletions(-) diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index b65c194b5..26241e560 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -158,8 +158,53 @@ void Cube::changeSideLengthBy(GLfloat delta) { attribMutex.unlock(); } -GLfloat Cube::getSideLength() { - return mySideLength; +/** + * \brief Sets the Cube to an array of new colors. + * \param c An array of new ColorGLfloats. + * \details The array should have 8 ColorGLfloats minimum, one for each corner. + */ +void Cube::setColor(ColorGLfloat c[]) { + attribMutex.lock(); + colors[0] = colors[36] = colors[64] = c[0].R; + colors[1] = colors[37] = colors[65] = c[0].G; + colors[2] = colors[38] = colors[66] = c[0].B; + colors[3] = colors[39] = colors[67] = c[0].A; + + colors[4] = colors[40] = colors[80] = c[1].R; + colors[5] = colors[41] = colors[81] = c[1].G; + colors[6] = colors[42] = colors[82] = c[1].B; + colors[7] = colors[43] = colors[83] = c[1].A; + + colors[8] = colors[56] = colors[84] = c[2].R; + colors[9] = colors[57] = colors[85] = c[2].G; + colors[10] = colors[58] = colors[86] = c[2].B; + colors[11] = colors[59] = colors[87] = c[2].A; + + colors[12] = colors[52] = colors[68] = c[3].R; + colors[13] = colors[53] = colors[69] = c[3].G; + colors[14] = colors[54] = colors[70] = c[3].B; + colors[15] = colors[55] = colors[71] = c[3].A; + + colors[16] = colors[32] = colors[76] = c[4].R; + colors[17] = colors[33] = colors[77] = c[4].G; + colors[18] = colors[34] = colors[78] = c[4].B; + colors[19] = colors[35] = colors[79] = c[4].A; + + colors[20] = colors[44] = colors[92] = c[5].R; + colors[21] = colors[45] = colors[93] = c[5].G; + colors[22] = colors[46] = colors[94] = c[5].B; + colors[23] = colors[47] = colors[95] = c[5].A; + + colors[24] = colors[60] = colors[88] = c[6].R; + colors[25] = colors[61] = colors[89] = c[6].G; + colors[26] = colors[62] = colors[90] = c[6].B; + colors[27] = colors[63] = colors[91] = c[6].A; + + colors[28] = colors[48] = colors[72] = c[7].R; + colors[29] = colors[49] = colors[73] = c[7].G; + colors[30] = colors[50] = colors[74] = c[7].B; + colors[31] = colors[51] = colors[75] = c[7].A; + attribMutex.unlock(); } /*! diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index a16df6779..43eee421e 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -27,7 +27,15 @@ class Cube : public Object3D { virtual void changeSideLengthBy(float delta); - virtual GLfloat getSideLength(); + /*! + * \brief Accessor for the radius of the Prism. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + virtual GLfloat getSideLength() { return mySideLength; } + + virtual void setColor(ColorGLfloat c) { Object3D::setColor(c); } + + virtual void setColor(ColorGLfloat c[]); virtual ~Cube(); }; diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index ff7bd8135..e8a06e1d9 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -222,6 +222,55 @@ void Cuboid::changeHeightBy(GLfloat delta) { attribMutex.unlock(); } +/** + * \brief Sets the Cuboid to an array of new colors. + * \param c An array of new ColorGLfloats. + * \details The array should have 8 ColorGLfloats minimum, one for each corner. + */ +void Cuboid::setColor(ColorGLfloat c[]) { + attribMutex.lock(); + colors[0] = colors[36] = colors[64] = c[0].R; + colors[1] = colors[37] = colors[65] = c[0].G; + colors[2] = colors[38] = colors[66] = c[0].B; + colors[3] = colors[39] = colors[67] = c[0].A; + + colors[4] = colors[40] = colors[80] = c[1].R; + colors[5] = colors[41] = colors[81] = c[1].G; + colors[6] = colors[42] = colors[82] = c[1].B; + colors[7] = colors[43] = colors[83] = c[1].A; + + colors[8] = colors[56] = colors[84] = c[2].R; + colors[9] = colors[57] = colors[85] = c[2].G; + colors[10] = colors[58] = colors[86] = c[2].B; + colors[11] = colors[59] = colors[87] = c[2].A; + + colors[12] = colors[52] = colors[68] = c[3].R; + colors[13] = colors[53] = colors[69] = c[3].G; + colors[14] = colors[54] = colors[70] = c[3].B; + colors[15] = colors[55] = colors[71] = c[3].A; + + colors[16] = colors[32] = colors[76] = c[4].R; + colors[17] = colors[33] = colors[77] = c[4].G; + colors[18] = colors[34] = colors[78] = c[4].B; + colors[19] = colors[35] = colors[79] = c[4].A; + + colors[20] = colors[44] = colors[92] = c[5].R; + colors[21] = colors[45] = colors[93] = c[5].G; + colors[22] = colors[46] = colors[94] = c[5].B; + colors[23] = colors[47] = colors[95] = c[5].A; + + colors[24] = colors[60] = colors[88] = c[6].R; + colors[25] = colors[61] = colors[89] = c[6].G; + colors[26] = colors[62] = colors[90] = c[6].B; + colors[27] = colors[63] = colors[91] = c[6].A; + + colors[28] = colors[48] = colors[72] = c[7].R; + colors[29] = colors[49] = colors[73] = c[7].G; + colors[30] = colors[50] = colors[74] = c[7].B; + colors[31] = colors[51] = colors[75] = c[7].A; + attribMutex.unlock(); +} + /*! * \brief Destructor for the Cuboid. */ diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index 979a8d844..d2831a5dc 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -35,12 +35,28 @@ class Cuboid : public Object3D { virtual void changeHeightBy(GLfloat delta); + /*! + * \brief Accessor for the length of the Prism. + * \details Returns the value of the myLength private variable, a GLfloat. + */ virtual GLfloat getLength() { return myLength; } + /*! + * \brief Accessor for the height of the Prism. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ virtual GLfloat getHeight() { return myHeight; } + /*! + * \brief Accessor for the width of the Prism. + * \details Returns the value of the myWidth private variable, a GLfloat. + */ virtual GLfloat getWidth() { return myWidth; } + virtual void setColor(ColorGLfloat c) { Object3D::setColor(c); } + + virtual void setColor(ColorGLfloat c[]); + virtual ~Cuboid(); }; diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 7db006525..20ba2d2fd 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -27,6 +27,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius verticalSections = 36; horizontalSections = 20; numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; + outlineGeometryType = GL_LINES; edgesOutlined = false; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; @@ -73,6 +74,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius verticalSections = 36; horizontalSections = 20; numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; + outlineGeometryType = GL_LINES; edgesOutlined = false; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; @@ -91,52 +93,9 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius addVertex(sin((a*PI)/(verticalSections/2))*sin(((b+1)*PI)/horizontalSections), cos((a*PI)/(verticalSections/2)), cos(((b+1)*PI)/horizontalSections)*sin((a*PI)/(verticalSections/2)), c[b]); } } - addVertex(0, 1, 0, c[horizontalSections]); + addVertex(0, 1, 0, c[horizontalSections-1]); } -/** - * \brief Sets the Ellipsoid to a new color. - * \param c The new ColorGLfloat. - */ -void Ellipsoid::setColor(ColorGLfloat c) { - // attribMutex.lock(); - // for(int i = 0; i < numberOfVertices; i++) { - // colors[i*6 + 2] = c.R; - // colors[i*6 + 3] = c.G; - // colors[i*6 + 4] = c.B; - // colors[i*6 + 5] = c.A; - // } - // attribMutex.unlock(); -} - -/** - * \brief Sets the Ellipsoid to an array of new colors. - * \param c An array of new ColorGLfloats. - */ -void Ellipsoid::setColor(ColorGLfloat c[]) { - // attribMutex.lock(); - // for(int i = 0; i < numberOfVertices; i++) { - // colors[i*4] = c[i].R; - // colors[i*4 + 1] = c[i].G; - // colors[i*4 + 2] = c[i].B; - // colors[i*4 + 3] = c[i].A; - // } - // attribMutex.unlock(); -} - -/** - * \brief Gets an array of the Ellipsoid's fill vertex colors. - * \return c An array of ColorGLfloats. - * \warning This method allocates memory. The caller is responsible for deallocating it. - */ -// ColorGLfloat* Ellipsoid::getColor() { -// ColorGLfloat * c = new ColorGLfloat[numberOfVertices * 4]; -// for(int i = 0; i < numberOfVertices; i++) { -// c[i] = ColorGLfloat(colors[i*6 + 2], colors[i*6 + 3], colors[i*6 + 4], colors[i*6 + 5]); -// } -// return c; -// } - /** * \brief Mutates the Ellipsoid's x-axis radius. * \param radius The new x-axis radius of the Ellipsoid. @@ -227,6 +186,61 @@ void Ellipsoid::changeZRadiusBy(GLfloat delta) { attribMutex.unlock(); } +/** + * \brief Sets the Ellipsoid to a new color. + * \param c The new ColorGLfloat. + */ +void Ellipsoid::setColor(ColorGLfloat c) { + attribMutex.lock(); + for(int b=0;bsetCenterX(sin(rotation)*2); @@ -48,6 +52,15 @@ void coneFunction(Canvas& can) { // delta = 0.05; // } // testCone->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCone->setColor(ColorGLfloat(1,0,0,1)); + } else { + testCone->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 90940a020..3cb58374e 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -19,6 +19,7 @@ void cubeFunction(Canvas& can) { can.add(testCube2); float rotation = 0.0f; GLfloat delta = 0.05; + bool boolean = false; while (can.isOpen()) { can.sleep(); // testCube->setCenterX(sin(rotation)*2); @@ -36,8 +37,16 @@ void cubeFunction(Canvas& can) { // } // testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); + if (rotation*45 >= 360) { + if (boolean) { + testCube->setColor(ColorGLfloat(1,0,0,1)); + } else { + testCube->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; - // printf("Roll %f\n", testCube2->getRoll()); } delete testCube; diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index 8fbb1336c..fead47d0d 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -19,6 +19,7 @@ void cuboidFunction(Canvas& can) { // can.add(testCuboid2); float rotation = 0.0f; GLfloat delta = 0.05; + bool boolean = false;; while (can.isOpen()) { can.sleep(); // testCuboid->setCenterX(sin(rotation)*2); @@ -53,6 +54,15 @@ void cuboidFunction(Canvas& can) { // delta = 0.05; // } // testCuboid->changeLengthBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCuboid->setColor(ColorGLfloat(1,0,0,1)); + } else { + testCuboid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index 5bdf6ba52..2de337bde 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -20,7 +20,8 @@ void cylinderFunction(Canvas& can) { can.add(testCylinder); // can.add(testCylinder2); float rotation = 0.0f; - GLfloat delta = 0.05; + // GLfloat delta = 0.05; + bool boolean = false; while (can.isOpen()) { can.sleep(); // testCylinder->setCenterX(sin(rotation)*2); @@ -45,6 +46,20 @@ void cylinderFunction(Canvas& can) { // delta = 0.05; // } // testCylinder->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // testCylinder->displayOutlineEdges(boolean); + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testCylinder->setColor(ColorGLfloat(1,0,0,1)); + } else { + testCylinder->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index a3ad4960b..65c2fdc98 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -23,7 +23,8 @@ void ellipsoidFunction(Canvas& can) { can.add(testEllipsoid); // can.add(testEllipsoid2); float rotation = 0.0f; - GLfloat delta = 0.05; + // GLfloat delta = 0.05; + bool boolean = true; // testEllipsoid->setXRadius(1.5); // testEllipsoid->setYRadius(1.5); // testEllipsoid->setZRadius(1.5); @@ -36,9 +37,9 @@ void ellipsoidFunction(Canvas& can) { // testEllipsoid->setCenterY(cos(rotation)); // testEllipsoid->setCenterZ(sin(rotation)); // testEllipsoid->setYaw(rotation*45); - // testEllipsoid->setPitch(rotation*45); + testEllipsoid->setPitch(rotation*45); // testEllipsoid2->setPitch(rotation*45); - testEllipsoid->setRoll(rotation*45); + // testEllipsoid->setRoll(rotation*45); // testEllipsoid->setXRadius(cos(rotation)+1.01); // testEllipsoid->setYRadius(sin(rotation)+2.01); // testEllipsoid->setZRadius(sin(rotation)+3.01); @@ -65,6 +66,20 @@ void ellipsoidFunction(Canvas& can) { // delta = 0.05; // } // testEllipsoid->changeZRadiusBy(delta); + // if (rotation*45 >= 360) { + // testEllipsoid->displayOutlineEdges(boolean); + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testEllipsoid->setColor(ColorGLfloat(1,0,0,1)); + } else { + testEllipsoid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index 6bd9ac8eb..94853b8fa 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -23,6 +23,7 @@ void prismFunction(Canvas& can) { can.add(testPrism3); float rotation = 0.0f; GLfloat delta = 0.05; + bool boolean = false; while (can.isOpen()) { can.sleep(); // testPrism->setCenterX(sin(rotation)*2); @@ -47,6 +48,19 @@ void prismFunction(Canvas& can) { // delta = 0.05; // } // testPrism->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // testPrism->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // rotation = 0; + // } + // if (rotation*45 >= 360) { + // if (boolean) { + // testPrism->setColor(ColorGLfloat(1,0,0,1)); + // } else { + // testPrism->setColor(colors); + // } + // boolean = !boolean; + // rotation = 0; + // } rotation+=0.01; } diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 644d86efb..68042f775 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -23,6 +23,7 @@ void pyramidFunction(Canvas& can) { can.add(testPyramid3); float rotation = 0.0f; GLfloat delta = 0.05; + bool boolean = false; while (can.isOpen()) { can.sleep(); // testPyramid->setCenterX(sin(rotation)*2); @@ -49,6 +50,15 @@ void pyramidFunction(Canvas& can) { // delta = 0.05; // } // testPyramid->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testPyramid->setColor(ColorGLfloat(1,0,0,1)); + } else { + testPyramid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index 30d9b291c..10c5a2bb8 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -18,10 +18,11 @@ void sphereFunction(Canvas& can) { ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors /* ColorGLfloat(1,0.1,0.5,1) */); + Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); can.add(testSphere); float rotation = 0.0f; - GLfloat delta = 0.05; + // GLfloat delta = 0.05; + bool boolean = true; while (can.isOpen()) { can.sleep(); // testSphere->setCenterX(sin(rotation)); @@ -38,6 +39,22 @@ void sphereFunction(Canvas& can) { // delta = 0.05; // } // testSphere->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // testSphere->displayOutlineEdges(boolean); + // boolean = !boolean; + // rotation = 0; + // } + // printf("%f\n", rotation*45); + if (rotation*45 >= 360) { + if (boolean) { + testSphere->setColor(ColorGLfloat(1,0,0,1)); + } else { + testSphere->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; } From 8f051ebd42e8046dbd599b1ff589b90b0dfa491c Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 16 Apr 2020 14:21:45 -0400 Subject: [PATCH 017/105] Improved rotation capabilities with getCenter_ --- src/TSGL/Object3D.cpp | 9 ++++++--- src/tests/test3DRotation.cpp | 16 +++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index e1d917133..ff96e60f6 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -384,7 +384,8 @@ float Object3D::getCenterX() { if (centerMatchesRotationPoint()) { return myCenterX; } - return myCenterX; + // return myCenterX; + return cos(myCurrentYaw * PI / 180) * cos(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + (cos(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) - sin(myCurrentYaw * PI / 180) * cos(myCurrentRoll * PI / 180)) * (myCenterY - myRotationPointY) + (cos(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) + sin(myCurrentYaw * PI / 180) * sin(myCurrentRoll * PI / 180)) * (myCenterZ - myRotationPointZ) + myRotationPointX; } /*! @@ -395,7 +396,8 @@ float Object3D::getCenterY() { if (centerMatchesRotationPoint()) { return myCenterY; } - return myCenterY; + // return myCenterY; + return sin(myCurrentYaw * PI / 180) * cos(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + (sin(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) + cos(myCurrentYaw * PI / 180) * cos(myCurrentRoll * PI / 180)) * (myCenterY - myRotationPointY) + (sin(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) - cos(myCurrentYaw * PI / 180) * sin(myCurrentRoll * PI / 180)) * (myCenterZ - myRotationPointZ) + myRotationPointY; } /*! @@ -406,7 +408,8 @@ float Object3D::getCenterZ() { if (centerMatchesRotationPoint()) { return myCenterZ; } - return myCenterZ; + // return myCenterZ; + return -sin(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + cos(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) * (myCenterY - myRotationPointY) + cos(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) * (myCenterZ - myRotationPointZ) + myRotationPointZ; } void Object3D::setRotation(float radians) { diff --git a/src/tests/test3DRotation.cpp b/src/tests/test3DRotation.cpp index 7f7853573..55dfc24ac 100644 --- a/src/tests/test3DRotation.cpp +++ b/src/tests/test3DRotation.cpp @@ -12,11 +12,16 @@ using namespace tsgl; void cubeFunction(Canvas& can) { ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cube * testCube = new Cube(2.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Cube * testCube = new Cube(2.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, colors); testCube->setRotationPoint(0,0,0); Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 90.0, colors); - Sphere * testSphere = new Sphere(4, 0, 0, 1, 0.0, 0.0, 0.0, colors); + Sphere * testSphere = new Sphere(3, 0, 0, 1, 0.0, 0.0, 0.0, colors); testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); can.add(testCube); can.add(testPrism); @@ -27,8 +32,9 @@ void cubeFunction(Canvas& can) { can.sleep(); testCube->setYaw(rotation); testPrism->setYaw(-rotation); - // testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setPitch(rotation); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setCenter(testCube->getCenterX() + 1, testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setYaw(-rotation); rotation += 1; } From 591d606704924714db41def8a1072199834ae897 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 16 Apr 2020 21:56:30 -0400 Subject: [PATCH 018/105] Clean up previous commit. --- src/TSGL/Object3D.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index ff96e60f6..7502b48f9 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -384,8 +384,13 @@ float Object3D::getCenterX() { if (centerMatchesRotationPoint()) { return myCenterX; } - // return myCenterX; - return cos(myCurrentYaw * PI / 180) * cos(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + (cos(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) - sin(myCurrentYaw * PI / 180) * cos(myCurrentRoll * PI / 180)) * (myCenterY - myRotationPointY) + (cos(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) + sin(myCurrentYaw * PI / 180) * sin(myCurrentRoll * PI / 180)) * (myCenterZ - myRotationPointZ) + myRotationPointX; + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return cosYaw * cosPitch * (myCenterX - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myCenterY - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointX; } /*! @@ -396,8 +401,13 @@ float Object3D::getCenterY() { if (centerMatchesRotationPoint()) { return myCenterY; } - // return myCenterY; - return sin(myCurrentYaw * PI / 180) * cos(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + (sin(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) + cos(myCurrentYaw * PI / 180) * cos(myCurrentRoll * PI / 180)) * (myCenterY - myRotationPointY) + (sin(myCurrentYaw * PI / 180) * sin(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) - cos(myCurrentYaw * PI / 180) * sin(myCurrentRoll * PI / 180)) * (myCenterZ - myRotationPointZ) + myRotationPointY; + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return sinYaw * cosPitch * (myCenterX - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myCenterY - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointY; } /*! @@ -408,8 +418,13 @@ float Object3D::getCenterZ() { if (centerMatchesRotationPoint()) { return myCenterZ; } - // return myCenterZ; - return -sin(myCurrentPitch * PI / 180) * (myCenterX - myRotationPointX) + cos(myCurrentPitch * PI / 180) * sin(myCurrentRoll * PI / 180) * (myCenterY - myRotationPointY) + cos(myCurrentPitch * PI / 180) * cos(myCurrentRoll * PI / 180) * (myCenterZ - myRotationPointZ) + myRotationPointZ; + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return -sinPitch * (myCenterX - myRotationPointX) + cosPitch * sinRoll * (myCenterY - myRotationPointY) + cosPitch * cosRoll * (myCenterZ - myRotationPointZ) + myRotationPointZ; } void Object3D::setRotation(float radians) { From 1f8496c0053b4aacc406a8688b170a30c99c6406 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 20 Apr 2020 15:33:05 -0400 Subject: [PATCH 019/105] Removed outlineFirstIndex instance var. Added docs --- src/TSGL/Cone.cpp | 2 -- src/TSGL/Cylinder.cpp | 2 -- src/TSGL/Object3D.cpp | 15 ++++++++++----- src/TSGL/Object3D.h | 1 - src/TSGL/Prism.cpp | 2 -- src/TSGL/Pyramid.cpp | 2 -- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 85844f325..8357be50d 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -21,7 +21,6 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo : Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; - outlineFirstIndex = 0; outlineGeometryType = GL_LINE_LOOP; } @@ -44,7 +43,6 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo : Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; - outlineFirstIndex = 0; outlineGeometryType = GL_LINE_LOOP; } diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index 9893c2dbc..d7880c651 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -21,7 +21,6 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl : Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; - outlineFirstIndex = 0; outlineGeometryType = GL_LINES; } @@ -44,7 +43,6 @@ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float : Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; - outlineFirstIndex = 0; outlineGeometryType = GL_LINES; } diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp index 7502b48f9..037b9951a 100644 --- a/src/TSGL/Object3D.cpp +++ b/src/TSGL/Object3D.cpp @@ -52,7 +52,7 @@ void Object3D::draw() { glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); glColorPointer(4, GL_FLOAT, 0, outlineArray); - glDrawArrays(outlineGeometryType, outlineFirstIndex, numberOfOutlineVertices); + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); } glPopMatrix(); @@ -377,8 +377,9 @@ void Object3D::setRotationPointZ(float z) { /*! * \brief Accessor for the center x-coordinate of the Object3D. - * \details Returns the value of the myCenterX private variable, - * rotated by yaw, pitch, and roll about myRotationPointX; + * \details Returns the value of the myCenterX private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointX; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. */ float Object3D::getCenterX() { if (centerMatchesRotationPoint()) { @@ -395,7 +396,9 @@ float Object3D::getCenterX() { /*! * \brief Accessor for the center z-coordinate of the Object3D. - * \details Returns the value of the myCenterZ private variable. + * \details Returns the value of the myCenterY private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointY; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. */ float Object3D::getCenterY() { if (centerMatchesRotationPoint()) { @@ -412,7 +415,9 @@ float Object3D::getCenterY() { /*! * \brief Accessor for the center z-coordinate of the Object3D. - * \details Returns the value of the myCenterZ private variable. + * \details Returns the value of the myCenterZ private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointZ; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. */ float Object3D::getCenterZ() { if (centerMatchesRotationPoint()) { diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h index 58b0a5088..d748db4dd 100644 --- a/src/TSGL/Object3D.h +++ b/src/TSGL/Object3D.h @@ -30,7 +30,6 @@ class Object3D : public Drawable { bool edgesOutlined = true; int numberOfVertices; int numberOfOutlineVertices; - GLint outlineFirstIndex = 0; GLsizei outlineStride = 0; GLfloat* vertices; GLfloat* colors; diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index 27a76a484..be0ff6b2d 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -33,7 +33,6 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu numberOfVertices = mySides * 12; outlineStride = 2; numberOfOutlineVertices = mySides * 6; - outlineFirstIndex = 0; outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; @@ -89,7 +88,6 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu numberOfVertices = mySides * 12; outlineStride = 2; numberOfOutlineVertices = mySides * 6; - outlineFirstIndex = 0; outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index b65b43426..146714548 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -36,7 +36,6 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; outlineStride = 2; - outlineFirstIndex = 0; outlineGeometryType = GL_LINE_LOOP; numberOfOutlineVertices = mySides * 3; vertices = new GLfloat[numberOfVertices * 3]; @@ -87,7 +86,6 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; outlineStride = 2; - outlineFirstIndex = 0; outlineGeometryType = GL_LINE_LOOP; numberOfOutlineVertices = mySides * 3; vertices = new GLfloat[numberOfVertices * 3]; From 7d2b67ab21b060f3c3600cc515fdb3092d4b802d Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 24 Apr 2020 02:41:34 -0400 Subject: [PATCH 020/105] Huge changes to 2D stuff. Some bugs in CCPolygon --- Makefile | 103 +- src/TSGL/Arrow.cpp | 192 +- src/TSGL/Arrow.h | 19 +- src/TSGL/Canvas.cpp | 3530 +++++++++++++++--------------- src/TSGL/Canvas.h | 182 +- src/TSGL/CartesianCanvas.cpp | 2522 ++++++++++----------- src/TSGL/CartesianCanvas.h | 104 +- src/TSGL/Circle.cpp | 95 +- src/TSGL/Circle.h | 33 +- src/TSGL/ConcavePolygon.cpp | 543 ++--- src/TSGL/ConcavePolygon.h | 29 +- src/TSGL/ConvexPolygon.cpp | 189 +- src/TSGL/ConvexPolygon.h | 28 +- src/TSGL/Cube.cpp | 4 +- src/TSGL/Cube.h | 8 +- src/TSGL/Cuboid.cpp | 4 +- src/TSGL/Cuboid.h | 8 +- src/TSGL/Drawable.cpp | 438 +++- src/TSGL/Drawable.h | 177 +- src/TSGL/Ellipse.cpp | 140 +- src/TSGL/Ellipse.h | 26 +- src/TSGL/Ellipsoid.cpp | 4 +- src/TSGL/Ellipsoid.h | 6 +- src/TSGL/Image.cpp | 326 +-- src/TSGL/Image.h | 102 +- src/TSGL/IntegralViewer.cpp | 308 +-- src/TSGL/IntegralViewer.h | 98 +- src/TSGL/Line.cpp | 65 +- src/TSGL/Line.h | 17 +- src/TSGL/Object3D.cpp | 445 ---- src/TSGL/Object3D.h | 145 -- src/TSGL/Polygon.cpp | 501 ----- src/TSGL/Polygon.h | 66 - src/TSGL/Polyline.cpp | 68 +- src/TSGL/Polyline.h | 15 +- src/TSGL/Prism.cpp | 66 +- src/TSGL/Prism.h | 8 +- src/TSGL/ProgressBar.cpp | 160 +- src/TSGL/ProgressBar.h | 90 +- src/TSGL/Pyramid.cpp | 4 +- src/TSGL/Pyramid.h | 6 +- src/TSGL/Rectangle.cpp | 140 +- src/TSGL/Rectangle.h | 25 +- src/TSGL/RegularPolygon.cpp | 130 +- src/TSGL/RegularPolygon.h | 49 +- src/TSGL/Shape.cpp | 169 +- src/TSGL/Shape.h | 29 +- src/TSGL/Spectrogram.cpp | 346 +-- src/TSGL/Spectrogram.h | 84 +- src/TSGL/Sphere.cpp | 4 +- src/TSGL/Sphere.h | 6 +- src/TSGL/Square.cpp | 98 +- src/TSGL/Square.h | 42 +- src/TSGL/Star.cpp | 182 +- src/TSGL/Star.h | 17 +- src/TSGL/Text.cpp | 452 ++-- src/TSGL/Text.h | 76 +- src/TSGL/TextureHandler.cpp | 1588 +++++++------- src/TSGL/TextureHandler.h | 156 +- src/TSGL/Triangle.cpp | 108 +- src/TSGL/Triangle.h | 12 +- src/TSGL/TriangleStrip.cpp | 81 +- src/TSGL/TriangleStrip.h | 12 +- src/TSGL/VisualTaskQueue.cpp | 284 +-- src/TSGL/VisualTaskQueue.h | 90 +- src/tests/testArrows.cpp | 57 +- src/tests/testBallroom.cpp | 36 +- src/tests/testCircle.cpp | 63 + src/tests/testConcavePolygon.cpp | 24 +- src/tests/testConvexPolygon.cpp | 59 + src/tests/testEllipse.cpp | 69 + src/tests/testRectangle.cpp | 66 + src/tests/testRegularPolygon.cpp | 60 + src/tests/testSquare.cpp | 60 + src/tests/testStar.cpp | 59 +- src/tests/testTriangle.cpp | 58 + src/tests/testTriangleStrip.cpp | 61 + 77 files changed, 7395 insertions(+), 8331 deletions(-) delete mode 100644 src/TSGL/Object3D.cpp delete mode 100644 src/TSGL/Object3D.h delete mode 100644 src/TSGL/Polygon.cpp delete mode 100644 src/TSGL/Polygon.h create mode 100644 src/tests/testCircle.cpp create mode 100644 src/tests/testConvexPolygon.cpp create mode 100644 src/tests/testEllipse.cpp create mode 100644 src/tests/testRectangle.cpp create mode 100644 src/tests/testRegularPolygon.cpp create mode 100644 src/tests/testSquare.cpp create mode 100644 src/tests/testTriangle.cpp create mode 100644 src/tests/testTriangleStrip.cpp diff --git a/Makefile b/Makefile index e552e1bff..1efe70a7d 100644 --- a/Makefile +++ b/Makefile @@ -65,64 +65,75 @@ LFLAGS=-Llib/ \ DEPFLAGS=-MMD -MP BINARIES= \ - bin/test_specs \ bin/test3DRotation \ - bin/testAlphaRectangle \ bin/testArrows \ - bin/testAura \ bin/testBallroom \ - bin/testBlurImage \ - bin/testCalcPi \ - bin/testColorPoints \ - bin/testColorWheel \ - bin/testConcavePolygon \ bin/testCone \ - bin/testConstructors \ - bin/testConway \ - bin/testCosineIntegral \ + bin/testConvexPolygon \ + bin/testConcavePolygon \ bin/testCube \ bin/testCuboid \ bin/testCylinder \ - bin/testDumbSort \ + bin/testCircle \ + bin/testEllipse \ bin/testEllipsoid \ - bin/testFireworks \ - bin/testForestFire \ - bin/testFunction \ - bin/testGetPixels \ - bin/testGradientWheel \ - bin/testGraydient \ - bin/testGreyscale \ - bin/testHighData \ - bin/testImage \ - bin/testImageCart \ - bin/testInverter \ - bin/testLangton \ - bin/testLineChain \ - bin/testLineFan \ - bin/testMandelbrot \ - bin/testMouse \ - bin/testNewtonPendulum \ - bin/testPhilosophers \ - bin/testProducerConsumer \ - bin/testPong \ bin/testPrism \ - bin/testProgressBar \ - bin/testProjectiles \ bin/testPyramid \ - bin/testReaderWriter \ - bin/testRotation \ - bin/testScreenshot \ - bin/testSeaUrchin \ - bin/testSmartSort \ - bin/testSpectrogram \ - bin/testSpectrum \ + bin/testRectangle \ + bin/testRegularPolygon \ bin/testSphere \ + bin/testSquare \ bin/testStar \ - bin/testText \ - bin/testTextCart \ - bin/testTextTwo \ - bin/testUnits \ - bin/testVoronoi \ + bin/testTriangle \ + bin/testTriangleStrip \ +# bin/test_specs \ +# bin/testAlphaRectangle \ +# bin/testArrows \ +# bin/testAura \ +# bin/testBlurImage \ +# bin/testCalcPi \ +# bin/testColorPoints \ +# bin/testColorWheel \ +# bin/testConcavePolygon \ +# bin/testConstructors \ +# bin/testConway \ +# bin/testCosineIntegral \ +# bin/testDumbSort \ +# bin/testFireworks \ +# bin/testForestFire \ +# bin/testFunction \ +# bin/testGetPixels \ +# bin/testGradientWheel \ +# bin/testGraydient \ +# bin/testGreyscale \ +# bin/testHighData \ +# bin/testImage \ +# bin/testImageCart \ +# bin/testInverter \ +# bin/testLangton \ +# bin/testLineChain \ +# bin/testLineFan \ +# bin/testMandelbrot \ +# bin/testMouse \ +# bin/testNewtonPendulum \ +# bin/testPhilosophers \ +# bin/testProducerConsumer \ +# bin/testPong \ +# bin/testProgressBar \ +# bin/testProjectiles \ +# bin/testReaderWriter \ +# bin/testRotation \ +# bin/testScreenshot \ +# bin/testSeaUrchin \ +# bin/testSmartSort \ +# bin/testSpectrogram \ +# bin/testSpectrum \ +# bin/testStar \ +# bin/testText \ +# bin/testTextCart \ +# bin/testTextTwo \ +# bin/testUnits \ +# bin/testVoronoi #Use make tsgl to make only the library files all: dif tsgl tests docs tutorial diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index b7fdfd6e7..9d2f915c9 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -2,121 +2,131 @@ namespace tsgl { - /*! - * \brief Explicitly constructs a new monocolored Line. - * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color The reference variable to the color of the Line. - * \return A new Line with the specified endpoints and color. - */ - Arrow::Arrow(int x1, int y1, int x2, int y2, const ColorFloat color, bool doubleArrow) : ConcavePolygon((doubleArrow)? 10 : 7) { - headX = x2; headY = y2; - tailX = x1; tailY = y1; +/*! +* \brief Explicitly constructs a new monocolored Line. +* \details This is the constructor for the Line class. +* \param x1 The x coordinate of the first endpoint. +* \param y1 The y coordinate of the first endpoint. +* \param x2 The x coordinate of the second endpoint. +* \param y2 The y coordinate of the second endpoint. +* \param color The reference variable to the color of the Line. +* \return A new Line with the specified endpoints and color. +*/ +Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + headX = -0.5; headY = 0; + tailX = 0.5; tailY = 0; + myXScale = length; + myLength = length; isDoubleArrow = doubleArrow; headColor = color; tailColor = color; generateVertices(); - } +} - /*! - * \brief Explicitly constructs a new multicolored Line. - * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array of colors for the line endpoints. - * \return A new Line with the specified endpoints and endpoint colors. - */ - Arrow::Arrow(int x1, int y1, int x2, int y2, const ColorFloat color[], bool doubleArrow) : ConcavePolygon((doubleArrow)? 10 : 7) { - headX = x2; headY = y2; - tailX = x1; tailY = y1; +/*! +* \brief Explicitly constructs a new multicolored Line. +* \details This is the constructor for the Line class. +* \param x1 The x coordinate of the first endpoint. +* \param y1 The y coordinate of the first endpoint. +* \param x2 The x coordinate of the second endpoint. +* \param y2 The y coordinate of the second endpoint. +* \param color An array of colors for the line endpoints. +* \return A new Line with the specified endpoints and endpoint colors. +*/ +Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + headX = -0.5; headY = 0; + tailX = 0.5; tailY = 0; + myXScale = length; + myLength = length; isDoubleArrow = doubleArrow; headColor = color[0]; tailColor = color[1]; generateVertices(); - } +} - /*! - * \brief private method helping constructor initialize vertices array for monocolored arrow - */ - void Arrow::generateVertices() { - //TODO: figure out locking for this since we are adding vertices, which uses the lock - makeArrowHead(headX, headY, headX-tailX, headY-tailY, headColor); - - if( isDoubleArrow ) { - makeArrowHead(tailX, tailY, tailX-headX, tailY-headY, tailColor); - } else { - int a, b; //Offsets for vertices - if( tailY < headY ) a = 1; - else a = -1; - if( tailX > headX ) b = 1; - else b = -1; - - addVertex(tailX-a, tailY-b, tailColor); - addVertex(tailX+a, tailY+b, tailColor); +void Arrow::setLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have an Arrow with length less than or equal to 0."); + return; } - } - - /** - * \brief Moves the head of the Arrow. - * \details Changes the coordinates of the first point in the Arrow to a new x and y. - * \param x The new x coordinate of the head. - * \param y The new y coordinate of the head. - */ - void Arrow::moveHead(float x, float y) { attribMutex.lock(); - current = 0; init = false; - headX = x; headY = y; + myXScale = length; + myLength = length; attribMutex.unlock(); - generateVertices(); - } +} - /** - * \brief Moves the tail of the Arrow. - * \details Changes the coordinates of the second point in the Arrow to a new x and y. - * \param x The new x coordinate of the tail. - * \param y The new y coordinate of the tail. - */ - void Arrow::moveTail(float x, float y) { +void Arrow::changeLengthBy(GLfloat delta) { + if (myLength + delta <= 0) { + TsglDebug("Cannot have an Arrow with length less than or equal to 0."); + return; + } attribMutex.lock(); - current = 0; init = false; - tailX = x; tailY = y; + myXScale += delta; + myLength += delta; attribMutex.unlock(); - generateVertices(); - } +} + +/*! +* \brief private method helping constructor initialize vertices array for monocolored arrow +*/ +void Arrow::generateVertices() { + //TODO: figure out locking for this since we are adding vertices, which uses the lock + makeArrowHead(-0.5, 0, -1, 0, headColor); + + if( isDoubleArrow ) { + makeArrowHead(0.5, 0, 1, 0, tailColor); + } else { + float a, b; //Offsets for vertices + // if( tailY < headY ) a = 1; + // else a = -1; + a = -.02; + // if( tailX > headX ) b = 1; + // else b = -1; + b = .02; + + // addVertex(tailX-a, tailY-b, 0, tailColor); + // addVertex(tailX+a, tailY+b, 0, tailColor); + addVertex(tailX, -b, 0, tailColor); + addVertex(tailX, b, 0, tailColor); + } +} - /*! - * \brief private method helping constructor for the arrow heads - */ - void Arrow::makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorFloat color) { +/*! +* \brief private method helping constructor for the arrow heads +*/ +void Arrow::makeArrowHead(float x, float y, float deltaX, float deltaY, ColorGLfloat color) { - int a, b; - if( deltaY > 0 ) a = 1; - else a = -1; - if( deltaX < 0 ) b = 1; - else b = -1; + float a, b; + // if( deltaY > 0 ) a = 1; + // else a = -1; + a = -.02; + if( deltaX < 0 ) b = .02; + else b = -.02; + // b = 1; - float angle = atan( deltaY / deltaX ); - float s = sin( angle ), c = cos( angle ); - float x1 = -10*c-(-5)*s, x2 = 2*c - 0*s, x3 = -10*c-5*s; - float y1 = -10*s+(-5)*c, y2 = 2*s + 0*c, y3 = -10*s+5*c; + // float angle = atan( deltaY / deltaX ); + float angle = 0; + // float s = sin( angle ), c = cos( angle ); + float s = 0, c = 1; + // float x1 = -10*c-(-5)*s, x2 = 2*c - 0*s, x3 = -10*c-5*s; + // float y1 = -10*s+(-5)*c, y2 = 2*s + 0*c, y3 = -10*s+5*c; + float x1 = -0.1, x2 = .02, x3 = -0.1; + float y1 = -.05, y2 = 0, y3 = .05; // if we have an arrow pointing left, rotate it pi radians ( sin = 0, cos = -1) if (deltaX < 0) { - x1 = -x1, x2 = -x2, x3 = -x3; - y1 = -y1, y2 = -y2, y3 = -y3; + x1 = -x1, x2 = -x2, x3 = -x3; + y1 = -y1, y2 = -y2, y3 = -y3; } // transpose the triangle to the end of the line x1 += x, x2 += x, x3 += x; y1 += y, y2 += y, y3 += y; - addVertex( (x1+x3)/2+a, (y1+y3)/2+b, color ); - addVertex(x1, y1, color); - addVertex(x2, y2, color); - addVertex(x3, y3, color); - addVertex( (x1+x3)/2-a, (y1+y3)/2-b, color ); - } + // addVertex( (x1+x3)/2+a, (y1+y3)/2+b, 0, color ); + addVertex(x1, +b, 0, color); + addVertex(x1, y1, 0, color); + addVertex(x2, y2, 0, color); + addVertex(x3, y3, 0, color); + // addVertex( (x1+x3)/2-a, (y1+y3)/2-b, 0, color ); + addVertex(x3, -b, 0, color); +} } \ No newline at end of file diff --git a/src/TSGL/Arrow.h b/src/TSGL/Arrow.h index a89f39c3c..3a4a7b7bd 100644 --- a/src/TSGL/Arrow.h +++ b/src/TSGL/Arrow.h @@ -15,21 +15,24 @@ namespace tsgl { */ class Arrow : public ConcavePolygon { private: - int headX, headY, tailX, tailY; + float headX, headY, tailX, tailY; bool isDoubleArrow; - ColorFloat headColor; - ColorFloat tailColor; - void makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorFloat color); // Helps constructor by calculating the Arrow Head's coordinates + GLfloat myLength; + ColorGLfloat headColor; + ColorGLfloat tailColor; + void makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorGLfloat color); // Helps constructor by calculating the Arrow Head's coordinates void generateVertices(); public: - Arrow(int x1, int y1, int x2, int y2, const ColorFloat color, bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow = false); - Arrow(int x1, int y1, int x2, int y2, const ColorFloat color[], bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow = false); - void moveHead(float x, float y); + void setLength(GLfloat length); - void moveTail(float x, float y); + void changeLengthBy(GLfloat delta); + + GLfloat getLength() { return myLength; } }; } diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 39e683528..ed061a8f8 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -3,49 +3,49 @@ namespace tsgl { // Shader sources -static const GLchar* vertexSource = - "#version 150 core\n" - "in vec2 position;" - "in vec4 color;" - "out vec4 Color;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" - "}"; -static const GLchar* fragmentSource = - "#version 150\n" - "in vec4 Color;" - "out vec4 outColor;" - "void main() {" - " outColor = vec4(Color);" - "}"; -static const GLchar* textureVertexSource = - "#version 150 core\n" - "in vec2 position;" - "in vec4 color;" - "in vec2 texcoord;" - "out vec4 Color;" - "out vec2 Texcoord;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Texcoord = texcoord;" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" - "}"; -static const GLchar* textureFragmentSource = - "#version 150\n" - "in vec4 Color;" - "in vec2 Texcoord;" - "out vec4 outColor;" - "uniform sampler2D tex;" - "void main() {" - " outColor = texture(tex, Texcoord) * vec4(Color);" - "}"; +// static const GLchar* vertexSource = +// "#version 150 core\n" +// "in vec2 position;" +// "in vec4 color;" +// "out vec4 Color;" +// "uniform mat4 model;" +// "uniform mat4 view;" +// "uniform mat4 proj;" +// "void main() {" +// " Color = color;" +// " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" +// "}"; +// static const GLchar* fragmentSource = +// "#version 150\n" +// "in vec4 Color;" +// "out vec4 outColor;" +// "void main() {" +// " outColor = vec4(Color);" +// "}"; +// static const GLchar* textureVertexSource = +// "#version 150 core\n" +// "in vec2 position;" +// "in vec4 color;" +// "in vec2 texcoord;" +// "out vec4 Color;" +// "out vec2 Texcoord;" +// "uniform mat4 model;" +// "uniform mat4 view;" +// "uniform mat4 proj;" +// "void main() {" +// " Texcoord = texcoord;" +// " Color = color;" +// " gl_Position = proj * view * model * vec4(position, 0.0, 1.0);" +// "}"; +// static const GLchar* textureFragmentSource = +// "#version 150\n" +// "in vec4 Color;" +// "in vec2 Texcoord;" +// "out vec4 outColor;" +// "uniform sampler2D tex;" +// "void main() {" +// " outColor = texture(tex, Texcoord) * vec4(Color);" +// "}"; int Canvas::drawBuffer = GL_FRONT_LEFT; bool Canvas::glfwIsReady = false; @@ -136,9 +136,9 @@ void Canvas::buttonCallback(GLFWwindow* window, int button, int action, int mods * \brief Clears the Canvas. * \details This function clears the screen to the color specified in setBackgroundColor(). */ -void Canvas::clearProcedural() { - drawRectangle(0,0,getWindowWidth(),getWindowHeight(),getBackgroundColor()); -} +// void Canvas::clearProcedural() { +// drawRectangle(0,0,getWindowWidth(),getWindowHeight(),getBackgroundColor()); +// } /*! * \brief Closes the Canvas window. @@ -166,7 +166,7 @@ void Canvas::add(Drawable * shapePtr) { objectBuffer.push_back(shapePtr); objectBufferEmpty = false; std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { - return (a->getLayer() < b->getLayer()); // true if A's layer is higher than B's layer + return (a->getCenterZ() < b->getCenterZ()); // true if A's layer is higher than B's layer }); objectMutex.unlock(); } @@ -472,1337 +472,1337 @@ void Canvas::draw() } } */ - /*! - * \brief Draws a monocolored arrow. - * \details This function draws an arrow with the given endpoints, color, and doubleheaded status - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color A single color for the arrow. - * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. - */ -void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow) { - Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); - drawDrawable(arrow); -} - - /*! - * \brief Draws a multicolored arrow. - * \details This function draws an arrow with the given endpoints, color, and doubleheaded status - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array of colors for the circle. - * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. - */ -void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow) { - Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); - drawDrawable(arrow); -} - - /*! - * \brief Draws a monocolored filled or outlined circle. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color A single color for the circle. - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat color, bool filled) { - Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined circle. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color An array of colors for the circle. - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat color[], bool filled) { - Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A single color for circle's fill vertices. - * \param outlineColor A single color for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for circle's fill vertices. - * \param outlineColor A single color for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A single color for circle's fill vertices. - * \param outlineColor An array of colors for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for circle's fill vertices. - * \param outlineColor An array of colors for circle's outline vertices. - */ -void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { - Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color - drawDrawable(c); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined concave polygon. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param color A single color for the said vertices. - * \param filled Whether the ConcavePolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined concave polygon. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConcavePolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with different monocolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with multicolored fill and monocolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with monocolored fill and multicolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined concave polygon with different multicolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of said vertices. - * \param y An array of y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw convex polygons with this function. - * \see drawConvexPolygon(). - */ -void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined convex polygon. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param color A single color for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined convex polygon. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with different monocolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with multicolored fill and monocolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with monocolored fill and multicolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined convex polygon with different multicolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param x An array of the x positions of said vertices. - * \param y An array of the y positions of said vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the ConvexPolygon in radians clockwise. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - -/*! - * \brief Draws a Drawable object - * \details This function pushes any Drawable object onto the drawable buffer - * \param d The Drawable object to be drawn - * \note protected method - */ -void Canvas::drawDrawable(Drawable* d) { - if (!started) { - TsglDebug("No drawing before Canvas is started! Ignoring draw request."); - return; - } - while (!readyToDraw) - sleep(); - bufferMutex.lock(); - drawableBuffer->push(d); // Push it onto our drawing buffer - bufferMutex.unlock(); -} - - /*! - * \brief Draws a monocolored filled or outlined ellipse. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param color A single color for ellipse. - * \param filled Whether the ellipse should be filled - * (set to true by default). - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a multicolored filled or outlined ellipse. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), color, and fill status. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param color An array of colors for ellipse. - * \param filled Whether the ellipse should be filled - * (set to true by default). - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with different monocolored fill and outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor A single color for ellipse's fill vertices. - * \param outlineColor A single color for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with multicolored fill and monocolored outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor An array of colors for ellipse's fill vertices. - * \param outlineColor A single color for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with monocolored fill and multicolored outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor A single color for ellipse's fill vertices. - * \param outlineColor An array of colors for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws a filled and outlined ellipse with different multicolored fill and outline. - * \details This function draws an ellipse with the given center, radii, resolution - * (number of sides), colors. - * \param x The x coordinate of the ellipse's center. - * \param y The y coordinate of the ellipse's center. - * \param xRadius The x radius of the ellipse in pixels. - * \param yRadius The x radius of the ellipse in pixels. - * \param sides The number of sides to use in the ellipse. - * \param fillColor An array of colors for ellipse's fill vertices. - * \param outlineColor An array of colors for ellipse's outline vertices. - * \param rotation Rotation of the ellipse in radians clockwise. - */ -void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); - e->setRotation(rotation); - drawDrawable(e); -} - - /*! - * \brief Draws an image. - * \details This function draws an Image with the given coordinates and dimensions. - * \param filename The name of the file to load the image from. - * \param x The x coordinate of the Image's left edge. - * \param y The y coordinate of the Image's top edge. - * \param width The width of the Image. - * \param height The height of the Image. - * \param alpha The alpha with which to draw the Image - * \param rotation Rotation of the Image in radians clockwise. - */ -void Canvas::drawImage(std::string filename, int x, int y, int width, int height, float alpha, float rotation) { - Image* im = new Image(filename, loader, x, y, width, height, alpha); // Creates the Image with the specified coordinates - im->setRotation(rotation); - drawDrawable(im); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color The color of the line - * (set to BLACK by default). - * \param rotation Rotation of the line in radians clockwise. - */ -void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color, float rotation) { - Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color - l->setRotation(rotation); - drawDrawable(l); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color A color array for the line. - * \param rotation Rotation of the line in radians clockwise. - */ -void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation) { - Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color - l->setRotation(rotation); - drawDrawable(l); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a single pixel, specified in row,column format. - * \details This function draws a pixel at the given screen coordinates with the given color. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. - * \param row The row (y-position) of the pixel. - * \param col The column (x-position) of the pixel. - * \param color The color of the point (set to BLACK by default). - * \param rotation Rotation of the ConcavePolygon in radians clockwise. - * \see drawPoint() - */ -inline void Canvas::drawPixel(int row, int col, ColorFloat color) { - drawPoint(col, row, color); -} - - /*! - * \brief Draws a single pixel, specified in x,y format. - * \details This function draws a pixel at the given Cartesian coordinates with the given color. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. - * \param x The x position of the point. - * \param y The y position of the point. - * \param color The color of the point (set to BLACK by default). - * \see drawPixel() - */ -void Canvas::drawPoint(int x, int y, ColorFloat color) { - pointArrayMutex.lock(); - if (pointBufferPosition >= myDrawables->capacity()) { - loopAround = true; - pointBufferPosition = 0; - } - int tempPos = pointBufferPosition * 6; - pointBufferPosition++; - - float atioff = atiCard ? 0.5f : 0.0f; - vertexData[tempPos] = x; - vertexData[tempPos + 1] = y+atioff; - vertexData[tempPos + 2] = color.R; - vertexData[tempPos + 3] = color.G; - vertexData[tempPos + 4] = color.B; - vertexData[tempPos + 5] = color.A; - pointArrayMutex.unlock(); -} - - /*! - * \brief Draws a monocolored series of connected lines. - * \details This function draws Polyline at the given coordinates with the given color. - * \param size The number of vertices of the polyline. - * \param x An array of the x positions of the polyline's vertices. - * \param y An array of the y positions of the polyline's vertices. - * \param color A color for the Polyline. - * \param rotation Rotation of the Polyline in radians clockwise. - */ -void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation) { - Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored series of connected lines. - * \details This function draws Polyline at the given coordinates with the given color. - * \param size The number of vertices of the polyline. - * \param x An array of the x positions of the polyline's vertices. - * \param y An array of the y positions of the polyline's vertices. - * \param color A color array for the Polyline. - * \param rotation Rotation of the Polyline in radians clockwise. - */ -void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation) { - Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a progress bar. - * \details This function draws a previously created ProgressBar to the Canvas, as - * specified in that ProgressBar's constructor. - * \param p A pointer to a ProgressBar. - * \note There is no equivalent function for CartesianCanvas. If you'd like to draw - * a ProgressBar on a CartesianCanvas, you can still use this function, but you must - * use absolute Canvas coordinates rather than the scaled CartesianCanvas coordinates. - */ -void Canvas::drawProgress(ProgressBar* p) { - for (int i = 0; i < p->getSegs(); ++i) { - drawDrawable(p->getRect(i)); - drawDrawable(p->getBorder(i)); - } -} - - /*! - * \brief Draws a monocolored filled or outlined rectangle. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color A single color for Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined rectangle. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color An array of colors for Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with different monocolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A single color for Rectangle's fill vertices. - * \param outlineColor A single color for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with multicolored fill and monocolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for Rectangle's fill vertices. - * \param outlineColor A single color for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with monocolored fill and multicolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A single color for Rectangle's fill vertices. - * \param outlineColor An array of colors for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined rectangle with different multicolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for Rectangle's fill vertices. - * \param outlineColor An array of colors for Rectangle's outline vertices. - * \param rotation Rotation of the Rectangle in radians clockwise. - * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. - */ -void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color - rec->setRotation(rotation); - drawDrawable(rec); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined regular polygon. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param color A single color for RegularPolygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color, bool filled, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a multicolored filled or outlined regular polygon. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and color - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param color An array of colors for RegularPolygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with different monocolored fill and outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor A single color for RegularPolygon's fill vertices. - * \param outlineColor A single color for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with multicolored fill and monocolored outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor An array of colors for RegularPolygon's fill vertices. - * \param outlineColor A single color for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with monocolored fill and multicolored outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor A single color for RegularPolygon's fill vertices. - * \param outlineColor An array of colors for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a filled and outlined regular polygon with different multicolored fill and outline. - * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors - * \param x The x coordinate of the RegularPolygon's center - * \param y The y coordinate of the RegularPolygon's center - * \param radius The distance from the center to each vertex - * \param sides The number of sides for the RegularPolygon - * \param fillColor An array of colors for RegularPolygon's fill vertices. - * \param outlineColor An array of colors for RegularPolygon's outline vertices. - * \param rotation Rotation of the RegularPolygon in radians clockwise. - */ -void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); - c->setRotation(rotation); - drawDrawable(c); -} - - /*! - * \brief Draws a monocolored filled or outlined square. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param color A single color for Square. - * \param filled Whether the Square should be filled - * (set to true by default). - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled, float rotation) { - Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined Square. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param color An array of colors for Square. - * \param filled Whether the Square should be filled - * (set to true by default). - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled, float rotation) { - Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with different monocolored fill and outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor A single color for Square's fill vertices. - * \param outlineColor A single color for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with multicolored fill and monocolored outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor An array of colors for Square's fill vertices. - * \param outlineColor A single color for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with monocolored fill and multicolored outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor A single color for Square's fill vertices. - * \param outlineColor An array of colors for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined Square with different multicolored fill and outline. - * \details This function draws a Square with the given coordinates, dimensions, and color. - * \param x1 The x coordinate of the Square's left edge. - * \param y1 The y coordinate of the Square's top edge. - * \param x2 The x coordinate of the Square's right edge. - * \param y2 The y coordinate of the Square's bottom edge. - * \param fillColor An array of colors for Square's fill vertices. - * \param outlineColor An array of colors for Square's outline vertices. - * \param rotation Rotation of the Square in radians clockwise. - * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. - */ -void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color - s->setRotation(rotation); - drawDrawable(s); // Push it onto our drawing buffer -} - - - /*! - * \brief Draws a monocolored filled or outlined star. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param color A single color or array of colors for the star vertices. - * \param filled Whether the star should be filled - * (set to true by default). - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color, bool filled, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, color, filled, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a multicolored filled or outlined star. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param color A single color or array of colors for the star vertices. - * \param filled Whether the star should be filled - * (set to true by default). - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color[], bool filled, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, color, filled, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with different monocolored fill and outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with multicolored fill and monocolored outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with monocolored fill and multicolored outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draws a filled and outlined star with different multicolored fill and outline. - * \details This function draws a Star with the given coordinates, radius, points, and color. - * \param x1 The x coordinate of the star's center - * \param y1 The y coordinate of the star's center - * \param radius Radius of the outer points of the star - * \param points The number of points on the star - * \param fillColor A single color or array of colors for the star's fill vertices. - * \param outlineColor A single color or array of colors for the star's outline vertices. - * \param ninja makes it look conventional or like a shuriken - * \param rotation Rotation of the star in radians clockwise. - */ -void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja, float rotation) { - Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); - star->setRotation(rotation); - drawDrawable(star); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \param text The string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \param rotation Rotation of the Text in radians clockwise. - */ -void Canvas::drawText(std::string text, int x, int y, unsigned size, ColorFloat color, std::string fontFileName, float rotation) { - std::wstring wsTmp(text.begin(), text.end()); - std::wstring ws = wsTmp; - drawText(ws, x, y, size, color, fontFileName, rotation); -} - - /*! - * \brief Draws a UTF8-encoded string of text. - * \details This function draws a given string of UTF-8 encoded Text at the given coordinates with the given color. - * \param text The UTF8-encoded string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \param rotation Rotation of the Text in radians clockwise. - * \note Identical to the drawText(std::string, ...) aside from the first parameter. - * \see drawText(std::string s, int x, int y, unsigned size, ColorFloat color = BLACK). - */ -void Canvas::drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color, std::string fontFileName, float rotation) { - Text* t = new Text(text, x, y, size, color); // Creates the Point with the specified coordinates and color - if(fontFileName != defaultFontFileName && fontFileName != "") { - t->setFont(fontFileName); - } else { - if(defaultFontFileName != "") { - t->setFont(defaultFontFileName); - } - } - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a monocolored filled or outlined triangle. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color A single color for the Triangle vertices. - * \param filled Whether the Triangle should be filled (set to true by default). - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a multicolored filled or outlined triangle. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color An array of colors for the Triangle vertices. - * \param filled Whether the Triangle should be filled (set to true by default). - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with different monocolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A single color for the Triangle's fill vertices. - * \param outlineColor A single color for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with multicolored fill and monocolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill vertices. - * \param outlineColor A single color for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with monocolored fill and multicolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A single color for the Triangle's fill vertices. - * \param outlineColor An array of colors for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws a filled and outlined triangle with different multicolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill vertices. - * \param outlineColor An array of colors for the Triangle's outline vertices. - * \param rotation Rotation of the Triangle in radians clockwise. - */ -void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color - t->setRotation(rotation); - drawDrawable(t); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled or outlined monocolored triangle strip. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param color A single color for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false). - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled or outlined multicolored triangle strip. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false). - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with different monocolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with multicolored fill and monocolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor A single color for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with monocolored fill and multicolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor A single color for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} - - /*! - * \brief Draws an arbitrary filled and outlined triangle strip with different multicolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param x An array of x positions of the vertices. - * \param y An array of y positions of the vertices. - * \param fillColor An array of colors for the fill vertices. - * \param outlineColor An array of colors for the outline vertices. - * \param rotation Rotation of the TriangleStrip in radians clockwise. - */ -void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { - TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); - p->setRotation(rotation); - drawDrawable(p); // Push it onto our drawing buffer -} +// /*! +// * \brief Draws a monocolored arrow. +// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status +// * \param x1 The x coordinate of the first endpoint. +// * \param y1 The y coordinate of the first endpoint. +// * \param x2 The x coordinate of the second endpoint. +// * \param y2 The y coordinate of the second endpoint. +// * \param color A single color for the arrow. +// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. +// */ +// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow) { +// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); +// drawDrawable(arrow); +// } + +// /*! +// * \brief Draws a multicolored arrow. +// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status +// * \param x1 The x coordinate of the first endpoint. +// * \param y1 The y coordinate of the first endpoint. +// * \param x2 The x coordinate of the second endpoint. +// * \param y2 The y coordinate of the second endpoint. +// * \param color An array of colors for the circle. +// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. +// */ +// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow) { +// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); +// drawDrawable(arrow); +// } + +// /*! +// * \brief Draws a monocolored filled or outlined circle. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param color A single color for the circle. +// * \param filled Whether the circle should be filled +// * (set to true by default). +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color, bool filled) { +// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined circle. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param color An array of colors for the circle. +// * \param filled Whether the circle should be filled +// * (set to true by default). +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color[], bool filled) { +// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined circle with different monocolored fill and outline. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor A single color for circle's fill vertices. +// * \param outlineColor A single color for circle's outline vertices. +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor) { +// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined circle with multicolored fill and monocolored outline. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor An array of colors for circle's fill vertices. +// * \param outlineColor A single color for circle's outline vertices. +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor) { +// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined circle with monocolored fill and multicolored outline. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor A single color for circle's fill vertices. +// * \param outlineColor An array of colors for circle's outline vertices. +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]) { +// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined circle with different multicolored fill and outline. +// * \details This function draws a circle with the given center, radius, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor An array of colors for circle's fill vertices. +// * \param outlineColor An array of colors for circle's outline vertices. +// */ +// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { +// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color +// drawDrawable(c); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a monocolored filled or outlined concave polygon. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param color A single color for the said vertices. +// * \param filled Whether the ConcavePolygon should be filled in or not +// * (set to true by default). +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined concave polygon. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param color An array of colors for the said vertices. +// * \param filled Whether the ConcavePolygon should be filled in or not +// * (set to true by default). +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined concave polygon with different monocolored fill and outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor A single color for the outline vertices. +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined concave polygon with multicolored fill and monocolored outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor A single color for the outline vertices. +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined concave polygon with monocolored fill and multicolored outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined concave polygon with different multicolored fill and outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of said vertices. +// * \param y An array of y positions of said vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw convex polygons with this function. +// * \see drawConvexPolygon(). +// */ +// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a monocolored filled or outlined convex polygon. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param color A single color for the said vertices. +// * \param filled Whether the ConvexPolygon should be filled in or not +// * (set to true by default). +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined convex polygon. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param color An array of colors for the said vertices. +// * \param filled Whether the ConvexPolygon should be filled in or not +// * (set to true by default). +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined convex polygon with different monocolored fill and outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined convex polygon with multicolored fill and monocolored outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor A single color for the outline vertices. +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined convex polygon with monocolored fill and multicolored outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined convex polygon with different multicolored fill and outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param x An array of the x positions of said vertices. +// * \param y An array of the y positions of said vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the ConvexPolygon in radians clockwise. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a Drawable object +// * \details This function pushes any Drawable object onto the drawable buffer +// * \param d The Drawable object to be drawn +// * \note protected method +// */ +// void Canvas::drawDrawable(Drawable* d) { +// if (!started) { +// TsglDebug("No drawing before Canvas is started! Ignoring draw request."); +// return; +// } +// while (!readyToDraw) +// sleep(); +// bufferMutex.lock(); +// drawableBuffer->push(d); // Push it onto our drawing buffer +// bufferMutex.unlock(); +// } + +// /*! +// * \brief Draws a monocolored filled or outlined ellipse. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param color A single color for ellipse. +// * \param filled Whether the ellipse should be filled +// * (set to true by default). +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws a multicolored filled or outlined ellipse. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), color, and fill status. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param color An array of colors for ellipse. +// * \param filled Whether the ellipse should be filled +// * (set to true by default). +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws a filled and outlined ellipse with different monocolored fill and outline. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), colors. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param fillColor A single color for ellipse's fill vertices. +// * \param outlineColor A single color for ellipse's outline vertices. +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws a filled and outlined ellipse with multicolored fill and monocolored outline. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), colors. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param fillColor An array of colors for ellipse's fill vertices. +// * \param outlineColor A single color for ellipse's outline vertices. +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws a filled and outlined ellipse with monocolored fill and multicolored outline. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), colors. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param fillColor A single color for ellipse's fill vertices. +// * \param outlineColor An array of colors for ellipse's outline vertices. +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws a filled and outlined ellipse with different multicolored fill and outline. +// * \details This function draws an ellipse with the given center, radii, resolution +// * (number of sides), colors. +// * \param x The x coordinate of the ellipse's center. +// * \param y The y coordinate of the ellipse's center. +// * \param xRadius The x radius of the ellipse in pixels. +// * \param yRadius The x radius of the ellipse in pixels. +// * \param sides The number of sides to use in the ellipse. +// * \param fillColor An array of colors for ellipse's fill vertices. +// * \param outlineColor An array of colors for ellipse's outline vertices. +// * \param rotation Rotation of the ellipse in radians clockwise. +// */ +// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); +// e->setRotation(rotation); +// drawDrawable(e); +// } + +// /*! +// * \brief Draws an image. +// * \details This function draws an Image with the given coordinates and dimensions. +// * \param filename The name of the file to load the image from. +// * \param x The x coordinate of the Image's left edge. +// * \param y The y coordinate of the Image's top edge. +// * \param width The width of the Image. +// * \param height The height of the Image. +// * \param alpha The alpha with which to draw the Image +// * \param rotation Rotation of the Image in radians clockwise. +// */ +// void Canvas::drawImage(std::string filename, int x, int y, int width, int height, float alpha, float rotation) { +// Image* im = new Image(filename, loader, x, y, width, height, alpha); // Creates the Image with the specified coordinates +// im->setRotation(rotation); +// drawDrawable(im); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a monocolored line. +// * \details This function draws a Line at the given coordinates with the given color. +// * \param x1 The x position of the start of the line. +// * \param y1 The y position of the start of the line. +// * \param x2 The x position of the end of the line. +// * \param y2 The y position of the end of the line. +// * \param color The color of the line +// * (set to BLACK by default). +// * \param rotation Rotation of the line in radians clockwise. +// */ +// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color, float rotation) { +// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color +// l->setRotation(rotation); +// drawDrawable(l); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored line. +// * \details This function draws a Line at the given coordinates with the given color. +// * \param x1 The x position of the start of the line. +// * \param y1 The y position of the start of the line. +// * \param x2 The x position of the end of the line. +// * \param y2 The y position of the end of the line. +// * \param color A color array for the line. +// * \param rotation Rotation of the line in radians clockwise. +// */ +// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation) { +// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color +// l->setRotation(rotation); +// drawDrawable(l); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a single pixel, specified in row,column format. +// * \details This function draws a pixel at the given screen coordinates with the given color. +// * \note (0,0) signifies the top-left of the screen when working with a Canvas object. +// * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. +// * \param row The row (y-position) of the pixel. +// * \param col The column (x-position) of the pixel. +// * \param color The color of the point (set to BLACK by default). +// * \param rotation Rotation of the ConcavePolygon in radians clockwise. +// * \see drawPoint() +// */ +// inline void Canvas::drawPixel(int row, int col, ColorFloat color) { +// drawPoint(col, row, color); +// } + +// /*! +// * \brief Draws a single pixel, specified in x,y format. +// * \details This function draws a pixel at the given Cartesian coordinates with the given color. +// * \note (0,0) signifies the left-top of the screen when working with a Canvas object. +// * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. +// * \param x The x position of the point. +// * \param y The y position of the point. +// * \param color The color of the point (set to BLACK by default). +// * \see drawPixel() +// */ +// void Canvas::drawPoint(int x, int y, ColorFloat color) { +// pointArrayMutex.lock(); +// if (pointBufferPosition >= myDrawables->capacity()) { +// loopAround = true; +// pointBufferPosition = 0; +// } +// int tempPos = pointBufferPosition * 6; +// pointBufferPosition++; + +// float atioff = atiCard ? 0.5f : 0.0f; +// vertexData[tempPos] = x; +// vertexData[tempPos + 1] = y+atioff; +// vertexData[tempPos + 2] = color.R; +// vertexData[tempPos + 3] = color.G; +// vertexData[tempPos + 4] = color.B; +// vertexData[tempPos + 5] = color.A; +// pointArrayMutex.unlock(); +// } + +// /*! +// * \brief Draws a monocolored series of connected lines. +// * \details This function draws Polyline at the given coordinates with the given color. +// * \param size The number of vertices of the polyline. +// * \param x An array of the x positions of the polyline's vertices. +// * \param y An array of the y positions of the polyline's vertices. +// * \param color A color for the Polyline. +// * \param rotation Rotation of the Polyline in radians clockwise. +// */ +// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation) { +// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored series of connected lines. +// * \details This function draws Polyline at the given coordinates with the given color. +// * \param size The number of vertices of the polyline. +// * \param x An array of the x positions of the polyline's vertices. +// * \param y An array of the y positions of the polyline's vertices. +// * \param color A color array for the Polyline. +// * \param rotation Rotation of the Polyline in radians clockwise. +// */ +// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation) { +// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a progress bar. +// * \details This function draws a previously created ProgressBar to the Canvas, as +// * specified in that ProgressBar's constructor. +// * \param p A pointer to a ProgressBar. +// * \note There is no equivalent function for CartesianCanvas. If you'd like to draw +// * a ProgressBar on a CartesianCanvas, you can still use this function, but you must +// * use absolute Canvas coordinates rather than the scaled CartesianCanvas coordinates. +// */ +// void Canvas::drawProgress(ProgressBar* p) { +// for (int i = 0; i < p->getSegs(); ++i) { +// drawDrawable(p->getRect(i)); +// drawDrawable(p->getBorder(i)); +// } +// } + +// /*! +// * \brief Draws a monocolored filled or outlined rectangle. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param color A single color for Rectangle. +// * \param filled Whether the Rectangle should be filled +// * (set to true by default). +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled, float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined rectangle. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param color An array of colors for Rectangle. +// * \param filled Whether the Rectangle should be filled +// * (set to true by default). +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled, float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined rectangle with different monocolored fill and outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor A single color for Rectangle's fill vertices. +// * \param outlineColor A single color for Rectangle's outline vertices. +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined rectangle with multicolored fill and monocolored outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor An array of colors for Rectangle's fill vertices. +// * \param outlineColor A single color for Rectangle's outline vertices. +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined rectangle with monocolored fill and multicolored outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor A single color for Rectangle's fill vertices. +// * \param outlineColor An array of colors for Rectangle's outline vertices. +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined rectangle with different multicolored fill and outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's top edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor An array of colors for Rectangle's fill vertices. +// * \param outlineColor An array of colors for Rectangle's outline vertices. +// * \param rotation Rotation of the Rectangle in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. +// */ +// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color +// rec->setRotation(rotation); +// drawDrawable(rec); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a monocolored filled or outlined regular polygon. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param color A single color for RegularPolygon. +// * \param filled Whether the regular polygon should be filled +// * (set to true by default). +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color, bool filled, float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a multicolored filled or outlined regular polygon. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and color +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param color An array of colors for RegularPolygon. +// * \param filled Whether the regular polygon should be filled +// * (set to true by default). +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled, float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a filled and outlined regular polygon with different monocolored fill and outline. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param fillColor A single color for RegularPolygon's fill vertices. +// * \param outlineColor A single color for RegularPolygon's outline vertices. +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a filled and outlined regular polygon with multicolored fill and monocolored outline. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param fillColor An array of colors for RegularPolygon's fill vertices. +// * \param outlineColor A single color for RegularPolygon's outline vertices. +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a filled and outlined regular polygon with monocolored fill and multicolored outline. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param fillColor A single color for RegularPolygon's fill vertices. +// * \param outlineColor An array of colors for RegularPolygon's outline vertices. +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a filled and outlined regular polygon with different multicolored fill and outline. +// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors +// * \param x The x coordinate of the RegularPolygon's center +// * \param y The y coordinate of the RegularPolygon's center +// * \param radius The distance from the center to each vertex +// * \param sides The number of sides for the RegularPolygon +// * \param fillColor An array of colors for RegularPolygon's fill vertices. +// * \param outlineColor An array of colors for RegularPolygon's outline vertices. +// * \param rotation Rotation of the RegularPolygon in radians clockwise. +// */ +// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); +// c->setRotation(rotation); +// drawDrawable(c); +// } + +// /*! +// * \brief Draws a monocolored filled or outlined square. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param color A single color for Square. +// * \param filled Whether the Square should be filled +// * (set to true by default). +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled, float rotation) { +// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined Square. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param color An array of colors for Square. +// * \param filled Whether the Square should be filled +// * (set to true by default). +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled, float rotation) { +// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined Square with different monocolored fill and outline. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param fillColor A single color for Square's fill vertices. +// * \param outlineColor A single color for Square's outline vertices. +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined Square with multicolored fill and monocolored outline. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param fillColor An array of colors for Square's fill vertices. +// * \param outlineColor A single color for Square's outline vertices. +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined Square with monocolored fill and multicolored outline. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param fillColor A single color for Square's fill vertices. +// * \param outlineColor An array of colors for Square's outline vertices. +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined Square with different multicolored fill and outline. +// * \details This function draws a Square with the given coordinates, dimensions, and color. +// * \param x1 The x coordinate of the Square's left edge. +// * \param y1 The y coordinate of the Square's top edge. +// * \param x2 The x coordinate of the Square's right edge. +// * \param y2 The y coordinate of the Square's bottom edge. +// * \param fillColor An array of colors for Square's fill vertices. +// * \param outlineColor An array of colors for Square's outline vertices. +// * \param rotation Rotation of the Square in radians clockwise. +// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. +// */ +// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color +// s->setRotation(rotation); +// drawDrawable(s); // Push it onto our drawing buffer +// } + + +// /*! +// * \brief Draws a monocolored filled or outlined star. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param color A single color or array of colors for the star vertices. +// * \param filled Whether the star should be filled +// * (set to true by default). +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color, bool filled, bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, color, filled, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draws a multicolored filled or outlined star. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param color A single color or array of colors for the star vertices. +// * \param filled Whether the star should be filled +// * (set to true by default). +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color[], bool filled, bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, color, filled, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draws a filled and outlined star with different monocolored fill and outline. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param fillColor A single color or array of colors for the star's fill vertices. +// * \param outlineColor A single color or array of colors for the star's outline vertices. +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draws a filled and outlined star with multicolored fill and monocolored outline. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param fillColor A single color or array of colors for the star's fill vertices. +// * \param outlineColor A single color or array of colors for the star's outline vertices. +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draws a filled and outlined star with monocolored fill and multicolored outline. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param fillColor A single color or array of colors for the star's fill vertices. +// * \param outlineColor A single color or array of colors for the star's outline vertices. +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draws a filled and outlined star with different multicolored fill and outline. +// * \details This function draws a Star with the given coordinates, radius, points, and color. +// * \param x1 The x coordinate of the star's center +// * \param y1 The y coordinate of the star's center +// * \param radius Radius of the outer points of the star +// * \param points The number of points on the star +// * \param fillColor A single color or array of colors for the star's fill vertices. +// * \param outlineColor A single color or array of colors for the star's outline vertices. +// * \param ninja makes it look conventional or like a shuriken +// * \param rotation Rotation of the star in radians clockwise. +// */ +// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja, float rotation) { +// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); +// star->setRotation(rotation); +// drawDrawable(star); +// } + +// /*! +// * \brief Draw a string of text. +// * \details This function draws a given string of Text at the given coordinates with the given color. +// * \param text The string to draw. +// * \param x The x coordinate of the text's left bound. +// * \param y The y coordinate of the text's left bound. +// * \param size The size of the text in pixels. +// * \param color The color of the Text (set to BLACK by default). +// * \param rotation Rotation of the Text in radians clockwise. +// */ +// void Canvas::drawText(std::string text, int x, int y, unsigned size, ColorFloat color, std::string fontFileName, float rotation) { +// std::wstring wsTmp(text.begin(), text.end()); +// std::wstring ws = wsTmp; +// drawText(ws, x, y, size, color, fontFileName, rotation); +// } + +// /*! +// * \brief Draws a UTF8-encoded string of text. +// * \details This function draws a given string of UTF-8 encoded Text at the given coordinates with the given color. +// * \param text The UTF8-encoded string to draw. +// * \param x The x coordinate of the text's left bound. +// * \param y The y coordinate of the text's left bound. +// * \param size The size of the text in pixels. +// * \param color The color of the Text (set to BLACK by default). +// * \param rotation Rotation of the Text in radians clockwise. +// * \note Identical to the drawText(std::string, ...) aside from the first parameter. +// * \see drawText(std::string s, int x, int y, unsigned size, ColorFloat color = BLACK). +// */ +// void Canvas::drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color, std::string fontFileName, float rotation) { +// Text* t = new Text(text, x, y, size, color); // Creates the Point with the specified coordinates and color +// if(fontFileName != defaultFontFileName && fontFileName != "") { +// t->setFont(fontFileName); +// } else { +// if(defaultFontFileName != "") { +// t->setFont(defaultFontFileName); +// } +// } +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a monocolored filled or outlined triangle. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param color A single color for the Triangle vertices. +// * \param filled Whether the Triangle should be filled (set to true by default). +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled, float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a multicolored filled or outlined triangle. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param color An array of colors for the Triangle vertices. +// * \param filled Whether the Triangle should be filled (set to true by default). +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled, float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined triangle with different monocolored fill and outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor A single color for the Triangle's fill vertices. +// * \param outlineColor A single color for the Triangle's outline vertices. +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined triangle with multicolored fill and monocolored outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor An array of colors for the Triangle's fill vertices. +// * \param outlineColor A single color for the Triangle's outline vertices. +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined triangle with monocolored fill and multicolored outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor A single color for the Triangle's fill vertices. +// * \param outlineColor An array of colors for the Triangle's outline vertices. +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws a filled and outlined triangle with different multicolored fill and outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor An array of colors for the Triangle's fill vertices. +// * \param outlineColor An array of colors for the Triangle's outline vertices. +// * \param rotation Rotation of the Triangle in radians clockwise. +// */ +// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color +// t->setRotation(rotation); +// drawDrawable(t); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled or outlined monocolored triangle strip. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param color A single color for the vertices. +// * \param filled Whether the triangle strip should be filled (true) or not (false). +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled or outlined multicolored triangle strip. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param color An array of colors for the said vertices. +// * \param filled Whether the triangle strip should be filled (true) or not (false). +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled and outlined triangle strip with different monocolored fill and outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor A single color for the outline vertices. +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled and outlined triangle strip with multicolored fill and monocolored outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor A single color for the outline vertices. +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled and outlined triangle strip with monocolored fill and multicolored outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param fillColor A single color for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } + +// /*! +// * \brief Draws an arbitrary filled and outlined triangle strip with different multicolored fill and outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param x An array of x positions of the vertices. +// * \param y An array of y positions of the vertices. +// * \param fillColor An array of colors for the fill vertices. +// * \param outlineColor An array of colors for the outline vertices. +// * \param rotation Rotation of the TriangleStrip in radians clockwise. +// */ +// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { +// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); +// p->setRotation(rotation); +// drawDrawable(p); // Push it onto our drawing buffer +// } void Canvas::errorCallback(int error, const char* string) { fprintf(stderr, "%i: %s\n", error, string); @@ -2132,126 +2132,126 @@ void Canvas::initGl() { printf("Exiting initGl.\n"); } -void Canvas::initGlew() { - // Enable Experimental GLEW to Render Properly - glewExperimental = GL_TRUE; - GLenum err = glewInit(); - if (GLEW_OK != err) { - // Problem: glewInit failed, something is seriously wrong. - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - exit(102); - } - - hasEXTFramebuffer = false; - - GLint n, i; - glGetIntegerv(GL_NUM_EXTENSIONS, &n); - for (i = 0; i < n; i++) { - std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); - if (s == "GL_EXT_framebuffer_object") { - hasEXTFramebuffer = true; - break; - } - } - const GLubyte* gfxVendor = glGetString(GL_VENDOR); - std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); - atiCard = (gfx.find("ATI") != std::string::npos); -// #define DEBUG - #ifdef DEBUG - printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - printf("GLFW version: %s\n", glfwGetVersionString()); - printf("GL Extension: "); - for (i = 0; i < n; i++) - printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); - if (hasEXTFramebuffer) - TsglDebug("EXT Framebuffer available"); - #endif - - GLint status; - - // Create and bind our Vertex Array Object - glGenVertexArrays(1, &vertexArray); - glBindVertexArray(vertexArray); - - // Create and bind our Vertex Buffer Object - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - - // Create / compile vertex shader - shaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(shaderVertex, 1, &vertexSource, NULL); - glCompileShader(shaderVertex); - glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile fragment shader - shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(shaderFragment, 1, &fragmentSource, NULL); - glCompileShader(shaderFragment); - glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to a shader program, link the program - shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, shaderVertex); - glAttachShader(shaderProgram, shaderFragment); - glBindFragDataLocation(shaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our standard shader - glLinkProgram(shaderProgram); - - // Create / compile textured vertex shader - textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); - glCompileShader(textureShaderVertex); - glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile textured fragment shader - textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); - glCompileShader(textureShaderFragment); - glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to another shader program, link the program - textureShaderProgram = glCreateProgram(); - glAttachShader(textureShaderProgram, textureShaderVertex); - glAttachShader(textureShaderProgram, textureShaderFragment); - glBindFragDataLocation(textureShaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our textured shader - glLinkProgram(textureShaderProgram); - textureShaders(false); - - /****** NEW ******/ - // Create a framebuffer - frameBuffer = 0; - glGenFramebuffersEXT(1, &frameBuffer); - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); - // The texture we're going to render to - glGenTextures(1, &renderedTexture); - // "Bind" the newly created texture : all future texture functions will modify this texture - glBindTexture(GL_TEXTURE_2D, renderedTexture); - // Give an empty image to OpenGL ( the last "0" ) - // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems - glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // Poor filtering. Needed ! - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // Set "renderedTexture" as our colour attachement #0 - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); - // Set the list of draw buffers. - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - // Always check that our framebuffer is ok - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("FRAMEBUFFER CREATION FAILED"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} +// void Canvas::initGlew() { +// // Enable Experimental GLEW to Render Properly +// glewExperimental = GL_TRUE; +// GLenum err = glewInit(); +// if (GLEW_OK != err) { +// // Problem: glewInit failed, something is seriously wrong. +// fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); +// exit(102); +// } + +// hasEXTFramebuffer = false; + +// GLint n, i; +// glGetIntegerv(GL_NUM_EXTENSIONS, &n); +// for (i = 0; i < n; i++) { +// std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); +// if (s == "GL_EXT_framebuffer_object") { +// hasEXTFramebuffer = true; +// break; +// } +// } +// const GLubyte* gfxVendor = glGetString(GL_VENDOR); +// std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); +// atiCard = (gfx.find("ATI") != std::string::npos); +// // #define DEBUG +// #ifdef DEBUG +// printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); +// printf("OpenGL version: %s\n", glGetString(GL_VERSION)); +// printf("GLFW version: %s\n", glfwGetVersionString()); +// printf("GL Extension: "); +// for (i = 0; i < n; i++) +// printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); +// if (hasEXTFramebuffer) +// TsglDebug("EXT Framebuffer available"); +// #endif + +// GLint status; + +// // Create and bind our Vertex Array Object +// glGenVertexArrays(1, &vertexArray); +// glBindVertexArray(vertexArray); + +// // Create and bind our Vertex Buffer Object +// glGenBuffers(1, &vertexBuffer); +// glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); + +// // Create / compile vertex shader +// shaderVertex = glCreateShader(GL_VERTEX_SHADER); +// glShaderSource(shaderVertex, 1, &vertexSource, NULL); +// glCompileShader(shaderVertex); +// glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); + +// // Create / compile fragment shader +// shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); +// glShaderSource(shaderFragment, 1, &fragmentSource, NULL); +// glCompileShader(shaderFragment); +// glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); + +// // Attach both shaders to a shader program, link the program +// shaderProgram = glCreateProgram(); +// glAttachShader(shaderProgram, shaderVertex); +// glAttachShader(shaderProgram, shaderFragment); +// glBindFragDataLocation(shaderProgram, 0, "outColor"); + +// // Specify the layout of the vertex data in our standard shader +// glLinkProgram(shaderProgram); + +// // Create / compile textured vertex shader +// textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); +// glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); +// glCompileShader(textureShaderVertex); +// glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); + +// // Create / compile textured fragment shader +// textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); +// glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); +// glCompileShader(textureShaderFragment); +// glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); + +// // Attach both shaders to another shader program, link the program +// textureShaderProgram = glCreateProgram(); +// glAttachShader(textureShaderProgram, textureShaderVertex); +// glAttachShader(textureShaderProgram, textureShaderFragment); +// glBindFragDataLocation(textureShaderProgram, 0, "outColor"); + +// // Specify the layout of the vertex data in our textured shader +// glLinkProgram(textureShaderProgram); +// textureShaders(false); + +// /****** NEW ******/ +// // Create a framebuffer +// frameBuffer = 0; +// glGenFramebuffersEXT(1, &frameBuffer); +// if (hasEXTFramebuffer) +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); +// else +// glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); +// // The texture we're going to render to +// glGenTextures(1, &renderedTexture); +// // "Bind" the newly created texture : all future texture functions will modify this texture +// glBindTexture(GL_TEXTURE_2D, renderedTexture); +// // Give an empty image to OpenGL ( the last "0" ) +// // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems +// glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); +// // Poor filtering. Needed ! +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// // Set "renderedTexture" as our colour attachement #0 +// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); +// // Set the list of draw buffers. +// GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; +// glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers +// // Always check that our framebuffer is ok +// if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) +// TsglErr("FRAMEBUFFER CREATION FAILED"); + +// glBindFramebuffer(GL_FRAMEBUFFER, 0); +// } void Canvas::initGlfw() { if (!glfwIsReady) { @@ -2326,17 +2326,17 @@ void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, * \see resumeDrawing() */ void Canvas::pauseDrawing() { - #pragma omp critical (pauseResume) - { - if (syncMutexLocked == 0 && syncMutexOwner == -1) { - syncMutex.lock(); - syncMutexOwner = omp_get_thread_num(); - } - #pragma omp critical (syncMutLock) - { - ++syncMutexLocked; - } - } + // #pragma omp critical (pauseResume) + // { + // if (syncMutexLocked == 0 && syncMutexOwner == -1) { + // syncMutex.lock(); + // syncMutexOwner = omp_get_thread_num(); + // } + // #pragma omp critical (syncMutLock) + // { + // ++syncMutexLocked; + // } + // } } /*! @@ -2371,21 +2371,21 @@ void Canvas::reset() { * \see pauseDrawing() */ void Canvas::resumeDrawing() { - #pragma omp critical (syncMutLock) - { - --syncMutexLocked; - } - #pragma omp critical (pauseResume) - { - if (syncMutexOwner == omp_get_thread_num()) { - while (syncMutexLocked > 0) - sleepFor(FRAME/2); - syncMutex.unlock(); - syncMutexOwner = -1; - } - } - while (syncMutexOwner != -1) - sleepFor(FRAME/2); + // #pragma omp critical (syncMutLock) + // { + // --syncMutexLocked; + // } + // #pragma omp critical (pauseResume) + // { + // if (syncMutexOwner == omp_get_thread_num()) { + // while (syncMutexLocked > 0) + // sleepFor(FRAME/2); + // syncMutex.unlock(); + // syncMutexOwner = -1; + // } + // } + // while (syncMutexOwner != -1) + // sleepFor(FRAME/2); } /*! @@ -2502,7 +2502,7 @@ void Canvas::screenShot() { char filename[25]; sprintf(filename, "Image%06d.png", frameCounter); // TODO: Make this save somewhere not in root - loader.saveImageToFile(filename, screenBuffer, winWidthPadded, winHeight); + // loader.saveImageToFile(filename, screenBuffer, winWidthPadded, winHeight); } void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { @@ -2657,47 +2657,47 @@ void Canvas::takeScreenShot() { if (toRecord == 0) toRecord = 1; } -void Canvas::textureShaders(bool on) { - GLint program; - if (!on) { - program = shaderProgram; - - // Relocate the shader attributes - GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); - glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 0); - GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); - glEnableVertexAttribArray(colAttrib); - glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) (2 * sizeof(float))); - - } else { - program = textureShaderProgram; - - // Relocate the shader attributes - GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); - glEnableVertexAttribArray(texturePosAttrib); - glVertexAttribPointer(texturePosAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); - GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); - glEnableVertexAttribArray(textureColAttrib); - glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), - (void*) (2 * sizeof(float))); - GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); - glEnableVertexAttribArray(textureTexAttrib); - glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), - (void*) (6 * sizeof(float))); - } - - // Reallocate the shader program for use - glUseProgram(program); - - // Recompute the camera matrices - uniModel = glGetUniformLocation(program, "model"); - uniView = glGetUniformLocation(program, "view"); - uniProj = glGetUniformLocation(program, "proj"); - - // Update the camera - setupCamera(); -} +// void Canvas::textureShaders(bool on) { +// GLint program; +// if (!on) { +// program = shaderProgram; + +// // Relocate the shader attributes +// GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); +// glEnableVertexAttribArray(posAttrib); +// glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 0); +// GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); +// glEnableVertexAttribArray(colAttrib); +// glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) (2 * sizeof(float))); + +// } else { +// program = textureShaderProgram; + +// // Relocate the shader attributes +// GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); +// glEnableVertexAttribArray(texturePosAttrib); +// glVertexAttribPointer(texturePosAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); +// GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); +// glEnableVertexAttribArray(textureColAttrib); +// glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), +// (void*) (2 * sizeof(float))); +// GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); +// glEnableVertexAttribArray(textureTexAttrib); +// glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), +// (void*) (6 * sizeof(float))); +// } + +// // Reallocate the shader program for use +// glUseProgram(program); + +// // Recompute the camera matrices +// uniModel = glGetUniformLocation(program, "model"); +// uniView = glGetUniformLocation(program, "view"); +// uniProj = glGetUniformLocation(program, "proj"); + +// // Update the camera +// setupCamera(); +// } /*! * \brief Waits for the user to close the Canvas. @@ -2723,160 +2723,160 @@ int Canvas::wait() { /*! * \brief Runs unit tests for the Canvas. */ -void Canvas::runTests() { - TsglDebug("Testing Canvas class..."); - Canvas c1(0, 0, 500, 500, "", FRAME); - c1.setBackgroundColor(WHITE); - c1.start(); - tsglAssert(testFilledDraw(c1), "Unit test for filled draw failed!"); - tsglAssert(testLine(c1), "Unit test for line failed!"); - // tsglAssert(testAccessors(c1), "Unit test for accessors failed!"); - tsglAssert(testDrawImage(c1), "Unit test for drawing images failed!"); - c1.stop(); - TsglDebug("Unit tests for Canvas complete."); - std::cout << std::endl; -} - -//Similar format is used for the remaining unit tests -bool Canvas::testFilledDraw(Canvas& can) { - int passed = 0; //Passed tests - int failed = 0; //Failed tests - ColorInt red(255, 0, 0); //Fill color - can.drawCircle(250, 250, 50, red, true); //Draw filled shape - can.sleepFor(1); - - //Test 1: Get middle pixel and see if its red. - if(can.getPixel(250, 250) == red) { - passed++; - } else { - failed++; - TsglErr("Test 1, middle pixel for testFilledDraw() failed!"); - } - - //Test 2: Get leftmost and rightmost pixel of the circle - //Have to add or subtract 1 from the y so that you can get the correct pixel (center radius is 1. No 0 radius). - if(can.getPixel(250, 201) == red && can.getPixel(250, 299) == red) { - passed++; - } else { - failed++; - TsglErr("Test 2, leftmost and rightmost pixel for testFilledDraw() failed!"); - } - - //Test 3: Outside pixels shouldn't equal inside pixels - int test = 0; - //Single pixel.... - if(can.getPixel(1, 1) != red) { - //Multiple pixels.... - for(int i = 201; i <= 299; i++) { - if(can.getPixel(1, i) != red) { - test++; - } - } - //Results of multiple pixels... - if(test == 99) { - passed++; - } else { - failed++; - TsglErr("Test 3, outside != inside, Multiple pixels for testFilledDraw() failed!"); - } - } else { - failed++; - TsglErr("Test 3, outside != inside, Single pixel for testFilledDraw() failed!"); - } - - //Test 4: A LOT of the pixels on the inside should be red - int count = 0; - for(int i = 201; i <= 299; i++) { - if(can.getPixel(250, i) == red) { - count++; - } - } - - //Now check the count, should be 99 - if(count == 99) { - passed++; - } else { - failed++; - std::cout << "Count: " << count << std::endl; - TsglErr("Test 4, multiple pixels for testFilledDraw() failed!"); - } - - //Determine if we passed all four tests or not, Results: - if(passed == 4 && failed == 0) { - can.clearProcedural(); - TsglDebug("Unit test for drawing filled shapes passed!"); - return true; - } else { - can.clearProcedural(); - TsglErr("This many passed for testFilledDraw(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testFilledDraw(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -bool Canvas::testLine(Canvas & can) { - int passed = 0; - int failed = 0; - can.drawLine(0, 0, 250, 250, BLACK); //Diagonal line - can.drawLine(253, 253, 400, 253); //Straight line - can.sleepFor(1); - ColorInt black(0, 0, 0); - //Test 1: Near the ending endpoint? (Diagonal) - if(can.getPoint(249, 249) == black) { - passed++; - } else { - failed++; - TsglErr("Test 1, Near the ending endpoint? for testLine() failed!"); - } - - //Test 2: Somewhere in the middle? (Diagonal) - if(can.getPoint(155, 155) == black) { - passed++; - } else { - failed++; - TsglErr("Test 2, Somewhere in the middle? for testLine() failed!"); - } - - //Test 3: Near the starting endpoint? (Diagonal) - if(can.getPoint(15, 15) == black) { - passed++; - } else { - failed++; - TsglErr("Test 3, Near the starting endpoint? for testLine() failed!"); - } - - //Test 4: An entire line? (Straight) - int count = 0; - for(int i = 253; i <= 399; i++) { - if(can.getPoint(i, 253) == black) { - count++; - } - } - - //Check the results of the Straight line test - if(count == 147) { - passed++; - } else { - failed++; - TsglErr("Test 4, An entire line? (Straight) for testLine() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - can.clearProcedural(); - TsglDebug("Unit test for line passed!"); - return true; - } else { - can.clearProcedural(); - TsglErr("This many passed testLine(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testLine(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} +// void Canvas::runTests() { +// TsglDebug("Testing Canvas class..."); +// Canvas c1(0, 0, 500, 500, "", FRAME); +// c1.setBackgroundColor(WHITE); +// c1.start(); +// tsglAssert(testFilledDraw(c1), "Unit test for filled draw failed!"); +// tsglAssert(testLine(c1), "Unit test for line failed!"); +// // tsglAssert(testAccessors(c1), "Unit test for accessors failed!"); +// tsglAssert(testDrawImage(c1), "Unit test for drawing images failed!"); +// c1.stop(); +// TsglDebug("Unit tests for Canvas complete."); +// std::cout << std::endl; +// } + +// //Similar format is used for the remaining unit tests +// bool Canvas::testFilledDraw(Canvas& can) { +// int passed = 0; //Passed tests +// int failed = 0; //Failed tests +// ColorInt red(255, 0, 0); //Fill color +// can.drawCircle(250, 250, 50, red, true); //Draw filled shape +// can.sleepFor(1); + +// //Test 1: Get middle pixel and see if its red. +// if(can.getPixel(250, 250) == red) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, middle pixel for testFilledDraw() failed!"); +// } + +// //Test 2: Get leftmost and rightmost pixel of the circle +// //Have to add or subtract 1 from the y so that you can get the correct pixel (center radius is 1. No 0 radius). +// if(can.getPixel(250, 201) == red && can.getPixel(250, 299) == red) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, leftmost and rightmost pixel for testFilledDraw() failed!"); +// } + +// //Test 3: Outside pixels shouldn't equal inside pixels +// int test = 0; +// //Single pixel.... +// if(can.getPixel(1, 1) != red) { +// //Multiple pixels.... +// for(int i = 201; i <= 299; i++) { +// if(can.getPixel(1, i) != red) { +// test++; +// } +// } +// //Results of multiple pixels... +// if(test == 99) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, outside != inside, Multiple pixels for testFilledDraw() failed!"); +// } +// } else { +// failed++; +// TsglErr("Test 3, outside != inside, Single pixel for testFilledDraw() failed!"); +// } + +// //Test 4: A LOT of the pixels on the inside should be red +// int count = 0; +// for(int i = 201; i <= 299; i++) { +// if(can.getPixel(250, i) == red) { +// count++; +// } +// } + +// //Now check the count, should be 99 +// if(count == 99) { +// passed++; +// } else { +// failed++; +// std::cout << "Count: " << count << std::endl; +// TsglErr("Test 4, multiple pixels for testFilledDraw() failed!"); +// } + +// //Determine if we passed all four tests or not, Results: +// if(passed == 4 && failed == 0) { +// // can.clearProcedural(); +// TsglDebug("Unit test for drawing filled shapes passed!"); +// return true; +// } else { +// // can.clearProcedural(); +// TsglErr("This many passed for testFilledDraw(): "); +// std::cerr << " " << passed << std::endl; +// TsglErr("This many failed for testFilledDraw(): "); +// std::cerr << " " << failed << std::endl; +// return false; +// } +// } + +// bool Canvas::testLine(Canvas & can) { +// int passed = 0; +// int failed = 0; +// can.drawLine(0, 0, 250, 250, BLACK); //Diagonal line +// can.drawLine(253, 253, 400, 253); //Straight line +// can.sleepFor(1); +// ColorInt black(0, 0, 0); +// //Test 1: Near the ending endpoint? (Diagonal) +// if(can.getPoint(249, 249) == black) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Near the ending endpoint? for testLine() failed!"); +// } + +// //Test 2: Somewhere in the middle? (Diagonal) +// if(can.getPoint(155, 155) == black) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, Somewhere in the middle? for testLine() failed!"); +// } + +// //Test 3: Near the starting endpoint? (Diagonal) +// if(can.getPoint(15, 15) == black) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Near the starting endpoint? for testLine() failed!"); +// } + +// //Test 4: An entire line? (Straight) +// int count = 0; +// for(int i = 253; i <= 399; i++) { +// if(can.getPoint(i, 253) == black) { +// count++; +// } +// } + +// //Check the results of the Straight line test +// if(count == 147) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 4, An entire line? (Straight) for testLine() failed!"); +// } + +// //Results: +// if(passed == 4 && failed == 0) { +// // can.clearProcedural(); +// TsglDebug("Unit test for line passed!"); +// return true; +// } else { +// // can.clearProcedural(); +// TsglErr("This many passed testLine(): "); +// std::cerr << " " << passed << std::endl; +// TsglErr("This many failed for testLine(): "); +// std::cerr << " " << failed << std::endl; +// return false; +// } +// } bool Canvas::testAccessors(Canvas& can) { int passed = 0; @@ -2935,11 +2935,11 @@ bool Canvas::testAccessors(Canvas& can) { //Results: if(passed == 4 && failed == 0) { - can.clearProcedural(); + // can.clearProcedural(); TsglDebug("Unit test for accessors/mutators passed!"); return true; } else { - can.clearProcedural(); + // can.clearProcedural(); TsglErr("This many passed for testAccessors(): "); std::cerr << " " << passed << std::endl; TsglErr("This many failed for testAccessors(): "); @@ -2948,48 +2948,48 @@ bool Canvas::testAccessors(Canvas& can) { } } -bool Canvas::testDrawImage(Canvas& can) { - can.drawImage("../assets/pics/ff0000.png", 0, 0, 200, 200); - can.sleepFor(1); - int passed = 0; - int failed = 0; - ColorInt red(255, 0, 0); - //Test 1: Single pixel - if(can.getPoint(1, 1) == red) { - passed++; - } else { - failed++; - TsglErr("Test 1, Single pixel for testDrawImage() failed!"); - } - - //Test 2: Multiple pixels - int count = 0; - for(int i = 0; i < 200; i++) { - if(can.getPoint(1, i) == red) { - count++; - } - } - - //Results of Test 2: - if(count == 200) { - passed++; - } else { - failed++; - std::cout << "Count: " << count << std::endl; - TsglErr("Test 2, Multiple pixels for testDrawImage() failed!"); - } - - //Results of entire Unit test:s - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for drawing images passed!"); - return true; - } else { - TsglErr("This many passed for testDrawImage(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testDrawImage(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} +// bool Canvas::testDrawImage(Canvas& can) { +// can.drawImage("../assets/pics/ff0000.png", 0, 0, 200, 200); +// can.sleepFor(1); +// int passed = 0; +// int failed = 0; +// ColorInt red(255, 0, 0); +// //Test 1: Single pixel +// if(can.getPoint(1, 1) == red) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Single pixel for testDrawImage() failed!"); +// } + +// //Test 2: Multiple pixels +// int count = 0; +// for(int i = 0; i < 200; i++) { +// if(can.getPoint(1, i) == red) { +// count++; +// } +// } + +// //Results of Test 2: +// if(count == 200) { +// passed++; +// } else { +// failed++; +// std::cout << "Count: " << count << std::endl; +// TsglErr("Test 2, Multiple pixels for testDrawImage() failed!"); +// } + +// //Results of entire Unit test:s +// if(passed == 2 && failed == 0) { +// TsglDebug("Unit test for drawing images passed!"); +// return true; +// } else { +// TsglErr("This many passed for testDrawImage(): "); +// std::cerr << " " << passed << std::endl; +// TsglErr("This many failed for testDrawImage(): "); +// std::cerr << " " << failed << std::endl; +// return false; +// } +// } //------------End Unit testing-------------------------------------------------------- } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 827349979..22d3b2483 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -23,18 +23,18 @@ #include "Circle.h" // Our own class for drawing circles #include "ConcavePolygon.h" // Our own class for concave polygons with colored vertices #include "ConvexPolygon.h" // Our own class for convex polygons with colored vertices -#include "Image.h" // Our own class for drawing images / textured quads +// #include "Image.h" // Our own class for drawing images / textured quads #include "Keynums.h" // Our enums for key presses #include "Line.h" // Our own class for drawing straight lines #include "Polyline.h" // Our own class for drawing polylines -#include "ProgressBar.h" // Our own class for drawing progress bars +// #include "ProgressBar.h" // Our own class for drawing progress bars #include "Pyramid.h" // Our own class for drawing pyramids #include "Rectangle.h" // Our own class for drawing rectangles #include "RegularPolygon.h" // Our own class for drawing regular polygons #include "Sphere.h" // Our own class for drawing spheres #include "Square.h" // Our own class for drawing squares #include "Star.h" // Our own class for drawing stars -#include "Text.h" // Our own class for drawing text +// #include "Text.h" // Our own class for drawing text #include "Timer.h" // Our own timer for steady FPS #include "Triangle.h" // Our own class for drawing triangles #include "Util.h" // Needed constants and has cmath for performing math operations @@ -92,7 +92,7 @@ class Canvas { bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice - TextureHandler loader; // The ImageLoader that holds all our already loaded textures + // TextureHandler loader; // The ImageLoader that holds all our already loaded textures bool loopAround; // Whether our point buffer has looped back to the beginning this int monitorX, monitorY; // Monitor position for upper left corner double mouseX, mouseY; // Location of the mouse once HandleIO() has been called @@ -115,25 +115,25 @@ class Canvas { GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window unsigned proceduralBufferSize; doubleFunction scrollFunction; // Single function object for scrolling - GLtexture shaderFragment, // Address of the fragment shader - shaderProgram, // Addres of the shader program to send to the GPU - shaderVertex; // Address of the vertex shader + // GLtexture shaderFragment, // Address of the fragment shader + // shaderProgram, // Addres of the shader program to send to the GPU + // shaderVertex; // Address of the vertex shader std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread int syncMutexLocked; // Whether the syncMutex is currently locked int syncMutexOwner; // Thread ID of the owner of the syncMutex - GLtexture textureShaderFragment, // Address of the textured fragment shader - textureShaderProgram, // Addres of the textured shader program to send to the GPU - textureShaderVertex; // Address of the textured vertex shader + // GLtexture textureShaderFragment, // Address of the textured fragment shader + // textureShaderProgram, // Addres of the textured shader program to send to the GPU + // textureShaderVertex; // Address of the textured vertex shader bool toClose; // If the Canvas has been asked to close unsigned int toRecord; // To record the screen each frame GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - GLtexture vertexArray, // Address of GL's array buffer object - vertexBuffer; // Address of GL's vertex buffer object + // GLtexture vertexArray, // Address of GL's array buffer object + // vertexBuffer; // Address of GL's vertex buffer object float* vertexData; // The allPoints array GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not @@ -158,7 +158,7 @@ class Canvas { unsigned int b, std::string title, double timerLength); // Method for initializing the canvas void initGl(); // Initializes the GL things specific to the Canvas - void initGlew(); // Initialized the GLEW things specific to the Canvas + // void initGlew(); // Initialized the GLEW things specific to the Canvas static void initGlfw(); // Initalizes GLFW for all future canvases. void initWindow(); // Initalizes the window specific to the Canvas static void keyCallback(GLFWwindow* window, int key, @@ -173,11 +173,11 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void textureShaders(bool state); // Turn textures on or off - static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works - static bool testLine(Canvas& can); // Unit tester for lines + // void textureShaders(bool state); // Turn textures on or off + // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works + // static bool testLine(Canvas& can); // Unit tester for lines static bool testAccessors(Canvas& can); // Unit tester for accessor methods - static bool testDrawImage(Canvas& can); // Unit tester for drawing images (simultaneously a Unit test for Image) + // static bool testDrawImage(Canvas& can); // Unit tester for drawing images (simultaneously a Unit test for Image) protected: bool atiCard; // Whether the vendor of the graphics card is ATI @@ -194,7 +194,7 @@ class Canvas { void bindToScroll(std::function function); - void clearProcedural(); + // void clearProcedural(); void close(); @@ -204,149 +204,149 @@ class Canvas { void clearObjectBuffer(bool shouldFreeMemory = false); - virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow = false); + // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow = false); - virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow = false); + // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow = false); - virtual void drawCircle(int x, int y, int radius, ColorFloat color, bool filled = true); + // virtual void drawCircle(int x, int y, int radius, ColorFloat color, bool filled = true); - virtual void drawCircle(int x, int y, int radius, ColorFloat color[], bool filled = true); + // virtual void drawCircle(int x, int y, int radius, ColorFloat color[], bool filled = true); - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor); + // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor); - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor); + // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor); - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]); + // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]); - virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]); + // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawImage(std::string filename, int x, int y, int width, int height, float alpha = 1.0f, float rotation = 0); + // virtual void drawImage(std::string filename, int x, int y, int width, int height, float alpha = 1.0f, float rotation = 0); - virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color = BLACK, float rotation = 0); + // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color = BLACK, float rotation = 0); - virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation = 0); + // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation = 0); - virtual void drawPixel(int row, int col, ColorFloat color = BLACK); + // virtual void drawPixel(int row, int col, ColorFloat color = BLACK); - virtual void drawPoint(int x, int y, ColorFloat color = BLACK); + // virtual void drawPoint(int x, int y, ColorFloat color = BLACK); - virtual void drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation = 0); + // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation = 0); - virtual void drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation = 0); + // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation = 0); - virtual void drawProgress(ProgressBar* p); + // virtual void drawProgress(ProgressBar* p); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color = BLACK, bool filled = true, float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color = BLACK, bool filled = true, float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color, bool filled = true, bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color, bool filled = true, bool ninja = false, float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color[], bool filled = true, bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color[], bool filled = true, bool ninja = false, float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false, float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false, float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false, float rotation = 0); + // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - virtual void drawText(std::string text, int x, int y, unsigned size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); + // virtual void drawText(std::string text, int x, int y, unsigned size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - virtual void drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); + // virtual void drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); ColorFloat getBackgroundColor(); @@ -434,7 +434,7 @@ class Canvas { int wait(); - static void runTests(); + // static void runTests(); }; } diff --git a/src/TSGL/CartesianCanvas.cpp b/src/TSGL/CartesianCanvas.cpp index 5781fd781..fb2f0d617 100644 --- a/src/TSGL/CartesianCanvas.cpp +++ b/src/TSGL/CartesianCanvas.cpp @@ -40,1043 +40,1043 @@ CartesianCanvas::CartesianCanvas(int x, int y, int width, int height, Decimal xM recomputeDimensions(xMin, yMin, xMax, yMax); } - /*! - * \brief Draws axes on the Cartesian Canvas. - * \details This function draws axes (with tick marks) on the CartesianCanvas, centered at the - * given (Cartesian) coordinates - * \param originX The horizontal location of the y-axis line. - * \param originY The vertical location of the x-axis line. - * \param spacingX The distance between marks on the x-axis. - * \param spacingY The distance between marks on the y-axis. - */ -void CartesianCanvas::drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY) { - drawLine(maxX, originY, minX, originY); // Make the two axes - drawLine(originX, maxY, originX, minY); - - if (spacingX != 0.0) { - if (spacingX < 0.0) spacingX = -spacingX; - - for (Decimal x_ = originX + spacingX; x_ < maxX; x_ += spacingX) { - drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); - } - for (Decimal x_ = originX - spacingX; x_ > minX; x_ -= spacingX) { - drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); - } - } - if (spacingY != 0.0) { - if (spacingY < 0.0) spacingY = -spacingY; - - for (Decimal y_ = originY + spacingY; y_ < maxY; y_ += spacingY) { - drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); - } - for (Decimal y_ = originY - spacingY; y_ > minY; y_ -= spacingY) { - drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); - } - } -} - - /*! - * \brief Draws a circle with monocolored fill or outline. - * \details This function draws a circle with the given center, radius, color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color The color of the circle - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, color, filled); -} - - /*! - * \brief Draws a circle with multicolored fill or outline. - * \details This function draws a circle with the given center, radius, color, and fill status. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param color An array of colors for the circle - * \param filled Whether the circle should be filled - * (set to true by default). - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, color, filled); -} - - /*! - * \brief Draws a circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A color for the circle's fill. - * \param outlineColor A color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the circle's fill. - * \param outlineColor A color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor A color for the circle's fill. - * \param outlineColor An array of colors for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, coloring. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of color for the circle's fill. - * \param outlineColor An array of color for the circle's outline. - */ -void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX, actualY, actualR; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x+radius,y,actualR,actualY); - actualR -= actualX; - Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); -} - - /*! - * \brief Draws a Concave polygon with monocolored fill or outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param color A color for the said vertices. - * \param filled Whether the Concave polygon should be filled in or not - * (set to true by default). - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with multicolored fill or outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the Concave polygon should be filled in or not - * (set to true by default). - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with different monocolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor A color for the concave polygon's fill. - * \param outlineColor A color for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with multicolored fill and monocolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor An array of colors for the concave polygon's fill. - * \param outlineColor A color for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with monocolored fill and multicolored outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor A color for the concave polygon's fill. - * \param outlineColor An array of colors for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a Concave polygon with different multicolored fill and outline. - * \details This function draws a ConcavePolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of said vertices. - * \param yverts An array of y positions of said vertices. - * \param fillColor An array of colors for the concave polygon's fill. - * \param outlineColor An array of colors for the concave polygon's outline. - * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended - * that you draw Convex polygons with this function. - */ -void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with monocolored fill or outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param color A color for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with multicolored fill or outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param color An array of colors for the said vertices. - * \param filled Whether the ConvexPolygon should be filled in or not - * (set to true by default). - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with different monocolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor A color for the polygon's fill. - * \param outlineColor A color for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with multicolored fill and monocoloredoutline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor An array of colors for the polygon's fill. - * \param outlineColor A color for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with monocolored fill and multicolored outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor A color for the polygon's fill. - * \param outlineColor An array of colors for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws a convex polygon with different multicolored fill and outline. - * \details This function draws a ConvexPolygon with the given vertex data, specified as the - * outer perimeter of the polygon. - * \param size The number of vertices in the polygon. - * \param xverts An array of the x positions of said vertices. - * \param yverts An array of the y positions of said vertices. - * \param fillColor An array of colors for the polygon's fill. - * \param outlineColor An array of colors for the polygon's outline. - * \note The difference between a convex polygon and a concave polygon - * is that a convex polygon has all interior angles less than - * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). - */ -void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Plots a function on the screen. - * \details This function receives a TSGL Function instance as a parameter and plots the function on the CartesianCanvas. - * \param function Reference to the Function to plot. - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - */ -void CartesianCanvas::drawFunction(const Function &function, float sleepTime, ColorFloat color) { - if (sleepTime > 0.0f) { - bool first = true; - Decimal lastX, lastY, y; - for (Decimal x = minX; x < maxX; x += pixelWidth) { - if (!isOpen()) break; - y = function.valueAt(x); - if (!first) - drawLine(lastX,lastY,x,y,color); - first = false; - lastX = x; - lastY = y; - if (y > minY && y < maxY) //Don't waste time if it's offscreen - sleepFor(sleepTime); - } - } else { - int screenX = 0, screenY = 0; - int size = (maxX - minX) / pixelWidth; - Polyline *p = new Polyline(size); - Decimal x = minX; - for (int i = 0; i < size; ++i) { - getScreenCoordinates(x, function.valueAt(x), screenX, screenY); - p->addVertex(screenX, screenY, color); - x += pixelWidth; - } - drawDrawable(p); - } -} - - /*! - * \brief Plots a function on the screen. - * \details This function receives a pointer to a function method as a parameter and plots the function on - * the CartesianCanvas. - * \param function Pointer to the function-drawing method to plot. - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. - */ -void CartesianCanvas::drawFunction(functionPointer &function, float sleepTime, ColorFloat color) { - drawPartialFunction(function,minX,maxX,sleepTime,color); -} - - /*! - * \brief Draws an image. - * \details This function draws an Image with the given coordinates and dimensions. - * \param function The name of the file to load the image from. - * \param x The x coordinate of the Image's left edge. - * \param y The y coordinate of the Image's top edge. - * \param w The width of the Image. - * \param h The height of the Image. - * \param a The alpha with which to draw the Image - * (set to 1.0f by default). - * \note Identical to Canvas::drawImage(). - */ -void CartesianCanvas::drawImage(std::string function, Decimal x, Decimal y, Decimal w, Decimal h, float a) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x, y, actualX1, actualY1); - getScreenCoordinates(x + w, y - h, actualX2, actualY2); - - Canvas::drawImage(function, actualX1, actualY1, actualX2 - actualX1, actualY2 - actualY1, a); -} - - /*! - * \brief Draws a monocolored line. - * \details This function draws a Line at the given coordinates with the given color. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color The color of the line - * (set to BLACK by default). - * \note Identical to Canvas::drawLine(). - */ -void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - - Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); -} - - /*! - * \brief Draws a multicolored line. - * \details This function draws a Line at the given coordinates with the given coloring. - * \param x1 The x position of the start of the line. - * \param y1 The y position of the start of the line. - * \param x2 The x position of the end of the line. - * \param y2 The y position of the end of the line. - * \param color An array of colors of the line endpoints - * (set to BLACK by default). - * \note Identical to Canvas::drawLine(). - */ -void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]) { - int actualX1, actualY1, actualX2, actualY2; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - - Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); -} - - /*! - * \brief Plots part of a function on the screen. - * \details This function receives a pointer to a function method as a parameter and plots the function on - * the CartesianCanvas between the specified minimum and maximum coordinates. - * \param function Pointer to the function-drawing method to plot. - * \param min Minimum x value to evaluate and plot - * \param max Maximum x value to evaluate and plot - * \param sleepTime Time to sleep between plotting points - * \param color The color of the vertices of the plotted function (set to BLACK by default). - * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. - */ -void CartesianCanvas::drawPartialFunction(functionPointer &function, Decimal min, Decimal max, float sleepTime, ColorFloat color) { - if (sleepTime > 0.0f) { - bool first = true; - Decimal lastX, lastY, y; - for (Decimal x = min; x < max; x += pixelWidth) { - if (!isOpen()) break; - y = (function)(x); - if (!first) - drawLine(lastX,lastY,x,y,color); - first = false; - lastX = x; - lastY = y; - if (y > minY && y < maxY) //Don't waste time if it's offscreen - sleepFor(sleepTime); - } - } else { - int screenX = 0, screenY = 0; - int size = 1 + ceil((max - min) / pixelWidth); - Polyline *p = new Polyline(size); - Decimal x = min; - for (int i = 0; i < size; ++i) { - getScreenCoordinates(x, (function)(x), screenX, screenY); - p->addVertex(screenX, screenY, color); - x += pixelWidth; - } - drawDrawable(p); - } -} - - /*! - * \brief Draws a single pixel, specified in row,column format. - * \details This function draws a pixel at the given screen coordinates with the given color. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. - * \param row The row (y-position) of the pixel. - * \param col The column (x-position) of the pixel. - * \param color The color of the point (set to BLACK by default). - * \see drawPixel() - * \note Identical to Canvas::drawPixel(). - */ -void CartesianCanvas::drawPixel(Decimal row, Decimal col, ColorFloat color) { - drawPoint(col, row, color); -} - - /*! - * \brief Draws a single pixel, specified in x,y format. - * \details This function draws a pixel at the given Cartesian coordinates with the given color. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. - * \param x The x position of the point. - * \param y The y position of the point. - * \param color The color of the point (set to BLACK by default). - * \see drawPoint() - * \note Identical to Canvas::drawPoint(). - */ -void CartesianCanvas::drawPoint(Decimal x, Decimal y, ColorFloat color) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - if (atiCard) - Canvas::drawPoint(actualX, actualY-1, color); - else - Canvas::drawPoint(actualX, actualY, color); -} - - /*! - * \brief Draws a rectangle with monocolored fill or outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and color. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color The color of the rectangle - * (set to BLACK by default). - * \param filled Whether the rectangle should be filled - * (set to true by default). - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color, bool filled) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); -} - - /*! - * \brief Draws a rectangle with multicolored fill or outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param color An array of colors for the rectangle - * (set to BLACK by default). - * \param filled Whether the rectangle should be filled - * (set to true by default). - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); -} - - /*! - * \brief Draws a rectangle with different monocolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A color for the Rectangle's fill - * \param outlineColor A color for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with multicolored fill and monocolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor A color for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with monocolored fill and multicolored outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor A color for the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draws a rectangle with different multicolored fill and outline. - * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's BOTTOM edge. - * \param w The Rectangle's width. - * \param h The Rectangle's height. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. - */ -void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX, actualY, actualX2, actualY2; - getScreenCoordinates(x, y, actualX, actualY); - getScreenCoordinates(x + w, y + h, actualX2, actualY2); - Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \paramtexts The string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \note Identical to Canvas::drawText(std::string,..). - */ -void CartesianCanvas::drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - Canvas::drawText(text, actualX, actualY, size, color, fontFileName); -} - - /*! - * \brief Draw a string of text. - * \details This function draws a given string of Text at the given coordinates with the given color. - * \param text The UTF8-encoded string to draw. - * \param x The x coordinate of the text's left bound. - * \param y The y coordinate of the text's left bound. - * \param size The size of the text in pixels. - * \param color The color of the Text (set to BLACK by default). - * \note Identical to Canvas::drawText(std::wstring,..). - */ -void CartesianCanvas::drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { - int actualX, actualY; - getScreenCoordinates(x, y, actualX, actualY); - - Canvas::drawText(text, actualX, actualY, size, color, fontFileName); -} - - /*! - * \brief Draw a triangle with monocolored fill or outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color A color for the Triangle (set to BLACK by default). - * \param filled Whether the Triangle should be filled (set to true by default). - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color, bool filled) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); -} - - /*! - * \brief Draw a triangle with multicolored fill or outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param color An array of colors for the Triangle. - * \param filled Whether the Triangle should be filled (set to true by default). - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); -} - - /*! - * \brief Draw a triangle with different monocolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A color for the Triangle's fill. - * \param outlineColor A color for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with multicolored fill and monocolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor A color for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with monocolored fill and multicolored outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor A color for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draw a triangle with different multicolored fill and outline. - * \details This function draws a Triangle with the given vertices. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - */ -void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]) { - int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; - getScreenCoordinates(x1, y1, actualX1, actualY1); - getScreenCoordinates(x2, y2, actualX2, actualY2); - getScreenCoordinates(x3, y3, actualX3, actualY3); - Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); -} - - /*! - * \brief Draws an arbitrary triangle strip with monocolored fill or outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param color A color for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false) - * (set to true by default). - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with multicolored fill or outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param color An array of colors for the vertices. - * \param filled Whether the triangle strip should be filled (true) or not (false) - * (set to true by default). - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with different monocolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor A color for the triangle strip's fill. - * \param outlineColor A color for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with multicolored fill and monocolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor An array of colors for the triangle strip's fill. - * \param outlineColor A color for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with monocolored fill and multicolored outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor A color for the triangle strip's fill. - * \param outlineColor An array of colors for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} - - /*! - * \brief Draws an arbitrary triangle strip with different multicolored fill and outline. - * \details This function draws a TriangleStrip with the given vertex data, specified as - * a triangle strip. - * \param size The number of vertices in the polygon. - * \param xverts An array of x positions of the vertices. - * \param yverts An array of y positions of the vertices. - * \param fillColor An array of colors for the triangle strip's fill. - * \param outlineColor An array of colors for the triangle strip's outline. - */ -void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { - int* int_x = new int[size]; - int* int_y = new int[size]; - - for (int i = 0; i < size; i++) { - getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); - } - Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); - - delete int_x; - delete int_y; -} +// /*! +// * \brief Draws axes on the Cartesian Canvas. +// * \details This function draws axes (with tick marks) on the CartesianCanvas, centered at the +// * given (Cartesian) coordinates +// * \param originX The horizontal location of the y-axis line. +// * \param originY The vertical location of the x-axis line. +// * \param spacingX The distance between marks on the x-axis. +// * \param spacingY The distance between marks on the y-axis. +// */ +// void CartesianCanvas::drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY) { +// drawLine(maxX, originY, minX, originY); // Make the two axes +// drawLine(originX, maxY, originX, minY); + +// if (spacingX != 0.0) { +// if (spacingX < 0.0) spacingX = -spacingX; + +// for (Decimal x_ = originX + spacingX; x_ < maxX; x_ += spacingX) { +// drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); +// } +// for (Decimal x_ = originX - spacingX; x_ > minX; x_ -= spacingX) { +// drawLine(x_, originY + 8 * pixelHeight, x_, originY - 8 * pixelHeight); +// } +// } +// if (spacingY != 0.0) { +// if (spacingY < 0.0) spacingY = -spacingY; + +// for (Decimal y_ = originY + spacingY; y_ < maxY; y_ += spacingY) { +// drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); +// } +// for (Decimal y_ = originY - spacingY; y_ > minY; y_ -= spacingY) { +// drawLine(originX + 8 * pixelWidth, y_, originX - 8 * pixelWidth, y_); +// } +// } +// } + +// /*! +// * \brief Draws a circle with monocolored fill or outline. +// * \details This function draws a circle with the given center, radius, color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param color The color of the circle +// * \param filled Whether the circle should be filled +// * (set to true by default). +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, color, filled); +// } + +// /*! +// * \brief Draws a circle with multicolored fill or outline. +// * \details This function draws a circle with the given center, radius, color, and fill status. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param color An array of colors for the circle +// * \param filled Whether the circle should be filled +// * (set to true by default). +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, color, filled); +// } + +// /*! +// * \brief Draws a circle with different monocolored fill and outline. +// * \details This function draws a circle with the given center, radius, coloring. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor A color for the circle's fill. +// * \param outlineColor A color for the circle's outline. +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a circle with multicolored fill and monocolored outline. +// * \details This function draws a circle with the given center, radius, coloring. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor An array of colors for the circle's fill. +// * \param outlineColor A color for the circle's outline. +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a circle with monocolored fill and multicolored outline. +// * \details This function draws a circle with the given center, radius, coloring. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor A color for the circle's fill. +// * \param outlineColor An array of colors for the circle's outline. +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a circle with different multicolored fill and outline. +// * \details This function draws a circle with the given center, radius, coloring. +// * \param x The x coordinate of the circle's center. +// * \param y The y coordinate of the circle's center. +// * \param radius The radius of the circle in pixels. +// * \param fillColor An array of color for the circle's fill. +// * \param outlineColor An array of color for the circle's outline. +// */ +// void CartesianCanvas::drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int actualX, actualY, actualR; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x+radius,y,actualR,actualY); +// actualR -= actualX; +// Canvas::drawCircle(actualX, actualY, actualR, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a Concave polygon with monocolored fill or outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param color A color for the said vertices. +// * \param filled Whether the Concave polygon should be filled in or not +// * (set to true by default). +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a Concave polygon with multicolored fill or outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param color An array of colors for the said vertices. +// * \param filled Whether the Concave polygon should be filled in or not +// * (set to true by default). +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a Concave polygon with different monocolored fill and outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param fillColor A color for the concave polygon's fill. +// * \param outlineColor A color for the concave polygon's outline. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a Concave polygon with multicolored fill and monocolored outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param fillColor An array of colors for the concave polygon's fill. +// * \param outlineColor A color for the concave polygon's outline. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a Concave polygon with monocolored fill and multicolored outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param fillColor A color for the concave polygon's fill. +// * \param outlineColor An array of colors for the concave polygon's outline. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a Concave polygon with different multicolored fill and outline. +// * \details This function draws a ConcavePolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of said vertices. +// * \param yverts An array of y positions of said vertices. +// * \param fillColor An array of colors for the concave polygon's fill. +// * \param outlineColor An array of colors for the concave polygon's outline. +// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended +// * that you draw Convex polygons with this function. +// */ +// void CartesianCanvas::drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConcavePolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with monocolored fill or outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param color A color for the said vertices. +// * \param filled Whether the ConvexPolygon should be filled in or not +// * (set to true by default). +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with multicolored fill or outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param color An array of colors for the said vertices. +// * \param filled Whether the ConvexPolygon should be filled in or not +// * (set to true by default). +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with different monocolored fill and outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param fillColor A color for the polygon's fill. +// * \param outlineColor A color for the polygon's outline. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with multicolored fill and monocoloredoutline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param fillColor An array of colors for the polygon's fill. +// * \param outlineColor A color for the polygon's outline. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with monocolored fill and multicolored outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param fillColor A color for the polygon's fill. +// * \param outlineColor An array of colors for the polygon's outline. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws a convex polygon with different multicolored fill and outline. +// * \details This function draws a ConvexPolygon with the given vertex data, specified as the +// * outer perimeter of the polygon. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of the x positions of said vertices. +// * \param yverts An array of the y positions of said vertices. +// * \param fillColor An array of colors for the polygon's fill. +// * \param outlineColor An array of colors for the polygon's outline. +// * \note The difference between a convex polygon and a concave polygon +// * is that a convex polygon has all interior angles less than +// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). +// */ +// void CartesianCanvas::drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawConvexPolygon(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Plots a function on the screen. +// * \details This function receives a TSGL Function instance as a parameter and plots the function on the CartesianCanvas. +// * \param function Reference to the Function to plot. +// * \param sleepTime Time to sleep between plotting points +// * \param color The color of the vertices of the plotted function (set to BLACK by default). +// */ +// void CartesianCanvas::drawFunction(const Function &function, float sleepTime, ColorFloat color) { +// if (sleepTime > 0.0f) { +// bool first = true; +// Decimal lastX, lastY, y; +// for (Decimal x = minX; x < maxX; x += pixelWidth) { +// if (!isOpen()) break; +// y = function.valueAt(x); +// if (!first) +// drawLine(lastX,lastY,x,y,color); +// first = false; +// lastX = x; +// lastY = y; +// if (y > minY && y < maxY) //Don't waste time if it's offscreen +// sleepFor(sleepTime); +// } +// } else { +// int screenX = 0, screenY = 0; +// int size = (maxX - minX) / pixelWidth; +// Polyline *p = new Polyline(size); +// Decimal x = minX; +// for (int i = 0; i < size; ++i) { +// getScreenCoordinates(x, function.valueAt(x), screenX, screenY); +// p->addVertex(screenX, screenY, color); +// x += pixelWidth; +// } +// drawDrawable(p); +// } +// } + +// /*! +// * \brief Plots a function on the screen. +// * \details This function receives a pointer to a function method as a parameter and plots the function on +// * the CartesianCanvas. +// * \param function Pointer to the function-drawing method to plot. +// * \param sleepTime Time to sleep between plotting points +// * \param color The color of the vertices of the plotted function (set to BLACK by default). +// * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. +// */ +// void CartesianCanvas::drawFunction(functionPointer &function, float sleepTime, ColorFloat color) { +// drawPartialFunction(function,minX,maxX,sleepTime,color); +// } + +// /*! +// * \brief Draws an image. +// * \details This function draws an Image with the given coordinates and dimensions. +// * \param function The name of the file to load the image from. +// * \param x The x coordinate of the Image's left edge. +// * \param y The y coordinate of the Image's top edge. +// * \param w The width of the Image. +// * \param h The height of the Image. +// * \param a The alpha with which to draw the Image +// * (set to 1.0f by default). +// * \note Identical to Canvas::drawImage(). +// */ +// void CartesianCanvas::drawImage(std::string function, Decimal x, Decimal y, Decimal w, Decimal h, float a) { +// int actualX1, actualY1, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX1, actualY1); +// getScreenCoordinates(x + w, y - h, actualX2, actualY2); + +// Canvas::drawImage(function, actualX1, actualY1, actualX2 - actualX1, actualY2 - actualY1, a); +// } + +// /*! +// * \brief Draws a monocolored line. +// * \details This function draws a Line at the given coordinates with the given color. +// * \param x1 The x position of the start of the line. +// * \param y1 The y position of the start of the line. +// * \param x2 The x position of the end of the line. +// * \param y2 The y position of the end of the line. +// * \param color The color of the line +// * (set to BLACK by default). +// * \note Identical to Canvas::drawLine(). +// */ +// void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color) { +// int actualX1, actualY1, actualX2, actualY2; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); + +// Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); +// } + +// /*! +// * \brief Draws a multicolored line. +// * \details This function draws a Line at the given coordinates with the given coloring. +// * \param x1 The x position of the start of the line. +// * \param y1 The y position of the start of the line. +// * \param x2 The x position of the end of the line. +// * \param y2 The y position of the end of the line. +// * \param color An array of colors of the line endpoints +// * (set to BLACK by default). +// * \note Identical to Canvas::drawLine(). +// */ +// void CartesianCanvas::drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]) { +// int actualX1, actualY1, actualX2, actualY2; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); + +// Canvas::drawLine(actualX1, actualY1, actualX2, actualY2, color); +// } + +// /*! +// * \brief Plots part of a function on the screen. +// * \details This function receives a pointer to a function method as a parameter and plots the function on +// * the CartesianCanvas between the specified minimum and maximum coordinates. +// * \param function Pointer to the function-drawing method to plot. +// * \param min Minimum x value to evaluate and plot +// * \param max Maximum x value to evaluate and plot +// * \param sleepTime Time to sleep between plotting points +// * \param color The color of the vertices of the plotted function (set to BLACK by default). +// * \note function must receive exactly one Decimal x parameter, and return a Decimal y parameter. +// */ +// void CartesianCanvas::drawPartialFunction(functionPointer &function, Decimal min, Decimal max, float sleepTime, ColorFloat color) { +// if (sleepTime > 0.0f) { +// bool first = true; +// Decimal lastX, lastY, y; +// for (Decimal x = min; x < max; x += pixelWidth) { +// if (!isOpen()) break; +// y = (function)(x); +// if (!first) +// drawLine(lastX,lastY,x,y,color); +// first = false; +// lastX = x; +// lastY = y; +// if (y > minY && y < maxY) //Don't waste time if it's offscreen +// sleepFor(sleepTime); +// } +// } else { +// int screenX = 0, screenY = 0; +// int size = 1 + ceil((max - min) / pixelWidth); +// Polyline *p = new Polyline(size); +// Decimal x = min; +// for (int i = 0; i < size; ++i) { +// getScreenCoordinates(x, (function)(x), screenX, screenY); +// p->addVertex(screenX, screenY, color); +// x += pixelWidth; +// } +// drawDrawable(p); +// } +// } + +// /*! +// * \brief Draws a single pixel, specified in row,column format. +// * \details This function draws a pixel at the given screen coordinates with the given color. +// * \note (0,0) signifies the top-left of the screen when working with a Canvas object. +// * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. +// * \param row The row (y-position) of the pixel. +// * \param col The column (x-position) of the pixel. +// * \param color The color of the point (set to BLACK by default). +// * \see drawPixel() +// * \note Identical to Canvas::drawPixel(). +// */ +// void CartesianCanvas::drawPixel(Decimal row, Decimal col, ColorFloat color) { +// drawPoint(col, row, color); +// } + +// /*! +// * \brief Draws a single pixel, specified in x,y format. +// * \details This function draws a pixel at the given Cartesian coordinates with the given color. +// * \note (0,0) signifies the left-top of the screen when working with a Canvas object. +// * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. +// * \param x The x position of the point. +// * \param y The y position of the point. +// * \param color The color of the point (set to BLACK by default). +// * \see drawPoint() +// * \note Identical to Canvas::drawPoint(). +// */ +// void CartesianCanvas::drawPoint(Decimal x, Decimal y, ColorFloat color) { +// int actualX, actualY; +// getScreenCoordinates(x, y, actualX, actualY); + +// if (atiCard) +// Canvas::drawPoint(actualX, actualY-1, color); +// else +// Canvas::drawPoint(actualX, actualY, color); +// } + +// /*! +// * \brief Draws a rectangle with monocolored fill or outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param color The color of the rectangle +// * (set to BLACK by default). +// * \param filled Whether the rectangle should be filled +// * (set to true by default). +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color, bool filled) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); +// } + +// /*! +// * \brief Draws a rectangle with multicolored fill or outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param color An array of colors for the rectangle +// * (set to BLACK by default). +// * \param filled Whether the rectangle should be filled +// * (set to true by default). +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY- actualY2, color, filled); +// } + +// /*! +// * \brief Draws a rectangle with different monocolored fill and outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor A color for the Rectangle's fill +// * \param outlineColor A color for the Rectangle's outline +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a rectangle with multicolored fill and monocolored outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor An array of colors for the Rectangle's fill +// * \param outlineColor A color for the Rectangle's outline +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a rectangle with monocolored fill and multicolored outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor A color for the Rectangle's fill +// * \param outlineColor An array of colors for the Rectangle's outline +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws a rectangle with different multicolored fill and outline. +// * \details This function draws a Rectangle with the given coordinates, dimensions, and coloring. +// * \param x The x coordinate of the Rectangle's left edge. +// * \param y The y coordinate of the Rectangle's BOTTOM edge. +// * \param w The Rectangle's width. +// * \param h The Rectangle's height. +// * \param fillColor An array of colors for the Rectangle's fill +// * \param outlineColor An array of colors for the Rectangle's outline +// * \warning This method's x and y parameters are NOT the same as the x and y of Canvas::drawRectangle. +// */ +// void CartesianCanvas::drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int actualX, actualY, actualX2, actualY2; +// getScreenCoordinates(x, y, actualX, actualY); +// getScreenCoordinates(x + w, y + h, actualX2, actualY2); +// Canvas::drawRectangle(actualX, actualY, actualX2 - actualX, actualY2 - actualY, fillColor, outlineColor); +// } + +// /*! +// * \brief Draw a string of text. +// * \details This function draws a given string of Text at the given coordinates with the given color. +// * \paramtexts The string to draw. +// * \param x The x coordinate of the text's left bound. +// * \param y The y coordinate of the text's left bound. +// * \param size The size of the text in pixels. +// * \param color The color of the Text (set to BLACK by default). +// * \note Identical to Canvas::drawText(std::string,..). +// */ +// void CartesianCanvas::drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { +// int actualX, actualY; +// getScreenCoordinates(x, y, actualX, actualY); + +// Canvas::drawText(text, actualX, actualY, size, color, fontFileName); +// } + +// /*! +// * \brief Draw a string of text. +// * \details This function draws a given string of Text at the given coordinates with the given color. +// * \param text The UTF8-encoded string to draw. +// * \param x The x coordinate of the text's left bound. +// * \param y The y coordinate of the text's left bound. +// * \param size The size of the text in pixels. +// * \param color The color of the Text (set to BLACK by default). +// * \note Identical to Canvas::drawText(std::wstring,..). +// */ +// void CartesianCanvas::drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color, const std::string& fontFileName) { +// int actualX, actualY; +// getScreenCoordinates(x, y, actualX, actualY); + +// Canvas::drawText(text, actualX, actualY, size, color, fontFileName); +// } + +// /*! +// * \brief Draw a triangle with monocolored fill or outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param color A color for the Triangle (set to BLACK by default). +// * \param filled Whether the Triangle should be filled (set to true by default). +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color, bool filled) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); +// } + +// /*! +// * \brief Draw a triangle with multicolored fill or outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param color An array of colors for the Triangle. +// * \param filled Whether the Triangle should be filled (set to true by default). +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, color, filled); +// } + +// /*! +// * \brief Draw a triangle with different monocolored fill and outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor A color for the Triangle's fill. +// * \param outlineColor A color for the Triangle's outline. +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); +// } + +// /*! +// * \brief Draw a triangle with multicolored fill and monocolored outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor An array of colors for the Triangle's fill. +// * \param outlineColor A color for the Triangle's outline. +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); +// } + +// /*! +// * \brief Draw a triangle with monocolored fill and multicolored outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor A color for the Triangle's fill. +// * \param outlineColor An array of colors for the Triangle's outline. +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); +// } + +// /*! +// * \brief Draw a triangle with different multicolored fill and outline. +// * \details This function draws a Triangle with the given vertices. +// * \param x1 The x coordinate of the first vertex of the Triangle. +// * \param y1 The y coordinate of the first vertex of the Triangle. +// * \param x2 The x coordinate of the second vertex of the Triangle. +// * \param y2 The y coordinate of the second vertex of the Triangle. +// * \param x3 The x coordinate of the third vertex of the Triangle. +// * \param y3 The y coordinate of the third vertex of the Triangle. +// * \param fillColor An array of colors for the Triangle's fill. +// * \param outlineColor An array of colors for the Triangle's outline. +// */ +// void CartesianCanvas::drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int actualX1, actualY1, actualX2, actualY2, actualX3, actualY3; +// getScreenCoordinates(x1, y1, actualX1, actualY1); +// getScreenCoordinates(x2, y2, actualX2, actualY2); +// getScreenCoordinates(x3, y3, actualX3, actualY3); +// Canvas::drawTriangle(actualX1, actualY1, actualX2, actualY2, actualX3, actualY3, fillColor, outlineColor); +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with monocolored fill or outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param color A color for the vertices. +// * \param filled Whether the triangle strip should be filled (true) or not (false) +// * (set to true by default). +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with multicolored fill or outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param color An array of colors for the vertices. +// * \param filled Whether the triangle strip should be filled (true) or not (false) +// * (set to true by default). +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, color, filled); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with different monocolored fill and outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param fillColor A color for the triangle strip's fill. +// * \param outlineColor A color for the triangle strip's outline. +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with multicolored fill and monocolored outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param fillColor An array of colors for the triangle strip's fill. +// * \param outlineColor A color for the triangle strip's outline. +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with monocolored fill and multicolored outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param fillColor A color for the triangle strip's fill. +// * \param outlineColor An array of colors for the triangle strip's outline. +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } + +// /*! +// * \brief Draws an arbitrary triangle strip with different multicolored fill and outline. +// * \details This function draws a TriangleStrip with the given vertex data, specified as +// * a triangle strip. +// * \param size The number of vertices in the polygon. +// * \param xverts An array of x positions of the vertices. +// * \param yverts An array of y positions of the vertices. +// * \param fillColor An array of colors for the triangle strip's fill. +// * \param outlineColor An array of colors for the triangle strip's outline. +// */ +// void CartesianCanvas::drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]) { +// int* int_x = new int[size]; +// int* int_y = new int[size]; + +// for (int i = 0; i < size; i++) { +// getScreenCoordinates(xverts[i], yverts[i], int_x[i], int_y[i]); +// } +// Canvas::drawTriangleStrip(size, int_x, int_y, fillColor, outlineColor); + +// delete int_x; +// delete int_y; +// } /*! * \brief Translates Cartesian coordinates into window coordinates. @@ -1324,229 +1324,229 @@ void CartesianCanvas::zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2) { /*! * \brief Runs the Unit tests for CartesianCanvas. */ -void CartesianCanvas::runTests() { - TsglDebug("Testing CartesianCanvas class..."); - CartesianCanvas c1(0.0f); - c1.setBackgroundColor(WHITE); - c1.start(); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - tsglAssert(testZoom(c1), "Unit test for zoom() functions failed!"); - tsglAssert(testRecomputeDimensions(c1), "Unit test for recomputing dimensions failed!"); - c1.stop(); - - CartesianCanvas c2(-1, -1, 800, 600, -1, -1, 3, 2,""); - c2.setBackgroundColor(WHITE); - c2.start(); - tsglAssert(testDraw(c2), "Unit test for drawing functions failed!"); - c2.wait(); - - TsglDebug("Unit tests for CartesianCanvas complete."); -} - -bool CartesianCanvas::testDraw(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - - float pw = can.getPixelWidth(); - float ph = can.getPixelHeight(); - - //Test 1: Physical to Cartesian point mapping - can.drawPoint(-1.0f,-1.0f,BLACK); //outer bottomleft - can.drawPoint(3.0f,-1.0f,BLACK); //outer bottomright - can.drawPoint(-1.0f,2.0f,BLACK); //outer topleft - can.drawPoint(3.0f,2.0f,BLACK); //outer topright - can.drawPoint(0.0f,0.0f,BLACK); //1/4 over, 1/3 down (origin) - - can.drawPoint(-1.0f+pw,-1.0f+ph,BLACK); //inner bottomleft - can.drawPoint(3.0f-pw,-1.0f+ph,BLACK); //inner bottomright - can.drawPoint(-1.0f+pw,2.0f-ph,BLACK); //inner topleft - can.drawPoint(3.0f-pw,2.0f-ph,BLACK); //inner topright - can.sleepFor(1.0f); - - if(can.getPoint(200,399).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, origin pixel for testDraw() failed!"); - } - if(can.getPoint(0,0).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer topleft pixel for testDraw() failed!"); - } - if(can.getPoint(799,0).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer topright pixel for testDraw() failed!"); - } - if(can.getPoint(0,599).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer bottomleft pixel for testDraw() failed!"); - } - if(can.getPoint(799,599).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, outer bottomright pixel for testDraw() failed!"); - } - - if(can.getPoint(1,1).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner topleft pixel for testDraw() failed!"); - } - if(can.getPoint(798,1).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner topright pixel for testDraw() failed!"); - } - if(can.getPoint(1,598).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner bottomleft pixel for testDraw() failed!"); - } - if(can.getPoint(798,598).R == 0) { - passed++; - } else { - failed++; - TsglErr("Test 1, inner bottomright pixel for testDraw() failed!"); - } - - //Results: - if(failed == 0) { - TsglDebug("Unit test for drawing passed!"); - return true; - } else { - TsglErr("This many passed for testDraw(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testDraw(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool CartesianCanvas::testZoom(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - //Test 1: Zooming out - //Had to use round() because there was a floating-point error that - //propagated to the rest of the tests after the first two - can.zoom(0, 0, 1.5); - if(round(can.getCartWidth()) == 1200 && round(can.getCartHeight()) == 900) { - passed++; - } else { - failed++; - TsglErr("Test 1, Zooming out for testZoom() failed!"); - } - - //Test 2: Zooming in - can.zoom(0, 0, .5); - if(round(can.getCartWidth()) == 600 && round(can.getCartHeight()) == 450) { - passed++; - } else { - failed++; - TsglErr("Test 2, Zooming in for testZoom() failed!"); - } - - //Test 3: Zooming out/in on a different point - - //Zooming out.... - can.zoom(10, 10, 1.2); - if(round(can.getCartWidth()) == 720 && round(can.getCartHeight()) == 540) { - passed++; - } else { - failed++; - TsglErr("Test 3, Zooming out on a different point for testZoom() failed!"); - } - - //Zooming in.... - can.zoom(15, 20, .9); - if(round(can.getCartWidth()) == 648 && round(can.getCartHeight()) == 486) { - passed++; - } else { - failed++; - TsglErr("Test 3, Zooming in on a different point for testZoom() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - TsglDebug("Unit test for zooming in & out passed!"); - return true; - } else { - TsglErr("This many passed for testZoom(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testZoom(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool CartesianCanvas::testRecomputeDimensions(CartesianCanvas& can) { - int passed = 0; - int failed = 0; - Decimal xMin, xMax; - Decimal yMin, yMax; - //Test 1: Positive values only (with 0.0) - xMin = 0.0; - xMax = 500.0; - yMin = 0.0; - yMax = 500.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - if(can.getCartWidth() == 500.0 && can.getCartHeight() == 500.0) { - passed++; - } else { - failed++; - TsglErr("Test 1, Positive values only for testRecomputeDimensions() failed!"); - } - - //Test 2: Negative values included - xMin = xMax = yMin = yMax = 0.0; - xMin = -300.0; - xMax = 900.0; - yMin = -500.0; - yMax = 1000.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - - if(can.getCartWidth() == 1200.0 && can.getCartHeight() == 1500.0) { - passed++; - } else { - failed++; - TsglErr("Test 2, Negative values for testRecomputeDimensions() failed!"); - } - - //Test 3: Same as Test 2, but negative values are max - xMin = xMax = yMin = yMax = 0.0; - xMin = -900.0; - xMax = -100.0; - yMin = -800.0; - yMax = -50.0; - can.recomputeDimensions(xMin, yMin, xMax, yMax); - - if(can.getCartWidth() == 800.0 && can.getCartHeight() == 750.0) { - passed++; - } else { - failed++; - TsglErr("Test 3, Max negative values for testRecomputeDimensions() failed!"); - } - - if(passed == 3 && failed == 0) { - TsglDebug("Unit test for recomputing dimensions passed!"); - return true; - } else { - TsglErr("This many tests passed for testRecomputeDimensions(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests failed for testRecomputeDimensions(): "); - std::cout << " " << failed << std::endl; - return false; - } -} +// void CartesianCanvas::runTests() { +// TsglDebug("Testing CartesianCanvas class..."); +// CartesianCanvas c1(0.0f); +// c1.setBackgroundColor(WHITE); +// c1.start(); + +// std::this_thread::sleep_for(std::chrono::seconds(1)); +// tsglAssert(testZoom(c1), "Unit test for zoom() functions failed!"); +// tsglAssert(testRecomputeDimensions(c1), "Unit test for recomputing dimensions failed!"); +// c1.stop(); + +// CartesianCanvas c2(-1, -1, 800, 600, -1, -1, 3, 2,""); +// c2.setBackgroundColor(WHITE); +// c2.start(); +// tsglAssert(testDraw(c2), "Unit test for drawing functions failed!"); +// c2.wait(); + +// TsglDebug("Unit tests for CartesianCanvas complete."); +// } + +// bool CartesianCanvas::testDraw(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; + +// float pw = can.getPixelWidth(); +// float ph = can.getPixelHeight(); + +// //Test 1: Physical to Cartesian point mapping +// can.drawPoint(-1.0f,-1.0f,BLACK); //outer bottomleft +// can.drawPoint(3.0f,-1.0f,BLACK); //outer bottomright +// can.drawPoint(-1.0f,2.0f,BLACK); //outer topleft +// can.drawPoint(3.0f,2.0f,BLACK); //outer topright +// can.drawPoint(0.0f,0.0f,BLACK); //1/4 over, 1/3 down (origin) + +// can.drawPoint(-1.0f+pw,-1.0f+ph,BLACK); //inner bottomleft +// can.drawPoint(3.0f-pw,-1.0f+ph,BLACK); //inner bottomright +// can.drawPoint(-1.0f+pw,2.0f-ph,BLACK); //inner topleft +// can.drawPoint(3.0f-pw,2.0f-ph,BLACK); //inner topright +// can.sleepFor(1.0f); + +// if(can.getPoint(200,399).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, origin pixel for testDraw() failed!"); +// } +// if(can.getPoint(0,0).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer topleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(799,0).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer topright pixel for testDraw() failed!"); +// } +// if(can.getPoint(0,599).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer bottomleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(799,599).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, outer bottomright pixel for testDraw() failed!"); +// } + +// if(can.getPoint(1,1).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner topleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(798,1).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner topright pixel for testDraw() failed!"); +// } +// if(can.getPoint(1,598).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner bottomleft pixel for testDraw() failed!"); +// } +// if(can.getPoint(798,598).R == 0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, inner bottomright pixel for testDraw() failed!"); +// } + +// //Results: +// if(failed == 0) { +// TsglDebug("Unit test for drawing passed!"); +// return true; +// } else { +// TsglErr("This many passed for testDraw(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many failed for testDraw(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } + +// bool CartesianCanvas::testZoom(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; +// //Test 1: Zooming out +// //Had to use round() because there was a floating-point error that +// //propagated to the rest of the tests after the first two +// can.zoom(0, 0, 1.5); +// if(round(can.getCartWidth()) == 1200 && round(can.getCartHeight()) == 900) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Zooming out for testZoom() failed!"); +// } + +// //Test 2: Zooming in +// can.zoom(0, 0, .5); +// if(round(can.getCartWidth()) == 600 && round(can.getCartHeight()) == 450) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, Zooming in for testZoom() failed!"); +// } + +// //Test 3: Zooming out/in on a different point + +// //Zooming out.... +// can.zoom(10, 10, 1.2); +// if(round(can.getCartWidth()) == 720 && round(can.getCartHeight()) == 540) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Zooming out on a different point for testZoom() failed!"); +// } + +// //Zooming in.... +// can.zoom(15, 20, .9); +// if(round(can.getCartWidth()) == 648 && round(can.getCartHeight()) == 486) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Zooming in on a different point for testZoom() failed!"); +// } + +// //Results: +// if(passed == 4 && failed == 0) { +// TsglDebug("Unit test for zooming in & out passed!"); +// return true; +// } else { +// TsglErr("This many passed for testZoom(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many failed for testZoom(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } + +// bool CartesianCanvas::testRecomputeDimensions(CartesianCanvas& can) { +// int passed = 0; +// int failed = 0; +// Decimal xMin, xMax; +// Decimal yMin, yMax; +// //Test 1: Positive values only (with 0.0) +// xMin = 0.0; +// xMax = 500.0; +// yMin = 0.0; +// yMax = 500.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); +// if(can.getCartWidth() == 500.0 && can.getCartHeight() == 500.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Positive values only for testRecomputeDimensions() failed!"); +// } + +// //Test 2: Negative values included +// xMin = xMax = yMin = yMax = 0.0; +// xMin = -300.0; +// xMax = 900.0; +// yMin = -500.0; +// yMax = 1000.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); + +// if(can.getCartWidth() == 1200.0 && can.getCartHeight() == 1500.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 2, Negative values for testRecomputeDimensions() failed!"); +// } + +// //Test 3: Same as Test 2, but negative values are max +// xMin = xMax = yMin = yMax = 0.0; +// xMin = -900.0; +// xMax = -100.0; +// yMin = -800.0; +// yMax = -50.0; +// can.recomputeDimensions(xMin, yMin, xMax, yMax); + +// if(can.getCartWidth() == 800.0 && can.getCartHeight() == 750.0) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 3, Max negative values for testRecomputeDimensions() failed!"); +// } + +// if(passed == 3 && failed == 0) { +// TsglDebug("Unit test for recomputing dimensions passed!"); +// return true; +// } else { +// TsglErr("This many tests passed for testRecomputeDimensions(): "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many tests failed for testRecomputeDimensions(): "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } //-----------------End Unit testing---------------------------------------------------- } diff --git a/src/TSGL/CartesianCanvas.h b/src/TSGL/CartesianCanvas.h index 258c81bfd..1c989e251 100644 --- a/src/TSGL/CartesianCanvas.h +++ b/src/TSGL/CartesianCanvas.h @@ -27,109 +27,109 @@ class CartesianCanvas : public Canvas { Decimal minX, maxX, minY, maxY; // Bounding Cartesian coordinates for the window Decimal pixelWidth, pixelHeight; // cartWidth/window.w(), cartHeight/window.h() - static bool testZoom(CartesianCanvas& can); // Unit test for zoom() methods - static bool testRecomputeDimensions(CartesianCanvas& can); // Unit test for recomputeDimensions() - static bool testDraw(CartesianCanvas& can); // Unit test for drawing + // static bool testZoom(CartesianCanvas& can); // Unit test for zoom() methods + // static bool testRecomputeDimensions(CartesianCanvas& can); // Unit test for recomputeDimensions() + // static bool testDraw(CartesianCanvas& can); // Unit test for drawing public: CartesianCanvas(double timerLength = 0.0); CartesianCanvas(int x, int y, int width, int height, Decimal xMin, Decimal yMin, Decimal xMax, Decimal yMax, std::string t, double timerLength = 0.0); - void drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY); + // void drawAxes(Decimal originX, Decimal originY, Decimal spacingX, Decimal spacingY); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled = true); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color, bool filled = true); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled = true); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat color[], bool filled = true); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor, ColorFloat outlineColor[]); - void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawCircle(Decimal x, Decimal y, Decimal radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawConcavePolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawConvexPolygon(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); - void drawFunction(const Function &function, float sleepTime = 0.0f, ColorFloat color = BLACK); + // void drawFunction(const Function &function, float sleepTime = 0.0f, ColorFloat color = BLACK); - void drawFunction(functionPointer &function, float sleepTime = 0.0f, ColorFloat color = BLACK); + // void drawFunction(functionPointer &function, float sleepTime = 0.0f, ColorFloat color = BLACK); - void drawImage(std::string filename, Decimal x, Decimal y, Decimal w, Decimal h, float a = 1.0f); + // void drawImage(std::string filename, Decimal x, Decimal y, Decimal w, Decimal h, float a = 1.0f); - void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color = BLACK); + // void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color = BLACK); - void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]); + // void drawLine(Decimal x1, Decimal y1, Decimal x2, Decimal y2, ColorFloat color[]); - void drawPartialFunction(functionPointer &function, Decimal min, Decimal max, - float sleepTime = 0.0f, ColorFloat color = BLACK); + // void drawPartialFunction(functionPointer &function, Decimal min, Decimal max, + // float sleepTime = 0.0f, ColorFloat color = BLACK); - void drawPixel(Decimal row, Decimal col, ColorFloat color = BLACK); + // void drawPixel(Decimal row, Decimal col, ColorFloat color = BLACK); - void drawPoint(Decimal x, Decimal y, ColorFloat color = BLACK); + // void drawPoint(Decimal x, Decimal y, ColorFloat color = BLACK); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color = BLACK, bool filled = true); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color = BLACK, bool filled = true); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled = true); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat color[], bool filled = true); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor, ColorFloat outlineColor[]); - void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawRectangle(Decimal x, Decimal y, Decimal w, Decimal h, ColorFloat fillColor[], ColorFloat outlineColor[]); - void drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); + // void drawText(std::string text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); - void drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); + // void drawText(std::wstring text, Decimal x, Decimal y, unsigned size, ColorFloat color = BLACK, const std::string& fontFileName = ""); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color = BLACK, bool filled = true); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color = BLACK, bool filled = true); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled = true); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat color[], bool filled = true); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor, ColorFloat outlineColor[]); - void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawTriangle(Decimal x1, Decimal y1, Decimal x2, Decimal y2, Decimal x3, Decimal y3, ColorFloat fillColor[], ColorFloat outlineColor[]); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color, bool filled = true); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat color[], bool filled = true); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor, ColorFloat outlineColor[]); - void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); + // void drawTriangleStrip(int size, Decimal xverts[], Decimal yverts[], ColorFloat fillColor[], ColorFloat outlineColor[]); void getCartesianCoordinates(int screenX, int screenY, Decimal &cartX, Decimal &cartY); @@ -175,7 +175,7 @@ class CartesianCanvas : public Canvas { void zoom(Decimal x1, Decimal y1, Decimal x2, Decimal y2); - static void runTests(); + // static void runTests(); }; } diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 72503aebb..19070a64f 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -12,8 +12,16 @@ namespace tsgl { * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float radius, const ColorFloat color, bool filled) -: Ellipse(x,y,radius,radius,color,filled) { } //Create an Ellipse with equal x and y radii +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / numberOfVertices * PI; + for (int i = 0; i < numberOfVertices; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + } +} /*! * \brief Explicitly constructs a new multicolored filled or outlined Circle. @@ -25,55 +33,46 @@ Circle::Circle(float x, float y, float radius, const ColorFloat color, bool fill * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float radius, const ColorFloat color[], bool filled) -: Ellipse(x,y,radius,radius,color,filled) { } //Create an Ellipse with equal x and y radii +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / numberOfVertices * PI; + for (int i = 0; i < numberOfVertices; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + } +} -/*! - * \brief Explicitly constructs a new Circle with different monocolored fill and outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor The color of the circle's fill - * \param outlineColor The color of the circle's outline - */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii - -/*! - * \brief Explicitly constructs a new Circle with multicolored fill and monocolored outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor The color of the circle's outline +/** + * \brief Mutates the radius of the Circle. + * \param radius The Circle's new radius. */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius = radius; + myXScale = myYScale = radius; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Circle with monocolored fill and multicolored outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor The color of the circle's fill - * \param outlineColor An array of colors for the Circle's outline - */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor[]) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii - -/*! - * \brief Explicitly constructs a new Circle with different multicolored fill and outline. - * \details This function draws a circle with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the circle's center. - * \param y The y coordinate of the circle's center. - * \param radius The radius of the circle in pixels. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor An array of colors for the Circle's outline +/** + * \brief Mutates the radius of the Circle by the parameter amount. + * \param delta The amount by which to change the radius of the Circle. */ -Circle::Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor[]) -: Ellipse(x,y,radius,radius,fillColor,outlineColor) { } //Create an Ellipse with equal x and y radii +void Circle::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); +} } \ No newline at end of file diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index 4b7780c6f..98a809267 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -1,31 +1,36 @@ /* -* Circle.h extends Ellipse and provides a class for drawing a circle to a Canvas. +* Circle.h extends ConvexPolygon and provides a class for drawing a circle to a Canvas. */ #ifndef CIRCLE_H_ #define CIRCLE_H_ -#include "Ellipse.h" // For extending our Ellipse object +#include "ConvexPolygon.h" // For extending our ConvexPolygon object namespace tsgl { - /*! \class Circle - * \brief Draw a circle. - * \details Circle is a class for holding Shape data for a circle. - */ - class Circle : public Ellipse { - public: - Circle(float x, float y, float radius, const ColorFloat color, bool filled = true); +/*! \class Circle +* \brief Draw a circle. +* \details Circle is a class for holding Shape data for a circle. +*/ +class Circle : public ConvexPolygon { +protected: + GLfloat myRadius; +public: + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color); - Circle(float x, float y, float radius, const ColorFloat color[], bool filled = true); + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color[]); - Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor); + void setRadius(GLfloat radius); - Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor); + void changeRadiusBy(GLfloat delta); - Circle(float x, float y, float radius, const ColorFloat fillColor, const ColorFloat outlineColor[]); + /*! + * \brief Accessor for the radius of the Circle. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + GLfloat getRadius() { return myRadius; } - Circle(float x, float y, float radius, const ColorFloat fillColor[], const ColorFloat outlineColor[]); }; diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index d0d6e72f5..b8eca9be2 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -8,8 +8,21 @@ namespace tsgl { * \param numVertices The number of vertices the complete ConcavePolygon will have. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(int numVertices, bool filled, bool outlined) : Polygon(numVertices) { - setup(numVertices, filled, outlined); +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + edgesOutlined = false; + geometryType = GL_TRIANGLES; + numberOfVertices = numVertices; + numberOfOutlineVertices = numVertices+1; + size = numberOfOutlineVertices * 3; + tsize = 0; + csize = 0; + dirty = false; + outlineGeometryType = GL_LINE_STRIP; + vertices = new GLfloat[numberOfOutlineVertices * 3]; + colors = new GLfloat[numberOfOutlineVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); } /*! @@ -23,11 +36,24 @@ ConcavePolygon::ConcavePolygon(int numVertices, bool filled, bool outlined) : Po * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); - } +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + edgesOutlined = false; + geometryType = GL_TRIANGLES; + numberOfVertices = numVertices; + numberOfOutlineVertices = numVertices+1; + size = numberOfOutlineVertices * 3; + tsize = 0; + csize = 0; + dirty = false; + outlineGeometryType = GL_LINE_STRIP; + vertices = new GLfloat[numberOfOutlineVertices * 3]; + colors = new GLfloat[numberOfOutlineVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); + for (int i = 0; i < numVertices; i++) { + addVertex(x[i], y[i], 0, color); + } } /*! @@ -41,102 +67,24 @@ ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat col * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with different monocolored fill and outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConcavePolygon's fill. - * \param outlineColor The color of the ConcavePolygon's outline. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with multicolored fill and monocolored outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConcavePolygon's fill. - * \param outlineColor The color of the ConcavePolygon's outline. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with monocolored fill and multicolored outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConcavePolygon's fill. - * \param outlineColor An array of colors for the ConcavePolygon's outline. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConcavePolygon with different multicolored fill and outline. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConcavePolygon's fill. - * \param outlineColor An array of colors for the ConcavePolygon's outline. - * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. - */ -ConcavePolygon::ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); - } -} - -/*! - * \brief private helper method that works with the constructor - * \details Defines a lot of instance variables, initializes vertices and outlineVertices arrays - * \param numVertices Number of vertices on the ConcavePolygon - * \param filled Whether or not the ConcavePolygon is filled. - * \param outlined Whether or not the ConcavePolygon is outlined. - */ -void ConcavePolygon::setup(int numVertices, bool filled, bool outlined) { - numberOfOutlineVertices = numVertices+1; - size = numberOfOutlineVertices * 6; - tsize = 0; - isFilled = filled; - hasOutline = outlined; - dirty = false; - geometryType = GL_TRIANGLES; - if(filled) { - vertices = new float[size]; - } - if(outlined) { - outlineVertices = new float[size]; - } +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + edgesOutlined = false; + geometryType = GL_TRIANGLES; + numberOfVertices = numVertices; + numberOfOutlineVertices = numVertices+1; + size = numberOfOutlineVertices * 3; + tsize = 0; + csize = 0; + dirty = false; + outlineGeometryType = GL_LINE_STRIP; + vertices = new GLfloat[numberOfOutlineVertices * 3]; + colors = new GLfloat[numberOfOutlineVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); + for (int i = 0; i < numVertices; i++) { + addVertex(x[i], y[i], 0, color[i]); + } } /*! @@ -148,197 +96,39 @@ void ConcavePolygon::setup(int numVertices, bool filled, bool outlined) { * \note This function does nothing if the vertex buffer is already full. * \note A message is given indicating that the vertex buffer is full. */ -void ConcavePolygon::addVertex(float x, float y, const ColorFloat &color) { - if (init) { +void ConcavePolygon::addVertex(float x, float y, float z, ColorGLfloat &color) { + if (init) { TsglDebug("Cannot add anymore vertices."); return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = color.R; - outlineVertices[current + 3] = color.G; - outlineVertices[current + 4] = color.B; - outlineVertices[current + 5] = color.A; - } - current += 6; - dirty = true; - - if (current == size-6) { - if(isFilled) { - vertices[current] = vertices[0]; - vertices[current + 1] = vertices[1]; - vertices[current + 2] = vertices[2]; - vertices[current + 3] = vertices[3]; - vertices[current + 4] = vertices[4]; - vertices[current + 5] = vertices[5]; - } - if(hasOutline) { - outlineVertices[current] = outlineVertices[0]; - outlineVertices[current + 1] = outlineVertices[1]; - outlineVertices[current + 2] = outlineVertices[2]; - outlineVertices[current + 3] = outlineVertices[3]; - outlineVertices[current + 4] = outlineVertices[4]; - outlineVertices[current + 5] = outlineVertices[5]; - } - init = true; - if(isFilled) { - preprocess(); } attribMutex.lock(); - float minX, maxX; - //Find min and max X - if(hasOutline) { - minX = maxX = outlineVertices[0]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - } else { - minX = maxX = vertices[0]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - } - myCenterX = myRotationPointX = (minX+maxX)/2; - - float minY, maxY; - //Find min and max Y - if(hasOutline) { - minY = maxY = outlineVertices[1]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else { - minY = maxY = vertices[1]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - myCenterY = myRotationPointY = (minY+maxY)/2; + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + colors[currentColor] = color.R; + colors[currentColor + 1] = color.G; + colors[currentColor + 2] = color.B; + colors[currentColor + 3] = color.A; + currentVertex += 3; + currentColor += 4; + dirty = true; attribMutex.unlock(); - } -} - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param fillColor The reference variable of the fill color of the vertex. - * \param outlineColor The reference variable of the outline color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void ConcavePolygon::addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = fillColor.R; - vertices[current + 3] = fillColor.G; - vertices[current + 4] = fillColor.B; - vertices[current + 5] = fillColor.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = outlineColor.R; - outlineVertices[current + 3] = outlineColor.G; - outlineVertices[current + 4] = outlineColor.B; - outlineVertices[current + 5] = outlineColor.A; - } - current += 6; - dirty = true; - - if (current == size-6) { - if(isFilled) { - vertices[current] = vertices[0]; - vertices[current + 1] = vertices[1]; - vertices[current + 2] = vertices[2]; - vertices[current + 3] = vertices[3]; - vertices[current + 4] = vertices[4]; - vertices[current + 5] = vertices[5]; + if (currentVertex == size-3) { + attribMutex.lock(); + vertices[currentVertex] = vertices[0]; + vertices[currentVertex + 1] = vertices[1]; + vertices[currentVertex + 2] = vertices[2]; + colors[currentColor] = colors[0]; + colors[currentColor + 1] = vertices[1]; + colors[currentColor + 2] = vertices[2]; + colors[currentColor + 3] = vertices[3]; + outlineArray = new GLfloat[numberOfOutlineVertices*4]; + std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); + preprocess(); + init = true; + attribMutex.unlock(); } - if(hasOutline) { - outlineVertices[current] = outlineVertices[0]; - outlineVertices[current + 1] = outlineVertices[1]; - outlineVertices[current + 2] = outlineVertices[2]; - outlineVertices[current + 3] = outlineVertices[3]; - outlineVertices[current + 4] = outlineVertices[4]; - outlineVertices[current + 5] = outlineVertices[5]; - } - init = true; - if(isFilled) { - preprocess(); - } - attribMutex.lock(); - float minX, maxX; - - //Find min and max X - if(hasOutline) { - minX = maxX = outlineVertices[0]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - } else { - minX = maxX = vertices[0]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - } - myCenterX = myRotationPointX = (minX+maxX)/2; - - float minY, maxY; - //Find min and max Y - if(hasOutline) { - minY = maxY = outlineVertices[1]; - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else { - minY = maxY = vertices[1]; - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - myCenterY = myRotationPointY = (minY+maxY)/2; - attribMutex.unlock(); - } } /*! @@ -384,11 +174,11 @@ bool ConcavePolygon::intersects(float p0_x, float p0_y, float p1_x, float p1_y, */ bool ConcavePolygon::pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3) { - bool b1 = ( (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2) ) <= 0.0f; - bool b2 = ( (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3) ) <= 0.0f; - bool b3 = ( (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1) ) <= 0.0f; + bool b1 = ( (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2) ) <= 0.0f; + bool b2 = ( (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3) ) <= 0.0f; + bool b3 = ( (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1) ) <= 0.0f; - return ((b1 == b2) && (b2 == b3)); + return ((b1 == b2) && (b2 == b3)); } /*! @@ -398,89 +188,100 @@ bool ConcavePolygon::pointInTriangle (float px, float py, float x1, float y1, fl * \warning This is an order of n-cubed operation, and is thus VERY SLOW. */ void ConcavePolygon::preprocess() { - - if (dirty) { - dirty = false; - std::queue newvertices; - - bool clockwise = ( - ( - (vertices[6]-vertices[0]) * (vertices[13]-vertices[7]) - - (vertices[7]-vertices[1]) * (vertices[12]-vertices[6]) - ) < 0.0); - - for (int i = 0; i < size-12; i += 6) { - float x1 = vertices[i], y1 = vertices[i+1]; - for (int j = i+6; j < size-6; j += 6) { - float x2 = vertices[j], y2 = vertices[j+1]; - for (int k = j+6; k < size; k += 6) { - float x3 = vertices[k], y3 = vertices[k+1]; - - bool open = true; - for (int n = 0; n < size-6; n += 6) { - float x4 = vertices[n], y4 = vertices[n+1], x5 = vertices[n+6],y5 = vertices[n+7]; - if (pointInTriangle(x4,y4,x1,y1,x2,y2,x3,y3) || pointInTriangle(x5,y5,x1,y1,x2,y2,x3,y3)) { - open = false; break; - } - if (intersects(x1,y1,x2,y2,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x2==x5 && y2==y5) || (x1==x5 && y1==y5) || (x2==x4 && y2==y4)) ) { - open = false; break; - } + if (dirty) { + dirty = false; + std::queue newvertices; + std::queue newcolors; + + bool clockwise = ( + ( + (vertices[3]-vertices[0]) * (vertices[7]-vertices[4]) - + (vertices[4]-vertices[1]) * (vertices[6]-vertices[3]) + ) < 0.0); + + for (int i = 0; i < size-6; i += 3) { + float x1 = vertices[i], y1 = vertices[i+1]; + for (int j = i+3; j < size-3; j += 3) { + float x2 = vertices[j], y2 = vertices[j+1]; + for (int k = j+3; k < size; k += 3) { + float x3 = vertices[k], y3 = vertices[k+1]; + + bool open = true; + for (int n = 0; n < size-3; n += 3) { + float x4 = vertices[n], y4 = vertices[n+1], x5 = vertices[n+3],y5 = vertices[n+4]; + if (pointInTriangle(x4,y4,x1,y1,x2,y2,x3,y3) || pointInTriangle(x5,y5,x1,y1,x2,y2,x3,y3)) { + open = false; break; + } + if (intersects(x1,y1,x2,y2,x4,y4,x5,y5)) { + if ( !( (x1==x4 && y1==y4) || (x2==x5 && y2==y5) || (x1==x5 && y1==y5) || (x2==x4 && y2==y4)) ) { + open = false; break; + } + } + if (intersects(x2,y2,x3,y3,x4,y4,x5,y5)) { + if ( !( (x2==x4 && y2==y4) || (x3==x5 && y3==y5) || (x2==x5 && y2==y5) || (x3==x4 && y3==y4)) ) { + open = false; break; + } + } + if (intersects(x1,y1,x3,y3,x4,y4,x5,y5)) { + if ( !( (x1==x4 && y1==y4) || (x3==x5 && y3==y5) || (x1==x5 && y1==y5) || (x3==x4 && y3==y4)) ) { + open = false; break; + } + } + } + + //If the angle is not open (intersects something), draw nothing + if (!open) + continue; + + //If the angle is concave, draw nothing + if ( ( ( (x2-x1) * (y3-y2) - (y2-y1) * (x3-x2) ) <= 0.0) != clockwise) { + continue; + } + + newvertices.push(x1); + newvertices.push(y1); + newvertices.push(vertices[i+2]); + newcolors.push(colors[4*i/3]); + newcolors.push(colors[4*i/3+1]); + newcolors.push(colors[4*i/3+2]); + newcolors.push(colors[4*i/3+3]); + newvertices.push(x2); + newvertices.push(y2); + newvertices.push(vertices[j+2]); + newcolors.push(colors[4*j/3]); + newcolors.push(colors[4*j/3+1]); + newcolors.push(colors[4*j/3+2]); + newcolors.push(colors[4*j/3+3]); + newvertices.push(x3); + newvertices.push(y3); + newvertices.push(vertices[k+2]); + newcolors.push(colors[4*k/3]); + newcolors.push(colors[4*k/3+1]); + newcolors.push(colors[4*k/3+2]); + newcolors.push(colors[4*k/3+3]); + } } - if (intersects(x2,y2,x3,y3,x4,y4,x5,y5)) { - if ( !( (x2==x4 && y2==y4) || (x3==x5 && y3==y5) || (x2==x5 && y2==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - if (intersects(x1,y1,x3,y3,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x3==x5 && y3==y5) || (x1==x5 && y1==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - } - - //If the angle is not open (intersects something), draw nothing - if (!open) - continue; - - //If the angle is concave, draw nothing - if ( ( ( (x2-x1) * (y3-y2) - (y2-y1) * (x3-x2) ) <= 0.0) != clockwise) { - continue; - } - - newvertices.push(x1); - newvertices.push(y1); - newvertices.push(vertices[i+2]); - newvertices.push(vertices[i+3]); - newvertices.push(vertices[i+4]); - newvertices.push(vertices[i+5]); - newvertices.push(x2); - newvertices.push(y2); - newvertices.push(vertices[j+2]); - newvertices.push(vertices[j+3]); - newvertices.push(vertices[j+4]); - newvertices.push(vertices[j+5]); - newvertices.push(x3); - newvertices.push(y3); - newvertices.push(vertices[k+2]); - newvertices.push(vertices[k+3]); - newvertices.push(vertices[k+4]); - newvertices.push(vertices[k+5]); } - } - } - tsize = newvertices.size(); - delete[] vertices; - vertices = new float[tsize]; - for (int i = 0; i < tsize; ++i) { - vertices[i] = newvertices.front(); - newvertices.pop(); - } + tsize = newvertices.size(); + delete[] vertices; + vertices = new GLfloat[tsize]; + for (int i = 0; i < tsize; ++i) { + vertices[i] = newvertices.front(); + newvertices.pop(); + } + + csize = newcolors.size(); + delete[] colors; + colors = new GLfloat[csize]; + for (int i = 0; i < csize; ++i) { + colors[i] = newcolors.front(); + newcolors.pop(); + } - numberOfVertices = tsize / 6; + numberOfVertices = tsize / 3; - } + } //Debug Outline // for (int i = 0; i < size; i += 6) { @@ -509,7 +310,7 @@ void ConcavePolygon::runTests() { bool ConcavePolygon::testIntersects() { int passed = 0; int failed = 0; - ConcavePolygon c1(10); + ConcavePolygon c1(0,0,0,10,0,0,0); //Test 1: Intersecting lines float x1, y1, x2, y2, x3, y3, x4, y4 = 0.0; @@ -566,7 +367,7 @@ bool ConcavePolygon::testIntersects() { bool ConcavePolygon::testPointITriangle() { int passed = 0; int failed = 0; - ConcavePolygon c2(10); + ConcavePolygon c2(0,0,0,10,0,0,0); //Test 1: Point is in the triangle float px, py, x1, y1, x2, y2, x3, y3 = 0.0; diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index d6424f19b..dc700a5e6 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -1,11 +1,13 @@ /* * ConcavePolygon.h extends Shape and provides a class for drawing a Concave polygon to a Canvas. + * #FIXME setColor(ColorGLfloat c[]) needs to be overrided. Looks awful with the default. + * #FIXME Performance is horrific. This is going to need to be fixed. */ #ifndef CONCAVEPOLYGON_H_ #define CONCAVEPOLYGON_H_ -#include "Polygon.h" // For extending our Shape object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes #include // std::queue #include // DEBUGGING @@ -22,41 +24,30 @@ namespace tsgl { * \note Calling addVertex() after all vertices have been added will do nothing. * \note Calling draw() before all vertices have been added will do nothing. */ -class ConcavePolygon : public Polygon { +class ConcavePolygon : public Shape { private: bool dirty; // Whether the new vertex buffer is dirty int size, // Number of floating point numbers in vertices tsize, // Number of floating point numbers in tarray + csize, // Number of floating point numbers in colors array length; // Number of vertices in vertices (size / 6) - void setup(int numVertices, bool filled, bool outlined = false); - static bool testIntersects(); // Unit test for intersects() static bool testPointITriangle(); // Unit test for pointInTriangle() public: - ConcavePolygon(int numVertices, bool filled = true, bool outlined = false); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color); - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - ConcavePolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color[]); bool intersects(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y); bool pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3); - void addVertex(float x, float y, const ColorFloat &color); - - void addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor); + void addVertex(float x, float y, float z, ColorGLfloat &color); void preprocess(); @@ -65,4 +56,4 @@ class ConcavePolygon : public Polygon { } -#endif /* COLOREDPOLYGON_H_ */ +#endif /* CONCAVEPOLYGON_H_ */ diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 4b78d5acb..5701db5b5 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -10,8 +10,15 @@ namespace tsgl { * \param outlined Whether or not the ConvexPolygon is outlined. * \return A new ConvexPolygon with a buffer for storing the specified numbered of vertices. */ -ConvexPolygon::ConvexPolygon(int numVertices, bool filled, bool outlined) : Polygon(numVertices) { - setup(numVertices, filled, outlined); +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_POLYGON; + numberOfVertices = numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); } /*! @@ -25,10 +32,17 @@ ConvexPolygon::ConvexPolygon(int numVertices, bool filled, bool outlined) : Poly * (set to true by default). * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_POLYGON; + numberOfVertices = numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); + addVertex(x[i], y[i], 0, color); } } @@ -43,162 +57,17 @@ ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color * (set to true by default). * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : Polygon(numVertices) { - setup(numVertices, filled, !filled); +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_POLYGON; + numberOfVertices = numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + myXScale = myYScale = myZScale = 1; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with different monocolored fill and outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConvexPolygon's fill. - * \param outlineColor The color of the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with multicolored fill and monocolored outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConvexPolygon's fill. - * \param outlineColor The color of the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with monocolored fill and multicolored outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor The color of the ConvexPolygon's fill. - * \param outlineColor An array of colors for the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); - } -} - - /*! - * \brief Explicitly constructs a new ConvexPolygon with different multicolored fill and outline. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param fillColor An array of colors for the ConvexPolygon's fill. - * \param outlineColor An array of colors for the ConvexPolygon's outline. - * \return A new ConvexPolygon with the specified vertices and color. - */ -ConvexPolygon::ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : Polygon(numVertices) { - setup(numVertices, true, true); - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); - } -} - -/*! - * \brief private helper method that works with the constructor - * \details Defines a lot of instance variables, initializes vertices and outlineVertices arrays - * \param numVertices Number of vertices on the ConvexPolygon - * \param filled Whether or not the ConvexPolygon is filled. - * \param outlined Whether or not the ConvexPolygon is outlined. - */ -void ConvexPolygon::setup(int numVertices, bool filled, bool outlined) { - numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices; - size = numberOfVertices * 6; - if(filled) { - vertices = new float[size]; - } - if(outlined) { - outlineVertices = new float[size]; - } - geometryType = GL_TRIANGLE_FAN; - isFilled = filled; - hasOutline = outlined; -} - -/*! - * \brief Runs the Unit tests. - * \details Runs the Unit tests for the ConvexPolygon class. addVertex() is tested. - */ -void ConvexPolygon::runTests() { - TsglDebug("Testing ConvexPolygon class..."); - tsglAssert(testAddVertex(), "Unit test for adding vertices failed"); - TsglDebug("Unit tests for ConvexPolygon complete."); - std::cout << std::endl; -} - -bool ConvexPolygon::testAddVertex() { - int passed = 0; - int failed = 0; - ConvexPolygon c1(4); //Start with a polygon that has the capacity for four vertices - //Test 1: Adding a single vertex - if(c1.size == 24 && c1.current == 0) { //As it should be... - c1.addVertex(20, 30, BLACK); //Add a vertex; only the current should change... - if(c1.size == 24 && c1.current == 6) { - passed++; - } else { - failed++; - TsglErr("Test 1, One vertex for testAddVertex() failed!"); - } - } - - //Test 2: Filling the polygon vertices completely - //Add three more vertices, checking if the current has changed correspondingly - c1.addVertex(20, 30, BLACK); - c1.addVertex(20, 30, BLACK); - c1.addVertex(20, 30, BLACK); - - //The size should've remained the same but the current should now equal the size - if(c1.size == 24 && c1.current == 24) { - passed++; - } else { - failed++; - TsglErr("Test 2, Filling vertices completely for testAddVertex() failed!"); - } - - //Test 3: Attempting to add another vertex to a filled vertices.... - c1.addVertex(20, 30, BLACK); - //The size and current should've stayed the same - if(c1.size == 24 && c1.current == 24) { - passed++; - } else { - failed++; - TsglErr("Test 3, Add more beyond capacity for testAddVertex() failed!"); - } - - if(passed == 3 && failed == 0) { - TsglDebug("Unit test for adding vertices passed!"); - return true; - } else { - TsglErr("This many tests for ConvexPolygon passed: "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests for ConvexPolygon failed: "); - std::cout << " " << failed << std::endl; - return false; + addVertex(x[i], y[i], 0, color[i]); } } diff --git a/src/TSGL/ConvexPolygon.h b/src/TSGL/ConvexPolygon.h index f13f74792..1e4f5fb87 100755 --- a/src/TSGL/ConvexPolygon.h +++ b/src/TSGL/ConvexPolygon.h @@ -5,7 +5,7 @@ #ifndef CONVEXPOLYGON_H_ #define CONVEXPOLYGON_H_ -#include "Polygon.h" // For extending our Shape object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -20,29 +20,13 @@ namespace tsgl { * \note Calling addVertex() after all vertices have been added will do nothing. * \note Calling draw() before all vertices have been added will do nothing. */ -class ConvexPolygon : public Polygon { - private: - int size; - - static bool testAddVertex(); // Unit test for addVertex() +class ConvexPolygon : public Shape { + protected: + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); public: - ConvexPolygon(int numVertices, bool filled = true, bool outlined = false); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - ConvexPolygon(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); - - void setup(int numVertices, bool filled, bool outlined); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color); - static void runTests(); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color[]); }; } diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 26241e560..72102fee1 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -17,7 +17,7 @@ namespace tsgl { * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c) -: Object3D(x, y, z, yaw, pitch, roll) { // FIXME vertices +: Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } @@ -78,7 +78,7 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Object3D(x, y, z, yaw, pitch, roll) { // FIXME vertices +: Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 43eee421e..8740341bf 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -5,7 +5,7 @@ #ifndef CUBE_H_ #define CUBE_H_ -#include "Object3D.h" // For extending our Prism object +#include "Drawable.h" // For extending our Prism object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cube * \brief Draw an arbitrary Cube with colored vertices. * \details Cube is a class for holding vertex data for a Cube. - * \details Cube is a 6-sided subclass of Object3D with all square faces. + * \details Cube is a 6-sided subclass of Drawable with all square faces. */ -class Cube : public Object3D { +class Cube : public Drawable { protected: GLfloat mySideLength; public: @@ -33,7 +33,7 @@ class Cube : public Object3D { */ virtual GLfloat getSideLength() { return mySideLength; } - virtual void setColor(ColorGLfloat c) { Object3D::setColor(c); } + virtual void setColor(ColorGLfloat c) { Drawable::setColor(c); } virtual void setColor(ColorGLfloat c[]); diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index e8a06e1d9..39443cfea 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -19,7 +19,7 @@ namespace tsgl { * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c) -: Object3D(x, y, z, yaw, pitch, roll) { +: Drawable(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } @@ -84,7 +84,7 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]) -: Object3D(x, y, z, yaw, pitch, roll) { +: Drawable(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index d2831a5dc..447a927f0 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -5,7 +5,7 @@ #ifndef CUBOID_H_ #define CUBOID_H_ -#include "Object3D.h" // For extending our Prism object +#include "Drawable.h" // For extending our Prism object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cuboid * \brief Draw an arbitrary Cuboid with colored vertices. * \details Cuboid is a class for holding vertex data for a Cuboid. - * \details Cuboid is a 6-sided subclass of Object3D with all rectangular faces. + * \details Cuboid is a 6-sided subclass of Drawable with all rectangular faces. */ -class Cuboid : public Object3D { +class Cuboid : public Drawable { protected: GLfloat myLength, myWidth, myHeight; public: @@ -53,7 +53,7 @@ class Cuboid : public Object3D { */ virtual GLfloat getWidth() { return myWidth; } - virtual void setColor(ColorGLfloat c) { Object3D::setColor(c); } + virtual void setColor(ColorGLfloat c) { Drawable::setColor(c); } virtual void setColor(ColorGLfloat c[]); diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index ff9804839..f2b37401d 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -4,66 +4,360 @@ namespace tsgl { /*! * \brief Constructs a new Drawable. + * \details + * - Usually vertices is filled with floating point values that represent the vertices of the Drawable to be drawn. + * - You may define other items in the constructor that pertain to the attributes of the subclass that is extending Drawable. + * - At a minimum, you *MUST* fill an array of floating point values that pertain to the vertices of the Drawable. * \warning You must inherit the parent's constructor if you are extending Drawable. * \note Refer to the Drawable class description for more details. */ -Drawable::Drawable() { +Drawable::Drawable(float x, float y, float z, float yaw, float pitch, float roll) { + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + myCenterX = x; + myCenterY = y; + myCenterZ = z; + myRotationPointX = myCenterX; + myRotationPointY = myCenterY; + myRotationPointZ = myCenterZ; +} + +/*! + * \brief Draw the Drawable. + * \details This function actually draws the Drawable to the Canvas. + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the Drawable cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). + */ +void Drawable::draw() { + glPushMatrix(); + glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); + glRotatef(myCurrentYaw, 0, 0, 1); + glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentRoll, 1, 0, 0); + glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); + glScalef(myXScale, myYScale, myZScale); + + /* We have a color array and a vertex array */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_FLOAT, 0, colors); + + glDrawArrays(geometryType, 0, numberOfVertices); + + if (edgesOutlined) { + glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); + glColorPointer(4, GL_FLOAT, 0, outlineArray); + + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); + } + + glPopMatrix(); + + /* Cleanup states */ + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +} + + /*! + * \brief Adds another vertex to a Drawable. + * \details This function initializes the next vertex in the Drawable and adds it to a Drawable buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Drawable::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &color) { + if (init) { + TsglDebug("Cannot add anymore vertices."); + return; + } attribMutex.lock(); - renderLayer = -1; + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + currentVertex += 3; + colors[currentColor] = color.R; + colors[currentColor+1] = color.G; + colors[currentColor+2] = color.B; + colors[currentColor+3] = color.A; + currentColor += 4; attribMutex.unlock(); + if (currentVertex == numberOfVertices*3) { + attribMutex.lock(); + outlineArray = new GLfloat[numberOfOutlineVertices*4]; + std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); + init = true; + attribMutex.unlock(); + } } -/*! - * \brief Accessor for isTextured. - * \return Whether the drawable is a textured primitive or not. +///////////////////////////////////////////////// +// MUTATORS +///////////////////////////////////////////////// + + +/** + * \brief Sets the Drawable to a new color. + * \param c The new ColorGLfloat. + */ +void Drawable::setColor(ColorGLfloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + colors[i*4] = c.R; + colors[i*4 + 1] = c.G; + colors[i*4 + 2] = c.B; + colors[i*4 + 3] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's outline/edges to a new color + * \param c The new ColorGLfloat. + */ +void Drawable::setEdgeColor(ColorGLfloat c) { + for (int i = 0; i < numberOfOutlineVertices; i++) { + outlineArray[4*i] = c.R; + outlineArray[4*i+1] = c.G; + outlineArray[4*i+2] = c.B; + outlineArray[4*i+3] = c.A; + } +} + +/** + * \brief Alters the Drawable's x position + * \param deltaX The difference between the new and old vertex x coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeXBy(float deltaX) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX += deltaX; + } + myCenterX += deltaX; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's y position + * \param deltaY The difference between the new and old vertex y coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeYBy(float deltaY) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointY += deltaY; + } + myCenterY += deltaY; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's z position + * \param deltaZ The difference between the new and old vertex z coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeZBy(float deltaZ) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointZ += deltaZ; + } + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's vertex locations. + * \param deltaX The difference between the new and old vertex x coordinates. + * \param deltaY The difference between the new and old vertex y coordinates. + * \param deltaZ The difference between the new and old vertex z coordinates. + * \warning This will also alter the Drawable's rotation point similarly if and + * only if the old rotation point was at the Drawable's old center. + */ +void Drawable::changeCenterBy(float deltaX, float deltaY, float deltaZ) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX += deltaX; + myRotationPointY += deltaY; + myRotationPointZ += deltaZ; + } + myCenterX += deltaX; + myCenterY += deltaY; + myCenterZ += deltaZ; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's x position + * \param x The new center x coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterX(float x) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointX = x; + } + myCenterX = x; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's y position + * \param y The new center y coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterY(float y) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointY = y; + } + myCenterY = y; + attribMutex.unlock(); +} + +/** + * \brief Sets the Drawable's z position + * \param z The new center z coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. + */ +void Drawable::setCenterZ(float z) { + attribMutex.lock(); + if (centerMatchesRotationPoint()) { + myRotationPointZ = z; + } + myCenterZ = z; + attribMutex.unlock(); +} + +/** + * \brief Moves the Drawable to new coordinates. + * \param x The new center x coordinate. + * \param y The new center y coordinate. + * \param z The new center z coordinate. + * \warning This will also alter the Drawable's rotation point similarly if and only + * if the old rotation point was at the Drawable's old center. */ -bool Drawable::getIsTextured() { +void Drawable::setCenter(float x, float y, float z) { attribMutex.lock(); - bool retVal = isTextured; + if (centerMatchesRotationPoint()) { + myRotationPointX = x; + myRotationPointY = y; + myRotationPointZ = z; + } + myCenterX = x; + myCenterY = y; + myCenterZ = z; attribMutex.unlock(); - return retVal; } /** -* \brief Sets the layer of the Drawable. -* \param n The new layer of the Drawable. -* \details Sets renderLayer to n if n >= 0. -*/ -void Drawable::setLayer(int n) { + * \brief Mutator for the Drawable's yaw + * \param yaw The new yaw value for Drawable. + */ +void Drawable::setYaw(float yaw) { attribMutex.lock(); - if (n>=0) { renderLayer = n; } + myCurrentYaw = yaw; attribMutex.unlock(); } /** - * \brief Accessor for renderLayer. - * \return The layer the drawable is set at. + * \brief Mutator for the Drawable's pitch + * \param pitch The new pitch value for Drawable. */ -int Drawable::getLayer() { +void Drawable::setPitch(float pitch) { attribMutex.lock(); - int retVal = renderLayer; + myCurrentPitch = pitch; + attribMutex.unlock(); +} + +/** + * \brief Mutator for the Drawable's roll + * \param roll The new roll value for Drawable. + */ +void Drawable::setRoll(float roll) { + attribMutex.lock(); + myCurrentRoll = roll; attribMutex.unlock(); - return retVal; } /*! - * \brief Virtual mutator that changes the rotation point of the Drawable - * \details Alters myRotationPointX and myRotationPointY; - * \param x myRotationPointX's new float value. - * \param y myRotationPointY's new float value. + * \brief Mutator for the yaw, pitch, and roll of the Drawable. + * \param yaw The new yaw value for Drawable. + * \param pitch The new pitch value for Drawable. + * \param roll The new roll value for Drawable. */ -void Drawable::setRotationPoint(float x, float y) { - myRotationPointX = x; - myRotationPointY = y; +void Drawable::setYawPitchRoll(float yaw, float pitch, float roll) { + attribMutex.lock(); + myCurrentYaw = yaw; + myCurrentPitch = pitch; + myCurrentRoll = roll; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's yaw by a specified amount. + * \param deltaYaw The change in yaw value for Drawable. + */ +void Drawable::changeYawBy(float deltaYaw) { + attribMutex.lock(); + myCurrentYaw += deltaYaw; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's pitch by a specified amount. + * \param deltaPitch The change in pitch value for Drawable. + */ +void Drawable::changePitchBy(float deltaPitch) { + attribMutex.lock(); + myCurrentPitch += deltaPitch; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's roll by a specified amount. + * \param deltaRoll The change in roll value for Drawable. + */ +void Drawable::changeRollBy(float deltaRoll) { + attribMutex.lock(); + myCurrentRoll += deltaRoll; + attribMutex.unlock(); +} + +/** + * \brief Alters the Drawable's yaw, pitch, and roll by a specified amount. + * \param deltaYaw The change in yaw value for Drawable. + * \param deltaPitch The change in pitch value for Drawable. + * \param deltaRoll The change in roll value for Drawable. + */ +void Drawable::changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll) { + attribMutex.lock(); + myCurrentYaw += deltaYaw; + myCurrentPitch += deltaPitch; + myCurrentRoll += deltaRoll; + attribMutex.unlock(); } /*! * \brief Virtual mutator that changes the rotation point of the Drawable's x value. * \details Alters myRotationPointX; - * \param x myRotationPointX's new float value. + * \param z myRotationPointX's new float value. */ void Drawable::setRotationPointX(float x) { + attribMutex.lock(); myRotationPointX = x; + attribMutex.unlock(); } /*! @@ -72,7 +366,97 @@ void Drawable::setRotationPointX(float x) { * \param y myRotationPointY's new float value. */ void Drawable::setRotationPointY(float y) { + attribMutex.lock(); + myRotationPointY = y; + attribMutex.unlock(); +} + +/*! + * \brief Virtual mutator that changes the rotation point of the Drawable's z value. + * \details Alters myRotationPointZ; + * \param z myRotationPointZ's new float value. + */ +void Drawable::setRotationPointZ(float z) { + attribMutex.lock(); + myRotationPointZ = z; + attribMutex.unlock(); +} + +/** + * \brief Sets the point around which Drawable is rotated. + * \param x The x coordinate of the new rotation point. + * \param y The y coordinate of the new rotation point. + * \param z The z coordinate of the new rotation point. + */ +void Drawable::setRotationPoint(float x, float y, float z) { + attribMutex.lock(); + myRotationPointX = x; myRotationPointY = y; + myRotationPointZ = z; + attribMutex.unlock(); +} + +/*! + * \brief Accessor for the center x-coordinate of the Drawable. + * \details Returns the value of the myCenterX private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointX; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterX() { + if (centerMatchesRotationPoint()) { + return myCenterX; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return cosYaw * cosPitch * (myCenterX - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myCenterY - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointX; +} + +/*! + * \brief Accessor for the center z-coordinate of the Drawable. + * \details Returns the value of the myCenterY private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointY; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterY() { + if (centerMatchesRotationPoint()) { + return myCenterY; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return sinYaw * cosPitch * (myCenterX - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myCenterY - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointY; +} + +/*! + * \brief Accessor for the center z-coordinate of the Drawable. + * \details Returns the value of the myCenterZ private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointZ; + * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin + * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. + */ +float Drawable::getCenterZ() { + if (centerMatchesRotationPoint()) { + return myCenterZ; + } + float cosYaw = cos(myCurrentYaw * PI / 180); + float sinYaw = sin(myCurrentYaw * PI / 180); + float cosPitch = cos(myCurrentPitch * PI / 180); + float sinPitch = sin(myCurrentPitch * PI / 180); + float cosRoll = cos(myCurrentPitch * PI / 180); + float sinRoll = sin(myCurrentRoll * PI / 180); + return -sinPitch * (myCenterX - myRotationPointX) + cosPitch * sinRoll * (myCenterY - myRotationPointY) + cosPitch * cosRoll * (myCenterZ - myRotationPointZ) + myRotationPointZ; +} + +Drawable::~Drawable() { + delete[] vertices; + delete[] colors; + delete[] outlineArray; } } \ No newline at end of file diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index b6a6c8010..6fa34fd31 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -1,88 +1,120 @@ /* -* Drawable.h provides a base class from which to extend other drawable shapes. -*/ + * Drawable.h provides a base class from which to extend other drawable objects. + */ #ifndef DRAWABLE_H_ #define DRAWABLE_H_ -#include // Needed for locking the attribute mutex for thread-safety #include "Color.h" // Needed for color type +#include // Needed for locking the attribute mutex for thread-safety namespace tsgl { - /*! \class Drawable - * \brief A class for drawing onto a Canvas or CartesianCanvas. - * \details Drawable provides a base class for drawing a shape, text, or image to a Canvas or CartesianCanvas. - * \note Drawable is abstract and must be extended. - */ - class Drawable { - protected: - std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed - bool isTextured = false; ///< Whether the Drawable is a Textured object. - float myRotationPointX, myRotationPointY, myCenterX, myCenterY; - int renderLayer; // The depth index to control the drawing order of the shapes - public: - Drawable(); +/*! \class Drawable + * \brief A class for drawing objects onto a Canvas or CartesianCanvas. + * \warning Though extending this class must be allowed due to the way the code is set up, attempting to do so + * could potentially mess up the internal GL calls the library uses. Proceed with great caution. + * \details Drawable provides a base class for drawing 3D objects to a Canvas or CartesianCanvas. + * \note Drawable is abstract, and must be extended by the user. + * \details vertices should be an array of floating point values in TSGL's vertex format. + * \details numberofvertices should be the actual integer number of vertices to be drawn (e.g., *36* for a cube). + * \details geometryType should be one of GL's primitive drawing modes. + * See https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml for further information. + * \details Theoretically, you could potentially extend the Drawable class so that you can create another Drawable class that suits your needs. + * \details However, this is not recommended for normal use of the TSGL library. + */ +class Drawable { + protected: + std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed + bool edgesOutlined = true; + int numberOfVertices; + int numberOfOutlineVertices; + GLsizei outlineStride = 0; + GLfloat* vertices; + GLfloat* colors; + GLfloat* outlineArray; + int currentVertex = 0; + int currentColor = 0; + float myCurrentYaw, myCurrentPitch, myCurrentRoll; + float myXScale, myYScale, myZScale; + float myRotationPointX, myRotationPointY, myRotationPointZ; + float myCenterX, myCenterY, myCenterZ; + GLenum geometryType; + GLenum outlineGeometryType; + bool init = false; + virtual void addVertex(float x, float y, float z, const ColorGLfloat &color = ColorGLfloat(1,1,1,1)); /*! - * \brief Destroys the Drawable. - * \details Destructor for a Drawable. - * \details Frees up memory that was allocated to a Drawable object. - */ - virtual ~Drawable() { } - - /*! - * \brief Actually draws the Drawable to the Canvas. - * \details This method renders the drawable to the Canvas. - * - When you extend the Drawable class, you *MUST* provide a definition for this method. - * - The definition must follow this format: - * - * glBufferData(drawingMode, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - * glDrawArrays(drawingMode, 0, numberOfVertices); - * - * - Really bad things could potentially happen if you do not follow this format. These two statements *MUST* be - * in the draw() method of the subclass that extends the Drawable class. - * - You can add other statements in the subclass - * \note Please refer to the class description for more information and warnings about overriding this method. + * \brief Protected helper method that determines if the Drawable's center matches its rotation point. + * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ + * \return True if all three coordinates match their respective others, false otherwise. + */ + bool centerMatchesRotationPoint() { + return (myCenterX == myRotationPointX && myCenterY == myRotationPointY && myCenterZ == myRotationPointZ); + } + public: + Drawable(float x, float y, float z, float yaw, float pitch, float roll); + + virtual ~Drawable(); + + virtual void draw(); + + virtual void setColor(ColorGLfloat c); + /** + * \brief Pure virtual mutator. Sets the Drawable to a new array of colors. + * \param c An array of the new ColorGLfloats. + * \warning Inheriting subclasses MUST define an override method for this method. */ - virtual void draw() = 0; // Abstract method for actually drawing the shape - - bool getIsTextured(); + virtual void setColor(ColorGLfloat c[]) = 0; + virtual void setEdgeColor(ColorGLfloat c); - void setLayer(int n); + virtual void changeXBy(float deltaX); + virtual void changeYBy(float deltaY); + virtual void changeZBy(float deltaZ); + virtual void changeCenterBy(float deltaX, float deltaY, float deltaZ); - int getLayer(); - - /*! - * \brief Virtual accessor that returns if Drawable is processed and ready to be drawn - * \details This function returns true only if all vertices have been inserted into an array. - */ - virtual bool isProcessed() { return true; } + virtual void setCenterX(float x); + virtual void setCenterY(float y); + virtual void setCenterZ(float z); + virtual void setCenter(float x, float y, float z); - /*! - * \brief Pure virtual mutator that changes the rotation of the Drawable - * \details Rotates the Drawable clockwise by radians radians. - * \param radians The number of radians to rotate the Drawable. - */ - virtual void setRotation(float radians) = 0; + virtual void setYaw(float yaw); + virtual void setPitch(float pitch); + virtual void setRoll(float roll); + virtual void setYawPitchRoll(float yaw, float pitch, float roll); - virtual void setRotationPoint(float x, float y); + virtual void changeYawBy(float deltaYaw); + virtual void changePitchBy(float deltaPitch); + virtual void changeRollBy(float deltaRoll); + virtual void changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll); virtual void setRotationPointX(float x); - virtual void setRotationPointY(float y); + virtual void setRotationPointZ(float z); + virtual void setRotationPoint(float x, float y, float z); + + + virtual float getCenterX(); + virtual float getCenterY(); + virtual float getCenterZ(); + + /*! + * \brief Accessor for the Yaw of the Drawable. + * \details Returns the value of the myCurrentYaw private variable. + */ + virtual float getYaw() { return myCurrentYaw; } /*! - * \brief Accessor for the center x-coordinate of the Drawable. - * \details Returns the value of the myCenterX private variable. + * \brief Accessor for the Pitch of the Drawable. + * \details Returns the value of the myCurrentPitch private variable. */ - virtual float getCenterX() { return myCenterX; } + virtual float getPitch() { return myCurrentPitch; } /*! - * \brief Accessor for the center y-coordinate of the Drawable. - * \details Returns the value of the myCenterY private variable. + * \brief Accessor for the Roll of the Drawable. + * \details Returns the value of the myCurrentRoll private variable. */ - virtual float getCenterY() { return myCenterY; } + virtual float getRoll() { return myCurrentRoll; } /*! * \brief Accessor for the rotation x-coordinate of the Drawable. @@ -95,7 +127,28 @@ namespace tsgl { * \details Returns the value of the myRotationPointY private variable. */ virtual float getRotationPointY() { return myRotationPointY; } - }; + + /*! + * \brief Accessor for the rotation z-coordinate of the Drawable. + * \details Returns the value of the myRotationPointZ private variable. + */ + virtual float getRotationPointZ() { return myRotationPointZ; } + + /* + * \brief Mutator that determines if the edges of the Drawable should be highlighted. + * \details Updates the value of the edgesOutlined instance variable. Defaults to true. + */ + virtual void displayOutlineEdges(bool on=true) { edgesOutlined=on; } + + + + /*! + * \brief Accessor that returns if Drawable is processed and ready to be drawn + * \details This function returns true only if all vertices have been inserted into an array. + */ + virtual bool isProcessed() { return init; } }; -#endif /* DRAWABLE_H_ */ \ No newline at end of file +} + +#endif /* DRAWABLE_H_ */ diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index fa9e7d76f..0c5beca47 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -13,12 +13,16 @@ namespace tsgl { * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color, bool filled) : ConvexPolygon((xRadius + yRadius) / 2, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), color); - } +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myXRadius = xRadius; + myYScale = myYRadius = yRadius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / numberOfVertices * PI; + for (int i = 0; i < numberOfVertices; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + } } /*! @@ -32,84 +36,76 @@ Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloa * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color[], bool filled) : ConvexPolygon((xRadius + yRadius) / 2, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), color[i]); - } +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myXRadius = xRadius; + myYScale = myYRadius = yRadius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / numberOfVertices * PI; + for (int i = 0; i < numberOfVertices; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + } } -/*! - * \brief Explicitly constructs a new Ellipse with different monocolored fill and outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor The color of the Ellipse's fill - * \param outlineColor The color of the Ellipse's outline +/** + * \brief Mutates the horizontal radius of the Ellipse. + * \param xRadius The Ellipse's new x-radius. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor, outlineColor); - } +void Ellipse::setXRadius(GLfloat xRadius) { + if (xRadius <= 0) { + TsglDebug("Cannot have a Ellipse with x-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXRadius = xRadius; + myXScale = xRadius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with multicolored fill and monocolored outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor An array of colors for the Ellipse's fill - * \param outlineColor The color of the Ellipse's outline +/** + * \brief Mutates the horizontal radius of the Ellipse by the parameter amount. + * \param delta The amount by which to change the x-radius of the Ellipse. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor[i], outlineColor); - } +void Ellipse::changeXRadiusBy(GLfloat delta) { + if (myXRadius + delta <= 0) { + TsglDebug("Cannot have a Ellipse with x-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXRadius += delta; + myXScale += delta; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with monocolored fill and multicolored outline. - * \details This function draws a Ellipse with the given center, radii, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor The color of the Ellipse's fill - * \param outlineColor An array of colors for the Ellipse's outline +/** + * \brief Mutates the vertical radius of the Ellipse. + * \param YRadius The Ellipse's new y-radius. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor, outlineColor[i]); - } +void Ellipse::setYRadius(GLfloat yRadius) { + if (yRadius <= 0) { + TsglDebug("Cannot have a Ellipse with y-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myYRadius = yRadius; + myYScale = yRadius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new Ellipse with different multicolored fill and outline. - * \details This function draws a Ellipse with the given center, radius, fillColor, and outline color. - * \param x The x coordinate of the Ellipse's center. - * \param y The y coordinate of the Ellipse's center. - * \param xRadius The horizontal radius of the Ellipse in pixels. - * \param yRadius The vertical radius of the Ellipse in pixels. - * \param fillColor An array of colors for the Ellipse's fill - * \param outlineColor An array of colors for the Ellipse's outline +/** + * \brief Mutates the vertical radius of the Ellipse by the parameter amount. + * \param delta The amount by which to change the y-radius of the Ellipse. */ -Ellipse::Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon((xRadius + yRadius) / 2, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(x+xRadius*cos(i*delta), y+yRadius*sin(i*delta), fillColor[i], outlineColor[i]); - } +void Ellipse::changeYRadiusBy(GLfloat delta) { + if (myYRadius + delta <= 0) { + TsglDebug("Cannot have a Ellipse with y-radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myYRadius += delta; + myYScale += delta; + attribMutex.unlock(); } diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index 5612c9155..fc6e6a70c 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -15,19 +15,31 @@ namespace tsgl { */ class Ellipse : public ConvexPolygon { private: - + GLfloat myXRadius, myYRadius; public: - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color, bool filled = true); + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color); + + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color[]); + + void setXRadius(GLfloat xRadius); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat color[], bool filled = true); + void setYRadius(GLfloat yRadius); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor); + void changeXRadiusBy(GLfloat delta); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor); + void changeYRadiusBy(GLfloat delta); - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor, const ColorFloat outlineColor[]); + /*! + * \brief Accessor for the x-radius of the Ellipse. + * \details Returns the value of the myXRadius private variable, a GLfloat. + */ + GLfloat getXRadius() { return myXRadius; } - Ellipse(float x, float y, float xRadius, float yRadius, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + /*! + * \brief Accessor for the y-radius of the Ellipse. + * \details Returns the value of the myYRadius private variable, a GLfloat. + */ + GLfloat getYRadius() { return myYRadius; } }; diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 20ba2d2fd..4b12ec25b 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } @@ -65,7 +65,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } diff --git a/src/TSGL/Ellipsoid.h b/src/TSGL/Ellipsoid.h index b3483fbbe..856bf2240 100644 --- a/src/TSGL/Ellipsoid.h +++ b/src/TSGL/Ellipsoid.h @@ -1,11 +1,11 @@ /* - * Ellipsoid.h extends Object3D and provides a class for drawing a ellipsoid. + * Ellipsoid.h extends Drawable and provides a class for drawing a ellipsoid. */ #ifndef ELLIPSOID_H_ #define ELLIPSOID_H_ -#include "Object3D.h" // For extending our Object3D object +#include "Drawable.h" // For extending our Drawable object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Ellipsoid with colored vertices. * \details Ellipsoid is a class for holding vertex data for an Ellipsoid. */ -class Ellipsoid : public Object3D { +class Ellipsoid : public Drawable { protected: GLfloat myXRadius, myYRadius, myZRadius; int horizontalSections, verticalSections; diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index 08ce1ad55..a1638ad3a 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -1,173 +1,173 @@ -#include "Image.h" +// #include "Image.h" -namespace tsgl { +// namespace tsgl { - /*! - * \brief Explicitly constructs a new Image. - * \details This is the explicit constructor for the Image class. - * \param filename The filename of the image to load. - * \param loader A reference pointer to the TextureHandler with which to load the image. - * \param x The x coordinate of the left of the Image. - * \param y The y coordinate of the top of the Image. - * \param width The width of the Image. - * \param height The height of the Image. - * \param alhpa The alpha of the Image. - * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. - * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. - */ -Image::Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha) { - isTextured = true; // Let the Canvas know we're a textured object - myTexture = 0; // Fix no texture initialization warning - myWidth = width; myHeight = height; - if (myWidth <= 0 || myHeight <= 0) { - TextureHandler::getDimensions(filename,myWidth,myHeight); - } - myCenterX = x + myWidth / 2; - myCenterY = y + myHeight / 2; - setRotationPoint(myCenterX, myCenterY); - currentRotation = 0; - myFile = filename; - myLoader = &loader; - vertices = new float[32]; - vertices[0] = x; - vertices[1] = y; - vertices[8] = x + myWidth; - vertices[9] = y; - vertices[16] = x; - vertices[17] = y + myHeight; - vertices[24] = x + myWidth; - vertices[25] = y + myHeight; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; - vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = alpha; - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left - vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right -} +// /*! +// * \brief Explicitly constructs a new Image. +// * \details This is the explicit constructor for the Image class. +// * \param filename The filename of the image to load. +// * \param loader A reference pointer to the TextureHandler with which to load the image. +// * \param x The x coordinate of the left of the Image. +// * \param y The y coordinate of the top of the Image. +// * \param width The width of the Image. +// * \param height The height of the Image. +// * \param alhpa The alpha of the Image. +// * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. +// * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. +// */ +// Image::Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha) { +// isTextured = true; // Let the Canvas know we're a textured object +// myTexture = 0; // Fix no texture initialization warning +// myWidth = width; myHeight = height; +// if (myWidth <= 0 || myHeight <= 0) { +// TextureHandler::getDimensions(filename,myWidth,myHeight); +// } +// myCenterX = x + myWidth / 2; +// myCenterY = y + myHeight / 2; +// setRotationPoint(myCenterX, myCenterY); +// currentRotation = 0; +// myFile = filename; +// myLoader = &loader; +// vertices = new float[32]; +// vertices[0] = x; +// vertices[1] = y; +// vertices[8] = x + myWidth; +// vertices[9] = y; +// vertices[16] = x; +// vertices[17] = y + myHeight; +// vertices[24] = x + myWidth; +// vertices[25] = y + myHeight; +// vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords +// vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; +// vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; +// vertices[5] = vertices[13] = vertices[21] = vertices[29] = alpha; +// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left +// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right +// vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left +// vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right +// } - /*! - * \brief Draw the Image. - * \details This function actually draws the Image to the Canvas. - */ -void Image::draw() { - unsigned int w, h; - myLoader->loadPicture(myFile, w, h, myTexture); +// /*! +// * \brief Draw the Image. +// * \details This function actually draws the Image to the Canvas. +// */ +// void Image::draw() { +// unsigned int w, h; +// myLoader->loadPicture(myFile, w, h, myTexture); - glBindTexture(GL_TEXTURE_2D, myTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -} +// glBindTexture(GL_TEXTURE_2D, myTexture); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); +// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +// } -/*! - * \brief Mutator for the center coordinates of the Image. - * \details Alters the values of the myCenterX and myCenterY private variables. - * \param x Float value for the new center x-coordinate. - * \param y Float value for the new center y-coordinate. - * \warning This will also alter the Image's rotation point if and only if the - * old rotation point was at the Image's old center. - */ -void Image::setCenter(float x, float y) { - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - setRotationPoint(x, y); - } - if(myCenterX != x || myCenterY != y) { - float deltaX = x - myCenterX; - float deltaY = y - myCenterY; - for(int i = 0; i < 4; i++) { - vertices[8*i] += deltaX; - vertices[8*i+1] += deltaY; - } - myCenterX = x; - myCenterY = y; - } - attribMutex.unlock(); -} +// /*! +// * \brief Mutator for the center coordinates of the Image. +// * \details Alters the values of the myCenterX and myCenterY private variables. +// * \param x Float value for the new center x-coordinate. +// * \param y Float value for the new center y-coordinate. +// * \warning This will also alter the Image's rotation point if and only if the +// * old rotation point was at the Image's old center. +// */ +// void Image::setCenter(float x, float y) { +// attribMutex.lock(); +// if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { +// setRotationPoint(x, y); +// } +// if(myCenterX != x || myCenterY != y) { +// float deltaX = x - myCenterX; +// float deltaY = y - myCenterY; +// for(int i = 0; i < 4; i++) { +// vertices[8*i] += deltaX; +// vertices[8*i+1] += deltaY; +// } +// myCenterX = x; +// myCenterY = y; +// } +// attribMutex.unlock(); +// } -/*! - * \brief Mutator for the coordinates of the Image. - * \details Alters all coordinate variables for the Image. - * \param deltaX Float value of how much to alter the y-coordinates. - * \param deltaY Float value of how much to alter the y-coordinates. - * \warning This will also alter the Image's rotation point if and only if the - * old rotation point was at the Image's old center. - */ -void Image::moveImageBy(float deltaX, float deltaY) { - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - if(deltaX != 0 || deltaY != 0) { - for(int i = 0; i < 4; i++) { - vertices[8*i] += deltaX; - vertices[8*i+1] += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; - } - attribMutex.unlock(); -} +// /*! +// * \brief Mutator for the coordinates of the Image. +// * \details Alters all coordinate variables for the Image. +// * \param deltaX Float value of how much to alter the y-coordinates. +// * \param deltaY Float value of how much to alter the y-coordinates. +// * \warning This will also alter the Image's rotation point if and only if the +// * old rotation point was at the Image's old center. +// */ +// void Image::moveImageBy(float deltaX, float deltaY) { +// attribMutex.lock(); +// if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { +// myRotationPointX += deltaX; +// myRotationPointY += deltaY; +// } +// if(deltaX != 0 || deltaY != 0) { +// for(int i = 0; i < 4; i++) { +// vertices[8*i] += deltaX; +// vertices[8*i+1] += deltaY; +// } +// myCenterX += deltaX; +// myCenterY += deltaY; +// } +// attribMutex.unlock(); +// } -/*! - * \brief Mutator for the rotation of the Image. - * \details Rotates the Image corners around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Image. - */ -void Image::setRotation(float radians) { - if(radians != currentRotation) { - attribMutex.lock(); - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; - for(int i = 0; i < 4; i++) { - float x = vertices[8*i]; - float y = vertices[8*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; +// /*! +// * \brief Mutator for the rotation of the Image. +// * \details Rotates the Image corners around myRotationPointX, myRotationPointY. +// * \param radians Float value denoting how many radians to rotate the Image. +// */ +// void Image::setRotation(float radians) { +// if(radians != currentRotation) { +// attribMutex.lock(); +// float pivotX = myRotationPointX; +// float pivotY = myRotationPointY; +// float s = sin(radians - currentRotation); +// float c = cos(radians - currentRotation); +// currentRotation = radians; +// for(int i = 0; i < 4; i++) { +// float x = vertices[8*i]; +// float y = vertices[8*i+1]; +// x -= pivotX; +// y -= pivotY; +// float xnew = x * c - y * s; +// float ynew = x * s + y * c; - x = xnew + pivotX; - y = ynew + pivotY; - vertices[8*i] = x; - vertices[8*i+1] = y; - } - attribMutex.unlock(); - } -} +// x = xnew + pivotX; +// y = ynew + pivotY; +// vertices[8*i] = x; +// vertices[8*i+1] = y; +// } +// attribMutex.unlock(); +// } +// } -/*! - * \brief Alters the file the Image draws. - * \details Alters the values of the myFile, myWidth, myHeight, and mutates vertices. - * \param filename New string value for myFile. - * \param width New width of the Image. - * \param height New height of the Image. - */ -void Image::changeFileName(std::string filename, int width, int height) { - attribMutex.lock(); - myFile = filename; - myWidth = width; myHeight = height; - if (myWidth <= 0 || myHeight <= 0) { - TextureHandler::getDimensions(filename,myWidth,myHeight); - } - vertices[0] = myCenterX - myWidth/2; - vertices[1] = myCenterY - myHeight/2; - vertices[8] = myCenterX + myWidth/2; - vertices[9] = myCenterY - myHeight/2; - vertices[16] = myCenterX - myWidth/2; - vertices[17] = myCenterY + myHeight/2; - vertices[24] = myCenterX + myWidth/2; - vertices[25] = myCenterY + myHeight/2; - attribMutex.unlock(); -} +// /*! +// * \brief Alters the file the Image draws. +// * \details Alters the values of the myFile, myWidth, myHeight, and mutates vertices. +// * \param filename New string value for myFile. +// * \param width New width of the Image. +// * \param height New height of the Image. +// */ +// void Image::changeFileName(std::string filename, int width, int height) { +// attribMutex.lock(); +// myFile = filename; +// myWidth = width; myHeight = height; +// if (myWidth <= 0 || myHeight <= 0) { +// TextureHandler::getDimensions(filename,myWidth,myHeight); +// } +// vertices[0] = myCenterX - myWidth/2; +// vertices[1] = myCenterY - myHeight/2; +// vertices[8] = myCenterX + myWidth/2; +// vertices[9] = myCenterY - myHeight/2; +// vertices[16] = myCenterX - myWidth/2; +// vertices[17] = myCenterY + myHeight/2; +// vertices[24] = myCenterX + myWidth/2; +// vertices[25] = myCenterY + myHeight/2; +// attribMutex.unlock(); +// } -} +// } diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index e00841db0..67b5b3a0d 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -1,67 +1,67 @@ -/* - * Image.h extends Shape and provides a class for drawing an image to a Canvas. - */ +// /* +// * Image.h extends Shape and provides a class for drawing an image to a Canvas. +// */ -#ifndef IMAGE_H_ -#define IMAGE_H_ +// #ifndef IMAGE_H_ +// #define IMAGE_H_ -#include +// #include -#include "Drawable.h" // For extending our Shape object -#include "TextureHandler.h" // For loading images -#include "TsglAssert.h" // For unit testing purposes +// #include "Drawable.h" // For extending our Shape object +// #include "TextureHandler.h" // For loading images +// #include "TsglAssert.h" // For unit testing purposes -namespace tsgl { +// namespace tsgl { -/*! \class Image - * \brief Draw an image to the Canvas. - * \details Image is a class which provides a simple interface for loading and drawing images. - * The Image class currently supports files in the .png, .bmp, and .jpg formats. - * \note For the time being, there is no way to measure the size of an image once it's loaded. - * Therefore, the width and height must be specified manually, and stretching may occur if the - * input dimensions don't match the images actual dimensions. - * \note Additionally, an ImageLoader must be passed as an argument. This ImageLoader is automatically - * constructed with the Canvas as the private *loader* variable. At the moment, there is no way to - * extend Canvas::drawImage() function due to this privatization. - * \warning Aside from an error message output to stderr, Image gives no indication if an image failed to load. - */ -class Image : public Drawable { - private: - int myWidth, myHeight; - float currentRotation; - float *vertices; - std::string myFile; - GLtexture myTexture; - TextureHandler* myLoader; - public: - Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha = 1.0f); +// /*! \class Image +// * \brief Draw an image to the Canvas. +// * \details Image is a class which provides a simple interface for loading and drawing images. +// * The Image class currently supports files in the .png, .bmp, and .jpg formats. +// * \note For the time being, there is no way to measure the size of an image once it's loaded. +// * Therefore, the width and height must be specified manually, and stretching may occur if the +// * input dimensions don't match the images actual dimensions. +// * \note Additionally, an ImageLoader must be passed as an argument. This ImageLoader is automatically +// * constructed with the Canvas as the private *loader* variable. At the moment, there is no way to +// * extend Canvas::drawImage() function due to this privatization. +// * \warning Aside from an error message output to stderr, Image gives no indication if an image failed to load. +// */ +// class Image : public Drawable { +// private: +// int myWidth, myHeight; +// float currentRotation; +// float *vertices; +// std::string myFile; +// GLtexture myTexture; +// TextureHandler* myLoader; +// public: +// Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha = 1.0f); - virtual void draw(); +// virtual void draw(); - /*! - * \brief Accessor for the image's height. - * \return The height of the Image. - */ - int getHeight() { return myHeight; } +// /*! +// * \brief Accessor for the image's height. +// * \return The height of the Image. +// */ +// int getHeight() { return myHeight; } - /*! - * \brief Accessor for the image's width. - * \return The width of the Image. - */ - int getWidth() { return myWidth; } +// /*! +// * \brief Accessor for the image's width. +// * \return The width of the Image. +// */ +// int getWidth() { return myWidth; } - void setCenter(float x, float y); +// void setCenter(float x, float y); - void moveImageBy(float deltaX, float deltaY); +// void moveImageBy(float deltaX, float deltaY); - virtual void setRotation(float radians); +// virtual void setRotation(float radians); - void changeFileName(std::string filename, int width = 0, int height = 0); +// void changeFileName(std::string filename, int width = 0, int height = 0); - ~Image() { delete[] vertices; } +// ~Image() { delete[] vertices; } -}; +// }; -} +// } -#endif /* IMAGE_H_ */ \ No newline at end of file +// #endif /* IMAGE_H_ */ \ No newline at end of file diff --git a/src/TSGL/IntegralViewer.cpp b/src/TSGL/IntegralViewer.cpp index c9a324111..841017f40 100644 --- a/src/TSGL/IntegralViewer.cpp +++ b/src/TSGL/IntegralViewer.cpp @@ -1,154 +1,154 @@ -#include "IntegralViewer.h" - -namespace tsgl { - - /*! - * \brief Default IntegralViewer constructor method. - * \details This is the default constructor for the IntegralViewer class. - * \param f A function to integrate and display. The function must accept exactly one argument of type - * Decimal, and return a Decimal. - * \param width The width of the window displaying the integration. - * \param height The height of the window displaying the integration. - * \param startX The minimum x-value whose y-value should be computed. - * \param stopX The maximum x-value whose y-value should be computed. - * \param startY The minimum y-value that should be displayed on the IntegralViewer's Canvas. - * \param stopY The maximum y-value that should be displayed on the IntegralViewer's Canvas. - * \param fname A descriptive name for the function you wish to integrate. - * \return A new IntegralViewer with the specified dimensions, bounds, and function description. - */ -IntegralViewer::IntegralViewer(functionPointer f, int width, int height, Decimal startX, Decimal stopX, Decimal startY, Decimal stopY, std::string fname) { - myF = f; - myWidth = width; myHeight = height; - myStartX = startX; myStopX = stopX; - myStartY = startY; myStopY = stopY; - myRecTime = myTrapTime = 0; - myDelay = FRAME; - std::stringstream ss; - ss.str("Integral of " + fname + " from " + to_string(myStartX) + " to " + to_string(myStopX)); - setupCanvas(myTrapCanvas, ss.str() + " using Trapezoids", myDelay); //Canvas for trapezoid method - setupCanvas(myRecCanvas, ss.str() + " using Rectangles", myDelay); //Canvas for rectangle method -} - - /*! - * \brief IntegralViewer destructor method. - * \details This is the destructor for the IntegralViewer class. - * \details Frees up memory that was allocated to a IntegralViewer instance. - */ -IntegralViewer::~IntegralViewer() { - if (myRecCanvas->isOpen()) - myRecCanvas->stop(); - if (myTrapCanvas->isOpen()) - myTrapCanvas->stop(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - delete myRecCanvas; - delete myTrapCanvas; -} - -void IntegralViewer::drawLabels(CartesianCanvas*& can) { - const int FSIZE = 32; - const float /* cpw = can->getPixelWidth(), */ cph = can->getPixelHeight(); - const float /* xoff = cpw*FSIZE, */ yoff = cph*FSIZE; - - bool blorigin = (myStartX == 0 && myStartY == 0); - bool tlorigin = (myStartX == 0 && myStopY == 0); - - can->drawText(to_string(myStartX), myStartX, myStartY-yoff, FSIZE); - can->drawText(to_string(myStopX), myStopX, myStartY-yoff, FSIZE); - if (!blorigin) - can->drawText(to_string(myStartY), 0, myStartY-1.5f*yoff, FSIZE); - if (!tlorigin) - can->drawText(to_string(myStopY), 0, myStopY, FSIZE); -} - -void IntegralViewer::setupCanvas(CartesianCanvas*& can, const std::string& label, double delay) { - const float BORDER = (myStopX-myStartX)/10.0f; - const float SPACING = BORDER; - can = new CartesianCanvas(-1, -1, myWidth, myHeight, myStartX - BORDER, myStartY - BORDER, - myStopX + BORDER, myStopY + BORDER, label, delay); - - can->setBackgroundColor(ColorFloat(0.95f, 0.95f, 0.95f, 1.0f)); - - can->start(); - - can->drawRectangle(myStartX,myStartY,myStopX - myStartX, myStartY - myStopY,WHITE); //Area we're drawing to - can->drawPartialFunction(myF,myStartX,myStopX,0,ColorInt(0,0,255)); //Outline of function - can->drawAxes(0, 0, SPACING, SPACING); //Axes marks - drawLabels(can); -} - - /*! - * \brief Evaluate an integral using the rectangle method. - * \param numRectangles The number of rectangles to use for the integration. - * \return The area under the curve represented by the IntegralViewer's function, evaluated using - * the rectangle method. - */ -long double IntegralViewer::rectangleEvaluate(long long numRectangles) { - double startTime = omp_get_wtime(); - long double result = 0.0, - recWidth = fabs(myStopX - myStartX) / numRectangles, - halfRecWidth = recWidth / 2.0; - #pragma omp parallel reduction(+:result) - { - Decimal xLo = 0.0, xMid = 0.0, y = 0.0; - ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); - tcol.A = 0.7f; - - #pragma omp for - for (long long i = 0; i < numRectangles; ++i) { - if (!myRecCanvas->isOpen()) continue; - myRecCanvas->sleep(); - xLo = myStartX + i * recWidth; - xMid = xLo + halfRecWidth; - y = (*myF)(xMid); - result += y; - myRecCanvas->drawRectangle(xLo, y, recWidth, y, tcol); - } - result *= recWidth; - } - myRecTime = omp_get_wtime() - startTime; - myRecCanvas->wait(); - return result; -} - - /*! - * \brief Evaluate an integral using the trapezoid method. - * \param numRectangles The number of trapezoids to use for the integration. - * \return The area under the curve represented by the IntegralViewer's function, evaluated using - * the trapezoid method. - */ -long double IntegralViewer::trapezoidEvaluate(long long numTrapezoids) { - double startTime = omp_get_wtime(); - long double result = 0.0, - trapWidth = fabs(myStopX - myStartX) / numTrapezoids, - halfTrapWidth = trapWidth / 2.0; - #pragma omp parallel reduction(+:result) - { - Decimal leftX = 0.0, rightX = 0.0, leftY = 0.0, rightY = 0.0; - Decimal xValues[4] = {0.0}, yValues[4] = {0.0}; - ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); - tcol.A = 0.7; - ColorFloat colorValues[4] = {tcol, tcol, tcol, tcol}; - - #pragma omp for - for (long long i = 0; i < numTrapezoids; ++i) { - if (!myTrapCanvas->isOpen()) continue; - leftX = myStartX + i * trapWidth; - rightX = leftX + trapWidth; - leftY = (*myF)(leftX); - rightY = (*myF)(rightX); - result += ((leftY + rightY) * halfTrapWidth); - - xValues[0] = xValues[1] = leftX; - xValues[2] = xValues[3] = rightX; - yValues[1] = leftY; yValues[2] = rightY; - - myTrapCanvas->drawConvexPolygon(4, xValues, yValues, colorValues); - myTrapCanvas->sleep(); - } - } - myTrapTime = omp_get_wtime() - startTime; - myTrapCanvas->wait(); - return result; -} - -} +// #include "IntegralViewer.h" + +// namespace tsgl { + +// /*! +// * \brief Default IntegralViewer constructor method. +// * \details This is the default constructor for the IntegralViewer class. +// * \param f A function to integrate and display. The function must accept exactly one argument of type +// * Decimal, and return a Decimal. +// * \param width The width of the window displaying the integration. +// * \param height The height of the window displaying the integration. +// * \param startX The minimum x-value whose y-value should be computed. +// * \param stopX The maximum x-value whose y-value should be computed. +// * \param startY The minimum y-value that should be displayed on the IntegralViewer's Canvas. +// * \param stopY The maximum y-value that should be displayed on the IntegralViewer's Canvas. +// * \param fname A descriptive name for the function you wish to integrate. +// * \return A new IntegralViewer with the specified dimensions, bounds, and function description. +// */ +// IntegralViewer::IntegralViewer(functionPointer f, int width, int height, Decimal startX, Decimal stopX, Decimal startY, Decimal stopY, std::string fname) { +// myF = f; +// myWidth = width; myHeight = height; +// myStartX = startX; myStopX = stopX; +// myStartY = startY; myStopY = stopY; +// myRecTime = myTrapTime = 0; +// myDelay = FRAME; +// std::stringstream ss; +// ss.str("Integral of " + fname + " from " + to_string(myStartX) + " to " + to_string(myStopX)); +// setupCanvas(myTrapCanvas, ss.str() + " using Trapezoids", myDelay); //Canvas for trapezoid method +// setupCanvas(myRecCanvas, ss.str() + " using Rectangles", myDelay); //Canvas for rectangle method +// } + +// /*! +// * \brief IntegralViewer destructor method. +// * \details This is the destructor for the IntegralViewer class. +// * \details Frees up memory that was allocated to a IntegralViewer instance. +// */ +// IntegralViewer::~IntegralViewer() { +// if (myRecCanvas->isOpen()) +// myRecCanvas->stop(); +// if (myTrapCanvas->isOpen()) +// myTrapCanvas->stop(); +// std::this_thread::sleep_for(std::chrono::milliseconds(20)); +// delete myRecCanvas; +// delete myTrapCanvas; +// } + +// void IntegralViewer::drawLabels(CartesianCanvas*& can) { +// const int FSIZE = 32; +// const float /* cpw = can->getPixelWidth(), */ cph = can->getPixelHeight(); +// const float /* xoff = cpw*FSIZE, */ yoff = cph*FSIZE; + +// bool blorigin = (myStartX == 0 && myStartY == 0); +// bool tlorigin = (myStartX == 0 && myStopY == 0); + +// can->drawText(to_string(myStartX), myStartX, myStartY-yoff, FSIZE); +// can->drawText(to_string(myStopX), myStopX, myStartY-yoff, FSIZE); +// if (!blorigin) +// can->drawText(to_string(myStartY), 0, myStartY-1.5f*yoff, FSIZE); +// if (!tlorigin) +// can->drawText(to_string(myStopY), 0, myStopY, FSIZE); +// } + +// void IntegralViewer::setupCanvas(CartesianCanvas*& can, const std::string& label, double delay) { +// const float BORDER = (myStopX-myStartX)/10.0f; +// const float SPACING = BORDER; +// can = new CartesianCanvas(-1, -1, myWidth, myHeight, myStartX - BORDER, myStartY - BORDER, +// myStopX + BORDER, myStopY + BORDER, label, delay); + +// can->setBackgroundColor(ColorFloat(0.95f, 0.95f, 0.95f, 1.0f)); + +// can->start(); + +// can->drawRectangle(myStartX,myStartY,myStopX - myStartX, myStartY - myStopY,WHITE); //Area we're drawing to +// can->drawPartialFunction(myF,myStartX,myStopX,0,ColorInt(0,0,255)); //Outline of function +// can->drawAxes(0, 0, SPACING, SPACING); //Axes marks +// drawLabels(can); +// } + +// /*! +// * \brief Evaluate an integral using the rectangle method. +// * \param numRectangles The number of rectangles to use for the integration. +// * \return The area under the curve represented by the IntegralViewer's function, evaluated using +// * the rectangle method. +// */ +// long double IntegralViewer::rectangleEvaluate(long long numRectangles) { +// double startTime = omp_get_wtime(); +// long double result = 0.0, +// recWidth = fabs(myStopX - myStartX) / numRectangles, +// halfRecWidth = recWidth / 2.0; +// #pragma omp parallel reduction(+:result) +// { +// Decimal xLo = 0.0, xMid = 0.0, y = 0.0; +// ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); +// tcol.A = 0.7f; + +// #pragma omp for +// for (long long i = 0; i < numRectangles; ++i) { +// if (!myRecCanvas->isOpen()) continue; +// myRecCanvas->sleep(); +// xLo = myStartX + i * recWidth; +// xMid = xLo + halfRecWidth; +// y = (*myF)(xMid); +// result += y; +// myRecCanvas->drawRectangle(xLo, y, recWidth, y, tcol); +// } +// result *= recWidth; +// } +// myRecTime = omp_get_wtime() - startTime; +// myRecCanvas->wait(); +// return result; +// } + +// /*! +// * \brief Evaluate an integral using the trapezoid method. +// * \param numRectangles The number of trapezoids to use for the integration. +// * \return The area under the curve represented by the IntegralViewer's function, evaluated using +// * the trapezoid method. +// */ +// long double IntegralViewer::trapezoidEvaluate(long long numTrapezoids) { +// double startTime = omp_get_wtime(); +// long double result = 0.0, +// trapWidth = fabs(myStopX - myStartX) / numTrapezoids, +// halfTrapWidth = trapWidth / 2.0; +// #pragma omp parallel reduction(+:result) +// { +// Decimal leftX = 0.0, rightX = 0.0, leftY = 0.0, rightY = 0.0; +// Decimal xValues[4] = {0.0}, yValues[4] = {0.0}; +// ColorFloat tcol = Colors::highContrastColor(omp_get_thread_num()); +// tcol.A = 0.7; +// ColorFloat colorValues[4] = {tcol, tcol, tcol, tcol}; + +// #pragma omp for +// for (long long i = 0; i < numTrapezoids; ++i) { +// if (!myTrapCanvas->isOpen()) continue; +// leftX = myStartX + i * trapWidth; +// rightX = leftX + trapWidth; +// leftY = (*myF)(leftX); +// rightY = (*myF)(rightX); +// result += ((leftY + rightY) * halfTrapWidth); + +// xValues[0] = xValues[1] = leftX; +// xValues[2] = xValues[3] = rightX; +// yValues[1] = leftY; yValues[2] = rightY; + +// myTrapCanvas->drawConvexPolygon(4, xValues, yValues, colorValues); +// myTrapCanvas->sleep(); +// } +// } +// myTrapTime = omp_get_wtime() - startTime; +// myTrapCanvas->wait(); +// return result; +// } + +// } diff --git a/src/TSGL/IntegralViewer.h b/src/TSGL/IntegralViewer.h index 1c418a111..a47522fe3 100644 --- a/src/TSGL/IntegralViewer.h +++ b/src/TSGL/IntegralViewer.h @@ -1,64 +1,64 @@ -/* - * IntegralViewer.h - */ +// /* +// * IntegralViewer.h +// */ -#ifndef INTEGRALVIEWER_H_ -#define INTEGRALVIEWER_H_ +// #ifndef INTEGRALVIEWER_H_ +// #define INTEGRALVIEWER_H_ -#include -#include -#include -#include -#include "Util.h" //Decimal typedef +// #include +// #include +// #include +// #include +// #include "Util.h" //Decimal typedef -namespace tsgl { +// namespace tsgl { -/*! \class IntegralViewer - * \brief Provides a a tool for computing and visualizing integrals of functions - * \details IntegralViewer provides a simple interface for integrating functions and outputting the results of the - * integration, both numerically and visually. IntegralViewer can evaluate an arbitrary function of the type - * Decimal myFunction(Decimal x), where x is the input value of the function and the return value is - * the y value of the function. IntegralViewer can compute integrals using one or both of the rectangle method - * and the trapezoid method, and provides functions for displaying both on a custom Canvas. Furthermore, these - * computations and visualizations are thread-safe; the number of threads to use can be set with - * omp_set_num_threads(). - */ -class IntegralViewer { -private: - functionPointer myF; - int myWidth, myHeight; - long double myStartX, myStopX, myStartY, myStopY; - double myRecTime, myTrapTime, myDelay; - CartesianCanvas *myRecCanvas, *myTrapCanvas; +// /*! \class IntegralViewer +// * \brief Provides a a tool for computing and visualizing integrals of functions +// * \details IntegralViewer provides a simple interface for integrating functions and outputting the results of the +// * integration, both numerically and visually. IntegralViewer can evaluate an arbitrary function of the type +// * Decimal myFunction(Decimal x), where x is the input value of the function and the return value is +// * the y value of the function. IntegralViewer can compute integrals using one or both of the rectangle method +// * and the trapezoid method, and provides functions for displaying both on a custom Canvas. Furthermore, these +// * computations and visualizations are thread-safe; the number of threads to use can be set with +// * omp_set_num_threads(). +// */ +// class IntegralViewer { +// private: +// functionPointer myF; +// int myWidth, myHeight; +// long double myStartX, myStopX, myStartY, myStopY; +// double myRecTime, myTrapTime, myDelay; +// CartesianCanvas *myRecCanvas, *myTrapCanvas; - void drawLabels(CartesianCanvas*& can); - void setupCanvas(CartesianCanvas*& can, const std::string& label = "", double delay = 0.0); +// void drawLabels(CartesianCanvas*& can); +// void setupCanvas(CartesianCanvas*& can, const std::string& label = "", double delay = 0.0); -public: +// public: - IntegralViewer(functionPointer f, int width, int height, Decimal startX, Decimal stopX, Decimal startY = 0, Decimal stopY = 1, - std::string fname = "function"); +// IntegralViewer(functionPointer f, int width, int height, Decimal startX, Decimal stopX, Decimal startY = 0, Decimal stopY = 1, +// std::string fname = "function"); - ~IntegralViewer(); +// ~IntegralViewer(); - /*! - * \brief Accessor for the time the canvas spent integrating using the rectangle method. - * \return The elapsed time in seconds for the integration using rectangles. - */ - double getRecTime() const { return myRecTime; } +// /*! +// * \brief Accessor for the time the canvas spent integrating using the rectangle method. +// * \return The elapsed time in seconds for the integration using rectangles. +// */ +// double getRecTime() const { return myRecTime; } - /*! - * \brief Accessor for the time the canvas spent integrating using the trapezoid method. - * \return The elapsed time in seconds for the integration using trapezoids. - */ - double getTrapTime() const { return myTrapTime; } +// /*! +// * \brief Accessor for the time the canvas spent integrating using the trapezoid method. +// * \return The elapsed time in seconds for the integration using trapezoids. +// */ +// double getTrapTime() const { return myTrapTime; } - long double rectangleEvaluate(long long numRectangles); +// long double rectangleEvaluate(long long numRectangles); - long double trapezoidEvaluate(long long numTrapezoids); -}; +// long double trapezoidEvaluate(long long numTrapezoids); +// }; -} +// } -#endif /* INTEGRALVIEWER_H_ */ +// #endif /* INTEGRALVIEWER_H_ */ diff --git a/src/TSGL/Line.cpp b/src/TSGL/Line.cpp index ddb1223c3..b79afa597 100644 --- a/src/TSGL/Line.cpp +++ b/src/TSGL/Line.cpp @@ -12,9 +12,10 @@ namespace tsgl { * \param color The reference variable to the color of the Line. * \return A new Line with the specified endpoints and color. */ -Line::Line(int x1, int y1, int x2, int y2, const ColorFloat color) : Polyline(2) { - addVertex(x1, y1, color); - addVertex(x2, y2, color); +Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color) : Polyline(x,y,z,2,yaw,pitch,roll) { + addVertex(-0.5, 0, 0, color); + addVertex(0.5, 0, 0, color); + myXScale = length; } /*! @@ -27,46 +28,40 @@ Line::Line(int x1, int y1, int x2, int y2, const ColorFloat color) : Polyline(2) * \param color An array for the colors of the line endpoints. * \return A new Line with the specified endpoints and colors. */ -Line::Line(int x1, int y1, int x2, int y2, const ColorFloat color[]) : Polyline(2) { - addVertex(x1, y1, color[0]); - addVertex(x2, y2, color[1]); +Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[]) : Polyline(x,y,z,2,yaw,pitch,roll) { + addVertex(-0.5, 0, 0, color[0]); + addVertex(0.5, 0, 0, color[1]); + myXScale = length; } /** - * \brief Moves one end of the Line. - * \details Moves the end of the line originally specified by (x1, y1). - * \param x The new x coordinate. - * \param y The new y coordinate. + * \brief Mutates the line's length to the new parameter value. + * \param length The Prism's new length. */ -void Line::setFirstEnd(float x, float y) { - attribMutex.lock(); - vertices[0] = x; - vertices[1] = y; - attribMutex.unlock(); +void Line::setLength(GLfloat length) { + if (length <= 0) { + TsglDebug("Cannot have a Line with length less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = length; + myLength = length; + attribMutex.unlock(); } /** - * \brief Moves one end of the Line. - * \details Moves the end of the line originally specified by (x2, y2). - * \param x The new x coordinate. - * \param y The new y coordinate. + * \brief Mutates the line's length by the parameter value. + * \param delta The difference between the new and old line lengths. */ -void Line::setSecondEnd(float x, float y) { - attribMutex.lock(); - vertices[6] = x; - vertices[7] = y; - attribMutex.unlock(); +void Line::changeLineLengthBy(GLfloat delta) { + if (myLength + delta <= 0) { + TsglDebug("Cannot have a Line with length less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale += delta; + myLength += delta; + attribMutex.unlock(); } -/** - * \brief Calculates the length of the line. - * \details Finds the distance between the two ends of the line. - * \return Length of the Line. - */ -float Line::getLength() { - attribMutex.lock(); - float length = sqrt((vertices[0]-vertices[2])*(vertices[0]-vertices[2])+(vertices[1]-vertices[3])*(vertices[1]-vertices[3])); - attribMutex.unlock(); - return length; -} } diff --git a/src/TSGL/Line.h b/src/TSGL/Line.h index 283c6e2d5..c72da4c24 100755 --- a/src/TSGL/Line.h +++ b/src/TSGL/Line.h @@ -15,17 +15,22 @@ namespace tsgl { */ class Line : public Polyline { private: - + GLfloat myLength; public: - Line(int x1, int y1, int x2, int y2, const ColorFloat color); + Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color); - Line(int x1, int y1, int x2, int y2, const ColorFloat color[]); + Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[]); - void setFirstEnd(float x, float y); + void setLength(GLfloat length); - void setSecondEnd(float x, float y); + void changeLineLengthBy(GLfloat delta); - float getLength(); + /** + * \brief Returns the length of the line. + * \details Returns the value of the myLength instance variable. + * \return Length of the Line. + */ + GLfloat getLength() { return myLength; } }; } diff --git a/src/TSGL/Object3D.cpp b/src/TSGL/Object3D.cpp deleted file mode 100644 index 037b9951a..000000000 --- a/src/TSGL/Object3D.cpp +++ /dev/null @@ -1,445 +0,0 @@ -#include "Object3D.h" - -namespace tsgl { - -/*! - * \brief Constructs a new Object3D. - * \details - * - Usually vertices is filled with floating point values that represent the vertices of the Object3D to be drawn. - * - You may define other items in the constructor that pertain to the attributes of the subclass that is extending Object3D. - * - At a minimum, you *MUST* fill an array of floating point values that pertain to the vertices of the Object3D. - * \warning You must inherit the parent's constructor if you are extending Object3D. - * \note Refer to the Object3D class description for more details. - */ -Object3D::Object3D(float x, float y, float z, float yaw, float pitch, float roll) : Drawable() { - isTextured = false; - myCurrentYaw = yaw; - myCurrentPitch = pitch; - myCurrentRoll = roll; - myCenterX = x; - myCenterY = y; - myCenterZ = z; - myRotationPointX = myCenterX; - myRotationPointY = myCenterY; - myRotationPointZ = myCenterZ; -} - -/*! - * \brief Draw the Object3D. - * \details This function actually draws the Object3D to the Canvas. - * \note This function does nothing if the vertex buffer is not yet full. - * \note A message indicating that the Object3D cannot be drawn yet will be given - * if the above condition is met (vertex buffer = not full). - */ -void Object3D::draw() { - glPushMatrix(); - glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); - glRotatef(myCurrentYaw, 0, 0, 1); - glRotatef(myCurrentPitch, 0, 1, 0); - glRotatef(myCurrentRoll, 1, 0, 0); - glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); - glScalef(myXScale, myYScale, myZScale); - - /* We have a color array and a vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - glColorPointer(4, GL_FLOAT, 0, colors); - - glDrawArrays(geometryType, 0, numberOfVertices); - - if (edgesOutlined) { - glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); - glColorPointer(4, GL_FLOAT, 0, outlineArray); - - glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); - } - - glPopMatrix(); - - /* Cleanup states */ - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); -} - - /*! - * \brief Adds another vertex to a Object3D. - * \details This function initializes the next vertex in the Object3D and adds it to a Object3D buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param z The z position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Object3D::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - attribMutex.lock(); - vertices[currentVertex] = x; - vertices[currentVertex + 1] = y; - vertices[currentVertex + 2] = z; - currentVertex += 3; - colors[currentColor] = color.R; - colors[currentColor+1] = color.G; - colors[currentColor+2] = color.B; - colors[currentColor+3] = color.A; - currentColor += 4; - attribMutex.unlock(); - if (currentVertex == numberOfVertices*3) { - attribMutex.lock(); - outlineArray = new GLfloat[numberOfOutlineVertices*4]; - std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); - init = true; - attribMutex.unlock(); - } -} - -///////////////////////////////////////////////// -// MUTATORS -///////////////////////////////////////////////// - - -/** - * \brief Sets the Object3D to a new color. - * \param c The new ColorGLfloat. - */ -void Object3D::setColor(ColorGLfloat c) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - colors[i*4] = c.R; - colors[i*4 + 1] = c.G; - colors[i*4 + 2] = c.B; - colors[i*4 + 3] = c.A; - } - attribMutex.unlock(); -} - -/** - * \brief Sets the Object3D's outline/edges to a new color - * \param c The new ColorGLfloat. - */ -void Object3D::setEdgeColor(ColorGLfloat c) { - for (int i = 0; i < numberOfOutlineVertices; i++) { - outlineArray[4*i] = c.R; - outlineArray[4*i+1] = c.G; - outlineArray[4*i+2] = c.B; - outlineArray[4*i+3] = c.A; - } -} - -/** - * \brief Alters the Object3D's x position - * \param deltaX The difference between the new and old vertex x coordinates. - * \warning This will also alter the Object3D's rotation point similarly if and - * only if the old rotation point was at the Object3D's old center. - */ -void Object3D::changeXBy(float deltaX) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointX += deltaX; - } - myCenterX += deltaX; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's y position - * \param deltaY The difference between the new and old vertex y coordinates. - * \warning This will also alter the Object3D's rotation point similarly if and - * only if the old rotation point was at the Object3D's old center. - */ -void Object3D::changeYBy(float deltaY) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointY += deltaY; - } - myCenterY += deltaY; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's z position - * \param deltaZ The difference between the new and old vertex z coordinates. - * \warning This will also alter the Object3D's rotation point similarly if and - * only if the old rotation point was at the Object3D's old center. - */ -void Object3D::changeZBy(float deltaZ) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointZ += deltaZ; - } - myCenterZ += deltaZ; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's vertex locations. - * \param deltaX The difference between the new and old vertex x coordinates. - * \param deltaY The difference between the new and old vertex y coordinates. - * \param deltaZ The difference between the new and old vertex z coordinates. - * \warning This will also alter the Object3D's rotation point similarly if and - * only if the old rotation point was at the Object3D's old center. - */ -void Object3D::changeCenterBy(float deltaX, float deltaY, float deltaZ) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - myRotationPointZ += deltaZ; - } - myCenterX += deltaX; - myCenterY += deltaY; - myCenterZ += deltaZ; - attribMutex.unlock(); -} - -/** - * \brief Sets the Object3D's x position - * \param x The new center x coordinate. - * \warning This will also alter the Object3D's rotation point similarly if and only - * if the old rotation point was at the Object3D's old center. - */ -void Object3D::setCenterX(float x) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointX = x; - } - myCenterX = x; - attribMutex.unlock(); -} - -/** - * \brief Sets the Object3D's y position - * \param y The new center y coordinate. - * \warning This will also alter the Object3D's rotation point similarly if and only - * if the old rotation point was at the Object3D's old center. - */ -void Object3D::setCenterY(float y) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointY = y; - } - myCenterY = y; - attribMutex.unlock(); -} - -/** - * \brief Sets the Object3D's z position - * \param z The new center z coordinate. - * \warning This will also alter the Object3D's rotation point similarly if and only - * if the old rotation point was at the Object3D's old center. - */ -void Object3D::setCenterZ(float z) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointZ = z; - } - myCenterZ = z; - attribMutex.unlock(); -} - -/** - * \brief Moves the Object3D to new coordinates. - * \param x The new center x coordinate. - * \param y The new center y coordinate. - * \param z The new center z coordinate. - * \warning This will also alter the Object3D's rotation point similarly if and only - * if the old rotation point was at the Object3D's old center. - */ -void Object3D::setCenter(float x, float y, float z) { - attribMutex.lock(); - if (centerMatchesRotationPoint()) { - myRotationPointX = x; - myRotationPointY = y; - myRotationPointZ = z; - } - myCenterX = x; - myCenterY = y; - myCenterZ = z; - attribMutex.unlock(); -} - -/** - * \brief Mutator for the Object3D's yaw - * \param yaw The new yaw value for Object3D. - */ -void Object3D::setYaw(float yaw) { - attribMutex.lock(); - myCurrentYaw = yaw; - attribMutex.unlock(); -} - -/** - * \brief Mutator for the Object3D's pitch - * \param pitch The new pitch value for Object3D. - */ -void Object3D::setPitch(float pitch) { - attribMutex.lock(); - myCurrentPitch = pitch; - attribMutex.unlock(); -} - -/** - * \brief Mutator for the Object3D's roll - * \param roll The new roll value for Object3D. - */ -void Object3D::setRoll(float roll) { - attribMutex.lock(); - myCurrentRoll = roll; - attribMutex.unlock(); -} - -/*! - * \brief Mutator for the yaw, pitch, and roll of the Object3D. - * \param yaw The new yaw value for Object3D. - * \param pitch The new pitch value for Object3D. - * \param roll The new roll value for Object3D. - */ -void Object3D::setYawPitchRoll(float yaw, float pitch, float roll) { - attribMutex.lock(); - myCurrentYaw = yaw; - myCurrentPitch = pitch; - myCurrentRoll = roll; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's yaw by a specified amount. - * \param deltaYaw The change in yaw value for Object3D. - */ -void Object3D::changeYawBy(float deltaYaw) { - attribMutex.lock(); - myCurrentYaw += deltaYaw; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's pitch by a specified amount. - * \param deltaPitch The change in pitch value for Object3D. - */ -void Object3D::changePitchBy(float deltaPitch) { - attribMutex.lock(); - myCurrentPitch += deltaPitch; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's roll by a specified amount. - * \param deltaRoll The change in roll value for Object3D. - */ -void Object3D::changeRollBy(float deltaRoll) { - attribMutex.lock(); - myCurrentRoll += deltaRoll; - attribMutex.unlock(); -} - -/** - * \brief Alters the Object3D's yaw, pitch, and roll by a specified amount. - * \param deltaYaw The change in yaw value for Object3D. - * \param deltaPitch The change in pitch value for Object3D. - * \param deltaRoll The change in roll value for Object3D. - */ -void Object3D::changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll) { - attribMutex.lock(); - myCurrentYaw += deltaYaw; - myCurrentPitch += deltaPitch; - myCurrentRoll += deltaRoll; - attribMutex.unlock(); -} - -/** - * \brief Sets the point around which Object3D is rotated. - * \param x The x coordinate of the new rotation point. - * \param y The y coordinate of the new rotation point. - * \param z The z coordinate of the new rotation point. - */ -void Object3D::setRotationPoint(float x, float y, float z) { - attribMutex.lock(); - myRotationPointX = x; - myRotationPointY = y; - myRotationPointZ = z; - attribMutex.unlock(); -} - -/*! - * \brief Virtual mutator that changes the rotation point of the Object3D's z value. - * \details Alters myRotationPointZ; - * \param z myRotationPointZ's new float value. - */ -void Object3D::setRotationPointZ(float z) { - attribMutex.lock(); - myRotationPointZ = z; - attribMutex.unlock(); -} - -/*! - * \brief Accessor for the center x-coordinate of the Object3D. - * \details Returns the value of the myCenterX private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointX; - * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin - * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. - */ -float Object3D::getCenterX() { - if (centerMatchesRotationPoint()) { - return myCenterX; - } - float cosYaw = cos(myCurrentYaw * PI / 180); - float sinYaw = sin(myCurrentYaw * PI / 180); - float cosPitch = cos(myCurrentPitch * PI / 180); - float sinPitch = sin(myCurrentPitch * PI / 180); - float cosRoll = cos(myCurrentPitch * PI / 180); - float sinRoll = sin(myCurrentRoll * PI / 180); - return cosYaw * cosPitch * (myCenterX - myRotationPointX) + (cosYaw * sinPitch * sinRoll - sinYaw * cosRoll) * (myCenterY - myRotationPointY) + (cosYaw * sinPitch * cosRoll + sinYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointX; -} - -/*! - * \brief Accessor for the center z-coordinate of the Object3D. - * \details Returns the value of the myCenterY private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointY; - * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin - * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. - */ -float Object3D::getCenterY() { - if (centerMatchesRotationPoint()) { - return myCenterY; - } - float cosYaw = cos(myCurrentYaw * PI / 180); - float sinYaw = sin(myCurrentYaw * PI / 180); - float cosPitch = cos(myCurrentPitch * PI / 180); - float sinPitch = sin(myCurrentPitch * PI / 180); - float cosRoll = cos(myCurrentPitch * PI / 180); - float sinRoll = sin(myCurrentRoll * PI / 180); - return sinYaw * cosPitch * (myCenterX - myRotationPointX) + (sinYaw * sinPitch * sinRoll + cosYaw * cosRoll) * (myCenterY - myRotationPointY) + (sinYaw * sinPitch * cosRoll - cosYaw * sinRoll) * (myCenterZ - myRotationPointZ) + myRotationPointY; -} - -/*! - * \brief Accessor for the center z-coordinate of the Object3D. - * \details Returns the value of the myCenterZ private variable, rotated by myCurrentYaw, myCurrentPitch, and myCurrentRoll about myRotationPointZ; - * \note See https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin - * \note and http://planning.cs.uiuc.edu/node102.html for more more understanding. - */ -float Object3D::getCenterZ() { - if (centerMatchesRotationPoint()) { - return myCenterZ; - } - float cosYaw = cos(myCurrentYaw * PI / 180); - float sinYaw = sin(myCurrentYaw * PI / 180); - float cosPitch = cos(myCurrentPitch * PI / 180); - float sinPitch = sin(myCurrentPitch * PI / 180); - float cosRoll = cos(myCurrentPitch * PI / 180); - float sinRoll = sin(myCurrentRoll * PI / 180); - return -sinPitch * (myCenterX - myRotationPointX) + cosPitch * sinRoll * (myCenterY - myRotationPointY) + cosPitch * cosRoll * (myCenterZ - myRotationPointZ) + myRotationPointZ; -} - -void Object3D::setRotation(float radians) { - -} - -Object3D::~Object3D() { - delete[] vertices; - delete[] colors; - delete[] outlineArray; -} - -} \ No newline at end of file diff --git a/src/TSGL/Object3D.h b/src/TSGL/Object3D.h deleted file mode 100644 index d748db4dd..000000000 --- a/src/TSGL/Object3D.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Object3D.h provides a base class from which to extend other drawable Object3Ds. - */ - -#ifndef OBJECT3D_H_ -#define OBJECT3D_H_ - -#include "Color.h" // Needed for color type -#include "Drawable.h" - -namespace tsgl { - -/*! \class Object3D - * \brief A class for drawing 3D objects onto a Canvas or CartesianCanvas. - * \warning Though extending this class must be allowed due to the way the code is set up, attempting to do so - * could potentially mess up the internal GL calls the library uses. Proceed with great caution. - * \details Object3D provides a base class for drawing 3D objects to a Canvas or CartesianCanvas. - * \note Object3D is abstract, and must be extended by the user. - * \details vertices should be an array of floating point values in TSGL's vertex format. - * One face consists of 3 vertices per triangle that it is divided into, #FIXME 7? vertices per face. - * E.g., to draw a cube, you would need 6 faces, 2 triangles per face, 3 vertices per triangle, 36 vertices total. - * \details numberofvertices should be the actual integer number of vertices to be drawn (e.g., *36* for a cube). - * \details geometryType should be one of GL's primitive drawing modes. - * See https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml for further information. - * \details Theoretically, you could potentially extend the Object3D class so that you can create another Object3D class that suits your needs. - * \details However, this is not recommended for normal use of the TSGL library. - */ -class Object3D : public Drawable { - protected: - bool edgesOutlined = true; - int numberOfVertices; - int numberOfOutlineVertices; - GLsizei outlineStride = 0; - GLfloat* vertices; - GLfloat* colors; - GLfloat* outlineArray; - int currentVertex = 0; - int currentColor = 0; - float myCurrentYaw, myCurrentPitch, myCurrentRoll; - float myXScale, myYScale, myZScale; - float myCenterZ; // myCenterX and myCenterY inherited - float myRotationPointZ; // myRotationPointX and myRotationPointY inherited - GLenum geometryType; - GLenum outlineGeometryType; - bool init = false; - virtual void addVertex(float x, float y, float z, const ColorGLfloat &color = ColorGLfloat(1,1,1,1)); - - /*! - * \brief Protected helper method that determines if the Object3D's center matches its rotation point. - * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ - * \return True if all three coordinates match their respective others, false otherwise. - */ - bool centerMatchesRotationPoint() { - return (myCenterX == myRotationPointX && myCenterY == myRotationPointY && myCenterZ == myRotationPointZ); - } - public: - Object3D(float yaw, float pitch, float roll, float x, float y, float z); - - virtual ~Object3D(); - - virtual void draw(); - - virtual void setColor(ColorGLfloat c); - /** - * \brief Pure virtual mutator. Sets the Object3D to a new array of colors. - * \param c An array of the new ColorGLfloats. - * \warning Inheriting subclasses MUST define an override method for this method. - */ - virtual void setColor(ColorGLfloat c[]) = 0; - virtual void setEdgeColor(ColorGLfloat c); - - virtual void changeXBy(float deltaX); - virtual void changeYBy(float deltaY); - virtual void changeZBy(float deltaZ); - virtual void changeCenterBy(float deltaX, float deltaY, float deltaZ); - - virtual void setCenterX(float x); - virtual void setCenterY(float y); - virtual void setCenterZ(float z); - virtual void setCenter(float x, float y, float z); - - virtual void setYaw(float yaw); - virtual void setPitch(float pitch); - virtual void setRoll(float roll); - virtual void setYawPitchRoll(float yaw, float pitch, float roll); - - virtual void changeYawBy(float deltaYaw); - virtual void changePitchBy(float deltaPitch); - virtual void changeRollBy(float deltaRoll); - virtual void changeYawPitchRollBy(float deltaYaw, float deltaPitch, float deltaRoll); - - virtual void setRotationPoint(float x, float y, float z); - - virtual void setRotationPointZ(float z); - - virtual float getCenterX(); - - virtual float getCenterY(); - - virtual float getCenterZ(); - - /*! - * \brief Accessor for the Yaw of the Object3D. - * \details Returns the value of the myCurrentYaw private variable. - */ - virtual float getYaw() { return myCurrentYaw; } - - /*! - * \brief Accessor for the Pitch of the Object3D. - * \details Returns the value of the myCurrentPitch private variable. - */ - virtual float getPitch() { return myCurrentPitch; } - - /*! - * \brief Accessor for the Roll of the Drawable. - * \details Returns the value of the myCurrentRoll private variable. - */ - virtual float getRoll() { return myCurrentRoll; } - - /*! - * \brief Accessor for the rotation z-coordinate of the Drawable. - * \details Returns the value of the myRotationPointZ private variable. - */ - virtual float getRotationPointZ() { return myRotationPointZ; } - - virtual void setRotation(float radians); - - /* - * \brief Mutator that determines if the edges of the Object3D should be highlighted. - * \details Updates the value of the edgesOutlined instance variable. Defaults to true. - */ - virtual void displayOutlineEdges(bool on=true) { edgesOutlined=on; } - - - - /*! - * \brief Accessor that returns if Object3D is processed and ready to be drawn - * \details This function returns true only if all vertices have been inserted into an array. - */ - virtual bool isProcessed() { return init; } -}; - -} - -#endif /* OBJECT3D_H_ */ diff --git a/src/TSGL/Polygon.cpp b/src/TSGL/Polygon.cpp deleted file mode 100644 index 3b1ac4a83..000000000 --- a/src/TSGL/Polygon.cpp +++ /dev/null @@ -1,501 +0,0 @@ -#include "Polygon.h" - -namespace tsgl { - - /*! - * \brief Explicitly constructs a new Polygon. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices the number of vertices the complete Polygon will have. - * \warning An invariant is held where if numVertices is less than 3 then an error message is given. - * \return A new Polygon with a buffer for storing the specified numbered of vertices. - */ -Polygon::Polygon(int numVertices) : Shape() { - attribMutex.lock(); - if (numVertices < 3) { - TsglDebug("Cannot have a polygon with fewer than 3 vertices."); - } - attribMutex.unlock(); -} - -/*! - * \brief This method actually draws the Polygon - * \details Depending on isFilled and hasOutline, draws either a series of connected lines outlining the Polygon or a filled version. - */ -void Polygon::draw() { - if(isFilled) { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); - } - if(hasOutline) { - glBufferData(GL_ARRAY_BUFFER, numberOfOutlineVertices * 6 * sizeof(float), outlineVertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_LINE_LOOP, 0, numberOfOutlineVertices); - } -} - - /*! - * \brief Adds another vertex to a Polygon. - * \details This function initializes the next vertex in the Polygon and adds it to a Polygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Polygon::addVertex(float x, float y, const ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = color.R; - outlineVertices[current + 3] = color.G; - outlineVertices[current + 4] = color.B; - outlineVertices[current + 5] = color.A; - } - current += 6; - if (current == numberOfVertices*6) { - init = true; - attribMutex.lock(); - float minX = 0, maxX = 0; - float minY = 0, maxY = 0; - if(hasOutline) { - minX = maxX = outlineVertices[0]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - minY = maxY = outlineVertices[1]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else if (isFilled) { - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - - myCenterX = (minX+maxX)/2; - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); - - attribMutex.unlock(); - } -} - - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param fillColor The reference variable of the fill color of the vertex. - * \param outlineColor The reference variable of the outline color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Polygon::addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - if(isFilled) { - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = fillColor.R; - vertices[current + 3] = fillColor.G; - vertices[current + 4] = fillColor.B; - vertices[current + 5] = fillColor.A; - } - if(hasOutline) { - outlineVertices[current] = x; - outlineVertices[current + 1] = y; - outlineVertices[current + 2] = outlineColor.R; - outlineVertices[current + 3] = outlineColor.G; - outlineVertices[current + 4] = outlineColor.B; - outlineVertices[current + 5] = outlineColor.A; - } - current += 6; - if (current == numberOfVertices*6) { - init = true; - attribMutex.lock(); - float minX = 0, maxX = 0; - float minY = 0, maxY = 0; - if(hasOutline) { - minX = maxX = outlineVertices[0]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6] < minX ) - minX = outlineVertices[i*6]; - else if( outlineVertices[i*6] > maxX ) - maxX = outlineVertices[i*6]; - } - minY = maxY = outlineVertices[1]; - //Find min and max X - for(int i = 0; i < numberOfOutlineVertices; i++) { - if( outlineVertices[i*6+1] < minY ) - minY = outlineVertices[i*6+1]; - else if( outlineVertices[i*6+1] > maxY ) - maxY = outlineVertices[i*6+1]; - } - } else if (isFilled) { - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - } - - myCenterX = (minX+maxX)/2; - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); - - attribMutex.unlock(); - } -} - -/** - * \brief Sets the Polygon to a new color. - * \param c The new ColorFloat. - */ -void Polygon::setColor(ColorFloat c) { - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = c.R; - outlineVertices[i*6 + 3] = c.G; - outlineVertices[i*6 + 4] = c.B; - outlineVertices[i*6 + 5] = c.A; - } - } -} - -/** - * \brief Sets the Polygon to an array of new colors. - * \param c An array of new ColorFloats. - */ -void Polygon::setColor(ColorFloat c[]) { - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = c[i].R; - outlineVertices[i*6 + 3] = c[i].G; - outlineVertices[i*6 + 4] = c[i].B; - outlineVertices[i*6 + 5] = c[i].A; - } - } -} - -/** - * \brief Sets the Polygon to new single fill and outline colors. - * \param fillColor A new ColorFloat for the Polygon's fill. - * \param outlineColor A new ColorFloat for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor, ColorFloat outlineColor) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor.R; - vertices[i*6 + 3] = fillColor.G; - vertices[i*6 + 4] = fillColor.B; - vertices[i*6 + 5] = fillColor.A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor.R; - outlineVertices[i*6 + 3] = outlineColor.G; - outlineVertices[i*6 + 4] = outlineColor.B; - outlineVertices[i*6 + 5] = outlineColor.A; - } -} - -/** - * \brief Gives the Polygon a new monocolored fill and multicolored outline. - * \param fillColor A new ColorFloat for the Polygon's fill. - * \param outlineColor A new array of ColorFloats for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor, ColorFloat outlineColor[]) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor.R; - vertices[i*6 + 3] = fillColor.G; - vertices[i*6 + 4] = fillColor.B; - vertices[i*6 + 5] = fillColor.A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor[i].R; - outlineVertices[i*6 + 3] = outlineColor[i].G; - outlineVertices[i*6 + 4] = outlineColor[i].B; - outlineVertices[i*6 + 5] = outlineColor[i].A; - } -} - -/** - * \brief Gives the Polygon a new multicolored fill and monocolored outline. - * \param fillColor A new array of ColorFloats for the Polygon's fill. - * \param outlineColor A new ColorFloat for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor[], ColorFloat outlineColor) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor[i].R; - vertices[i*6 + 3] = fillColor[i].G; - vertices[i*6 + 4] = fillColor[i].B; - vertices[i*6 + 5] = fillColor[i].A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor.R; - outlineVertices[i*6 + 3] = outlineColor.G; - outlineVertices[i*6 + 4] = outlineColor.B; - outlineVertices[i*6 + 5] = outlineColor.A; - } -} - -/** - * \brief Sets the Polygon to new single fill and outline colors. - * \param fillColor A new array of ColorFloats for the Polygon's fill. - * \param outlineColor A new array of ColorFloats for the Polygon's outline. - */ -void Polygon::setColor(ColorFloat fillColor[], ColorFloat outlineColor[]) { - if(!isFilled || !hasOutline) { - TsglErr("Polygon isn't filled and outlined."); - return; - } - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = fillColor[i].R; - vertices[i*6 + 3] = fillColor[i].G; - vertices[i*6 + 4] = fillColor[i].B; - vertices[i*6 + 5] = fillColor[i].A; - } - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6 + 2] = outlineColor[i].R; - outlineVertices[i*6 + 3] = outlineColor[i].G; - outlineVertices[i*6 + 4] = outlineColor[i].B; - outlineVertices[i*6 + 5] = outlineColor[i].A; - } -} - -/** - * \brief Gets an array of the Polygon's fill vertex colors. - * \return c An array of ColorFloats. - * \warning This method allocates memory. The caller is responsible for deallocating it. - */ -ColorFloat* Polygon::getFillColor() { - ColorFloat * c = new ColorFloat[numberOfVertices]; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(vertices[i*6 + 2], vertices[i*6 + 3], vertices[i*6 + 4], vertices[i*6 + 5]); - } - } else { - TsglErr("Polygon isn't filled."); - for(int i = 0; i < numberOfVertices; i++) { - c[i] = ColorFloat(1.0f, 1.0f, 1.0f, 1.0f); - } - } - return c; -} - -/** - * \brief Gets an array of the Polygon's fill vertex colors. - * \return c An array of ColorFloats. - * \warning This method allocates memory. The caller is responsible for deallocating it. - */ -ColorFloat* Polygon::getOutlineColor() { - ColorFloat * c = new ColorFloat[numberOfOutlineVertices]; - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - c[i] = ColorFloat(outlineVertices[i*6 + 2], outlineVertices[i*6 + 3], outlineVertices[i*6 + 4], outlineVertices[i*6 + 5]); - } - } else { - TsglErr("Polygon isn't outlined."); - for(int i = 0; i < numberOfOutlineVertices; i++) { - c[i] = ColorFloat(1.0f, 1.0f, 1.0f, 1.0f); - } - } - return c; -} - -/** - * \brief Alters the Polygon's vertex locations. - * \param deltaX The difference between the new and old vertex X coordinates. - * \param deltaY The difference between the new and old vertex Y coordinates. - * \warning This will also alter the Polygon's rotation point if and only if the - * old rotation point was at the Polygon's old center. - */ -void Polygon::moveShapeBy(float deltaX, float deltaY) { - attribMutex.lock(); - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6] += deltaX; //Transpose x - outlineVertices[(i*6)+1] += deltaY; //Transpose y - } - } - myCenterX += deltaX; - myCenterY += deltaY; - attribMutex.unlock(); -} - -/** - * \brief Moves the Polygon to new coordinates. - * \param x The new center x coordinate. - * \param y The new center y coordinate. - * \warning This will also alter the Polygon's rotation point if and only if the - * old rotation point was at the Polygon's old center. - */ -void Polygon::setCenter(float x, float y) { - float deltaX = x - myCenterX; //Change for x - float deltaY = y - myCenterY; //Change for y - attribMutex.lock(); - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - setRotationPoint(x,y); - } - myCenterX = x; - myCenterY = y; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - outlineVertices[i*6] += deltaX; //Transpose x - outlineVertices[(i*6)+1] += deltaY; //Transpose y - } - } - attribMutex.unlock(); -} - - -/*! - * \brief Mutator for the rotation of the Polygon. - * \details Rotates the Polygon vertices around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Polygon. - */ -void Polygon::setRotation(float radians) { - if(radians != currentRotation) { - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; - if(isFilled) { - for(int i = 0; i < numberOfVertices; i++) { - float x = vertices[6*i]; - float y = vertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - vertices[6*i] = x; - vertices[6*i+1] = y; - } - } - if(hasOutline) { - for(int i = 0; i < numberOfOutlineVertices; i++) { - float x = outlineVertices[6*i]; - float y = outlineVertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - outlineVertices[6*i] = x; - outlineVertices[6*i+1] = y; - } - } - } -} - -/*! - * \brief Destructor for the Polygon. - */ -Polygon::~Polygon() { - if(hasOutline) { - delete[] outlineVertices; - } - if(isFilled) { - delete[] vertices; - } -} - -} \ No newline at end of file diff --git a/src/TSGL/Polygon.h b/src/TSGL/Polygon.h deleted file mode 100644 index 034311938..000000000 --- a/src/TSGL/Polygon.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Polygon.h extends Shape and provides a class for drawing a polygon. - */ - -#ifndef POLYGON_H_ -#define POLYGON_H_ - -#include "Shape.h" // For extending our Shape object -#include "TsglAssert.h" // For unit testing purposes - -namespace tsgl { - -/*! \class Polygon - * \brief Draw an arbitrary Convex polygon with colored vertices. - * \details Polygon is a class for holding vertex data for a Shape with at least three vertices. - * \note Polygon is abstract, and must be extended. - * \details Vertices are drawn in triangle strip format, where the first three vertices make up the first triangle, - * the next vertex plus the previous two make up the second triangle, and so on. - * \details This method is optimized for long lists and offers a marked improvement over drawing individual Triangle instances. - * \note The addVertex() method must be called the same number of times as specified in the constructor. - * \note Calling addVertex() after all vertices have been added will do nothing. - */ -class Polygon : public Shape { -protected: - bool isFilled = true; - bool hasOutline = false; - float* outlineVertices; - int numberOfOutlineVertices; -public: - - Polygon(int numVertices); - - virtual ~Polygon(); - - virtual void draw(); - - virtual void addVertex(float x, float y, const ColorFloat &color = BLACK); - - virtual void addVertex(float x, float y, const ColorFloat &fillColor, const ColorFloat &outlineColor); - - virtual void setColor(ColorFloat c); - - virtual void setColor(ColorFloat c[]); - - virtual void setColor(ColorFloat fillColor, ColorFloat outlineColor); - - virtual void setColor(ColorFloat fillColor, ColorFloat outlineColor[]); - - virtual void setColor(ColorFloat fillColor[], ColorFloat outlineColor); - - virtual void setColor(ColorFloat fillColor[], ColorFloat outlineColor[]); - - virtual ColorFloat* getFillColor(); - - virtual ColorFloat* getOutlineColor(); - - virtual void moveShapeBy(float deltaX, float deltaY); - - virtual void setCenter(float x, float y); - - virtual void setRotation(float radians); -}; - -} - -#endif /* POLYGON_H_ */ \ No newline at end of file diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index c5c54a99d..75e7357bb 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -5,11 +5,17 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices) : Shape() { +Polyline::Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll) : Shape(x,y,z,yaw,pitch,roll) { if (numVertices < 2) TsglDebug("Cannot have a line with fewer than 2 vertices."); numberOfVertices = numVertices; @@ -21,50 +27,70 @@ Polyline::Polyline(int numVertices) : Shape() { /*! * \brief Explicitly constructs a new monocolored Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. - * \param x Array of x positions for the Polyline vertices. - * \param y Array of y positions for the Polyline vertices. - * \param color Color of the Polyline. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param lineVertices An array of vertices for the Polyline. 3 floats * numVertices, x-y-z. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. + * \param color Color of the Polyline, as a ColorGLfloat. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices, int x[], int y[], ColorFloat color) { +Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(x,y,z,yaw,pitch,roll) { if (numVertices < 2) TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; + numberOfOutlineVertices = 0; + edgesOutlined = false; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; geometryType = GL_LINE_STRIP; for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); + addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color); } + attribMutex.unlock(); } /*! * \brief Explicitly constructs a new multicolored Polyline. * \details Explicit constructor for a new Polyline object. - * \param numVertices The number of vertices the complete Polyline will have. - * \param x Array of x positions for the Polyline vertices. - * \param y Array of y positions for the Polyline vertices. - * \param color Color of the Polyline. + * \param x The x coordinate of the center of the Polyline. + * \param y The y coordinate of the center of the Polyline. + * \param z The z coordinate of the center of the Polyline. + * \param numVertices The number of vertices in the Polyline. + * \param lineVertices An array of vertices for the Polyline. 3 floats * numVertices, x-y-z. + * \param yaw The Polyline's yaw. + * \param pitch The Polyline's pitch. + * \param roll The Polyline's roll. + * \param color Array of ColorGLfloats for the Polyline; 1 ColorGLfloat per vertex. * \warning An invariant is held where if v is less than 2 then an error message is given. * \return A new Polyline with a buffer for storing the specified numbered of vertices. */ -Polyline::Polyline(int numVertices, int x[], int y[], ColorFloat color[]) { +Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(x,y,z,yaw,pitch,roll) { if (numVertices < 2) - TsglDebug("Cannot have a line with fewer than 2 vertices."); + TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; + numberOfOutlineVertices = 0; + edgesOutlined = false; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; geometryType = GL_LINE_STRIP; for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); + addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color[i]); } + attribMutex.unlock(); } /*! - * \brief Overrides isProcessed() in Shape.h - * \details Overrides Shape::isProcessed() to include invariant. + * \brief Overrides isProcessed() in Drawable.h + * \details Overrides Drawable::isProcessed() to include invariant. */ bool Polyline::isProcessed() { if (numberOfVertices < 2) { diff --git a/src/TSGL/Polyline.h b/src/TSGL/Polyline.h index 2e74da147..5ab2c388a 100755 --- a/src/TSGL/Polyline.h +++ b/src/TSGL/Polyline.h @@ -14,27 +14,22 @@ namespace tsgl { * \details Polyline is a class for holding vertex data for multiple lines whose endpoints are connected. * \details This method is optimized for long lists and offers a marked improvement over drawing individual * Line instances. - * \note The addVertex() method must be called the same number of times as specified in the constructor. + * \note The addVertex() method must be called the same number of times as specified in the constructor, unless a float array is also passed. * \note Calling addVertex() after all vertices have been added will do nothing. - * \note Calling draw() before all vertices have been added will do nothing. + * \note Calling Drawable::draw() before all vertices have been added will do nothing. */ class Polyline : public Shape { private: public: - Polyline(int numVertices); + Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll); - Polyline(int numVertices, int x[], int y[], ColorFloat color); + Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorGLfloat color); - Polyline(int numVertices, int x[], int y[], ColorFloat color[]); + Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorGLfloat color[]); bool isProcessed(); - - /*! - * \brief Destructor for the Polyline. - */ - ~Polyline() { delete[] vertices; } }; } diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index be0ff6b2d..18847ee81 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (radius <= 0 || height <= 0 || sides < 3) { TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); } @@ -37,23 +37,22 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - GLfloat half = myHeight/2; for (int i = 0; i < mySides; i++) { - addVertex(cos(TWOPI * i / mySides), half, sin(TWOPI * i / mySides), c); - addVertex(0,half,0, c); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); + addVertex(0,0.5,0, c); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c); - addVertex(cos(TWOPI * i / mySides), half, sin(TWOPI * i / mySides), c); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c); - addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); - addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c); - addVertex(0,-half,0, c); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); + addVertex(0,-0.5,0, c); } } @@ -73,7 +72,7 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { if (radius <= 0 || height <= 0 || sides < 3) { TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); } @@ -92,28 +91,27 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; attribMutex.unlock(); - GLfloat half = myHeight/2; for (int i = 0; i < mySides; i++) { - addVertex(cos(TWOPI * i / mySides), half, sin(TWOPI * i / mySides), c[1]); - addVertex(0,half,0, c[0]); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c[1]); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[1]); + addVertex(0,0.5,0, c[0]); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[1]); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c[2]); - addVertex(cos(TWOPI * i / mySides), half, sin(TWOPI * i / mySides), c[2]); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c[2]); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[2]); + addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[2]); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[2]); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c[2]); - addVertex(cos(TWOPI * (i + 1) / mySides), half, sin(TWOPI * (i + 1) / mySides), c[2]); - addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c[2]); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[2]); + addVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), c[2]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[2]); - addVertex(cos(TWOPI * (i + 1) / mySides), -half, sin(TWOPI * (i + 1) / mySides), c[3]); - addVertex(cos(TWOPI * i / mySides), -half, sin(TWOPI * i / mySides), c[3]); - addVertex(0,-half,0, c[4]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[3]); + addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[3]); + addVertex(0,-0.5,0, c[4]); } } /** - * \brief Mutates the distance from the center of the Prism's base to the tip. + * \brief Mutates the distance from the Prism's bottom to its top. * \param height The Prism's new height. */ void Prism::setHeight(GLfloat height) { @@ -128,7 +126,7 @@ void Prism::setHeight(GLfloat height) { } /** - * \brief Mutates the distance from the center of the Prism's base to the tip by the parameter amount. + * \brief Mutates the distance from the Prism's bottom to its top by the parameter amount. * \param delta The amount by which to change the height of the Prism. */ void Prism::changeHeightBy(GLfloat delta) { @@ -143,8 +141,8 @@ void Prism::changeHeightBy(GLfloat delta) { } /** - * \brief Mutates the distance from the center of the Prism's base to the tip. - * \param height The Prism's new height. + * \brief Mutates the distance from the center of the Prism's base to the corners. + * \param radius The Prism's new radius. */ void Prism::setRadius(GLfloat radius) { if (radius <= 0) { @@ -159,8 +157,8 @@ void Prism::setRadius(GLfloat radius) { } /** - * \brief Mutates the distance from the center of the Prism's base to the tip by the parameter amount. - * \param delta The amount by which to change the height of the Prism. + * \brief Mutates the distance from the center of the Prism's base to the corner by the parameter amount. + * \param delta The amount by which to change the radius of the Prism. */ void Prism::changeRadiusBy(GLfloat delta) { if (myRadius + delta <= 0) { diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h index 580ea434a..aaabd63f1 100644 --- a/src/TSGL/Prism.h +++ b/src/TSGL/Prism.h @@ -1,11 +1,11 @@ /* - * Prism.h extends Object3D and provides a class for drawing a prism. + * Prism.h extends Drawable and provides a class for drawing a prism. */ #ifndef PRISM_H_ #define PRISM_H_ -#include "Object3D.h" // For extending our Object3D object +#include "Drawable.h" // For extending our Drawable object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Prism with colored vertices. * \details Prism is a class for holding vertex data for a Prism with a base with at least 3 sides. */ -class Prism : public Object3D { +class Prism : public Drawable { protected: GLfloat myHeight; GLfloat myRadius; @@ -46,7 +46,7 @@ class Prism : public Object3D { */ virtual GLfloat getHeight() { return myHeight; } - virtual void setColor(ColorGLfloat c) { Object3D::setColor(c); } + virtual void setColor(ColorGLfloat c) { Drawable::setColor(c); } virtual void setColor(ColorGLfloat c[]); }; diff --git a/src/TSGL/ProgressBar.cpp b/src/TSGL/ProgressBar.cpp index 51ca3288c..aa6e4ddd1 100644 --- a/src/TSGL/ProgressBar.cpp +++ b/src/TSGL/ProgressBar.cpp @@ -1,87 +1,87 @@ -#include "ProgressBar.h" +// #include "ProgressBar.h" -namespace tsgl { +// namespace tsgl { - /*! - * \brief Explicit ProgressBar constructor method. - * \details This is the explicit constructor for the ProgressBar class. - * \param x The x position of the left edge of the ProgressBar. - * \param y The y position of the top edge of the ProgressBar. - * \param width The maximum width in pixels of the ProgressBar. - * \param height The maximum height in pixels of the ProgressBar. - * \param minValue The minimum value represented by the ProgressBar. - * \param maxValue The maximum value represented by the ProgressBar. - * \param numSegments The number of segments in the progress bar - * \return A new ProgressBar with the specified coordinates, maximum dimensions, value range, and segments. - */ -ProgressBar::ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments) { - startX = new float[numSegments]; - endX = new float[numSegments]; - min = minValue; max = maxValue; - xx = x; yy = y; - myWidth = width; myHeight = height; - segs = numSegments; - startX[0] = x; endX[0] = x + myWidth/segs; - for (int i = 1; i < segs; ++i) { - startX[i] = endX[i-1]; - endX[i] = startX[i] + myWidth/segs; - } -} +// /*! +// * \brief Explicit ProgressBar constructor method. +// * \details This is the explicit constructor for the ProgressBar class. +// * \param x The x position of the left edge of the ProgressBar. +// * \param y The y position of the top edge of the ProgressBar. +// * \param width The maximum width in pixels of the ProgressBar. +// * \param height The maximum height in pixels of the ProgressBar. +// * \param minValue The minimum value represented by the ProgressBar. +// * \param maxValue The maximum value represented by the ProgressBar. +// * \param numSegments The number of segments in the progress bar +// * \return A new ProgressBar with the specified coordinates, maximum dimensions, value range, and segments. +// */ +// ProgressBar::ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments) { +// startX = new float[numSegments]; +// endX = new float[numSegments]; +// min = minValue; max = maxValue; +// xx = x; yy = y; +// myWidth = width; myHeight = height; +// segs = numSegments; +// startX[0] = x; endX[0] = x + myWidth/segs; +// for (int i = 1; i < segs; ++i) { +// startX[i] = endX[i-1]; +// endX[i] = startX[i] + myWidth/segs; +// } +// } - /*! - * \brief ProgressBar destructor method. - * \details This is the destructor for the ProgressBar class. - * \details Frees up memory that was allocated to a ProgressBar instance. - */ -ProgressBar::~ProgressBar() { - delete [] startX; delete [] endX; -} +// /*! +// * \brief ProgressBar destructor method. +// * \details This is the destructor for the ProgressBar class. +// * \details Frees up memory that was allocated to a ProgressBar instance. +// */ +// ProgressBar::~ProgressBar() { +// delete [] startX; delete [] endX; +// } - /*! - * \brief Updates a ProgressBar segment with a new value. - * \details This function updates the segment seg of the ProgressBar to represent - * the new value newV. If newV is less than the segment's minimum value, the segment - * is set to its minimum value. If newV is more than the segment's maximum value, the segment - * is set to its maximum value. - * \param newValue The value to set the segment to. - * \param segnum The segment whose value to update. A value of -1 indicates the current thread number. - * \note The minimum value for a segment is calculated as minV + (maxV-minV)*seg/segs - * \note The maximum value for a segment is calculated as minV + (maxV-minV)*(seg+1)/segs - */ -void ProgressBar::update(float newValue, int segnum) { - if (segnum == -1) - segnum = omp_get_thread_num(); - float d = max-min; - float start = min + (d * segnum)/segs; - float end = start + d/segs; - clamp(newValue,start,end); - float percent = (newValue-start) / (end-start); - endX[segnum] = startX[segnum]+percent*(myWidth/segs); -} +// /*! +// * \brief Updates a ProgressBar segment with a new value. +// * \details This function updates the segment seg of the ProgressBar to represent +// * the new value newV. If newV is less than the segment's minimum value, the segment +// * is set to its minimum value. If newV is more than the segment's maximum value, the segment +// * is set to its maximum value. +// * \param newValue The value to set the segment to. +// * \param segnum The segment whose value to update. A value of -1 indicates the current thread number. +// * \note The minimum value for a segment is calculated as minV + (maxV-minV)*seg/segs +// * \note The maximum value for a segment is calculated as minV + (maxV-minV)*(seg+1)/segs +// */ +// void ProgressBar::update(float newValue, int segnum) { +// if (segnum == -1) +// segnum = omp_get_thread_num(); +// float d = max-min; +// float start = min + (d * segnum)/segs; +// float end = start + d/segs; +// clamp(newValue,start,end); +// float percent = (newValue-start) / (end-start); +// endX[segnum] = startX[segnum]+percent*(myWidth/segs); +// } - /*! - * \brief Accessor for the ProgressBar's representative Polyline array. - * \param index Index of the segment to access. - * \return A pointer to the Polyline array representing segment border i of the ProgressBar. - */ -Polyline* ProgressBar::getBorder(int index) { - int y2 = yy+myHeight; - Polyline* p = new Polyline(5); - p->addVertex(startX[index],yy,BLACK); - p->addVertex(startX[index]+myWidth/segs,yy,BLACK); - p->addVertex(startX[index]+myWidth/segs,y2,BLACK); - p->addVertex(startX[index],y2,BLACK); - p->addVertex(startX[index],yy,BLACK); - return p; -} +// /*! +// * \brief Accessor for the ProgressBar's representative Polyline array. +// * \param index Index of the segment to access. +// * \return A pointer to the Polyline array representing segment border i of the ProgressBar. +// */ +// Polyline* ProgressBar::getBorder(int index) { +// int y2 = yy+myHeight; +// Polyline* p = new Polyline(5); +// p->addVertex(startX[index],yy,BLACK); +// p->addVertex(startX[index]+myWidth/segs,yy,BLACK); +// p->addVertex(startX[index]+myWidth/segs,y2,BLACK); +// p->addVertex(startX[index],y2,BLACK); +// p->addVertex(startX[index],yy,BLACK); +// return p; +// } - /*! - * \brief Accessor for the ProgressBar's representative Rectangle array. - * \param index Index of the segment to access. - * \return A pointer to the Rectangle array representing segment i of the ProgressBar. - */ -Rectangle* ProgressBar::getRect(int index) { - return new Rectangle(startX[index], yy, endX[index]-startX[index], myHeight, Colors::highContrastColor(index)); -} +// /*! +// * \brief Accessor for the ProgressBar's representative Rectangle array. +// * \param index Index of the segment to access. +// * \return A pointer to the Rectangle array representing segment i of the ProgressBar. +// */ +// Rectangle* ProgressBar::getRect(int index) { +// return new Rectangle(startX[index], yy, endX[index]-startX[index], myHeight, Colors::highContrastColor(index)); +// } -} +// } diff --git a/src/TSGL/ProgressBar.h b/src/TSGL/ProgressBar.h index 184afd757..936bf89e0 100755 --- a/src/TSGL/ProgressBar.h +++ b/src/TSGL/ProgressBar.h @@ -1,60 +1,60 @@ -/* - * ProgressBar.h extends Shape and provides a class for drawing a progress bar to a Canvas. - */ +// /* +// * ProgressBar.h extends Shape and provides a class for drawing a progress bar to a Canvas. +// */ -#ifndef PROGRESSBAR_H -#define PROGRESSBAR_H +// #ifndef PROGRESSBAR_H +// #define PROGRESSBAR_H -#include +// #include -#include "Polyline.h" -#include "Rectangle.h" +// #include "Polyline.h" +// #include "Rectangle.h" -namespace tsgl { +// namespace tsgl { -/*! \class ProgressBar - * \brief Draws and updates a progress bar. - * \details ProgressBar is a class for holding vertex data for multiple rectangles forming a progress bar. - * ProgressBar is formed of multiple segments, each of which is thread-safe and updated individually - * with the update() method. A ProgressBar can be drawn to the screen using Canvas::drawProgress(). - */ -class ProgressBar { - private: - float *startX, *endX; - float min, max; - int xx, yy, myWidth, myHeight, segs; - public: +// /*! \class ProgressBar +// * \brief Draws and updates a progress bar. +// * \details ProgressBar is a class for holding vertex data for multiple rectangles forming a progress bar. +// * ProgressBar is formed of multiple segments, each of which is thread-safe and updated individually +// * with the update() method. A ProgressBar can be drawn to the screen using Canvas::drawProgress(). +// */ +// class ProgressBar { +// private: +// float *startX, *endX; +// float min, max; +// int xx, yy, myWidth, myHeight, segs; +// public: - ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments); +// ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments); - ~ProgressBar(); +// ~ProgressBar(); - void update(float newValue, int segnum = -1); +// void update(float newValue, int segnum = -1); - Polyline* getBorder(int index); +// Polyline* getBorder(int index); - Rectangle* getRect(int index); +// Rectangle* getRect(int index); - /*! - * \brief Accessor for the ProgressBar's number of segments - * \return The number of segments in the ProgressBar. - */ - int getSegs() { return segs; } +// /*! +// * \brief Accessor for the ProgressBar's number of segments +// * \return The number of segments in the ProgressBar. +// */ +// int getSegs() { return segs; } - /*! - * \brief Accessor for a segment's x position - * \param i Index of the segment - * \return The x-coordinate of the left edge of segment i in the ProgressBar. - */ - int getSegX(int i) { return startX[i]; } +// /*! +// * \brief Accessor for a segment's x position +// * \param i Index of the segment +// * \return The x-coordinate of the left edge of segment i in the ProgressBar. +// */ +// int getSegX(int i) { return startX[i]; } - /*! - * \brief Accessor for a segment's y position - * \return The y-coordinate of the top edge of the ProgressBar. - */ - int getSegY() { return yy; } -}; +// /*! +// * \brief Accessor for a segment's y position +// * \return The y-coordinate of the top edge of the ProgressBar. +// */ +// int getSegY() { return yy; } +// }; -} +// } -#endif /* PROGRESSBAR_H */ +// #endif /* PROGRESSBAR_H */ diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index 146714548..4faacfdb7 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -19,7 +19,7 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } @@ -69,7 +69,7 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h index 1c3f97954..357edb214 100644 --- a/src/TSGL/Pyramid.h +++ b/src/TSGL/Pyramid.h @@ -1,11 +1,11 @@ /* - * Pyramid.h extends Object3D and provides a class for drawing a pyramid. + * Pyramid.h extends Drawable and provides a class for drawing a pyramid. */ #ifndef PYRAMID_H_ #define PYRAMID_H_ -#include "Object3D.h" // For extending our Object3D object +#include "Drawable.h" // For extending our Drawable object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Pyramid with colored vertices. * \details Pyramid is a class for holding vertex data for a pyramid with a base with at least 3 sides. */ -class Pyramid : public Object3D { +class Pyramid : public Drawable { protected: GLfloat myHeight; GLfloat myRadius; diff --git a/src/TSGL/Rectangle.cpp b/src/TSGL/Rectangle.cpp index bd3053f34..7b3c52a84 100644 --- a/src/TSGL/Rectangle.cpp +++ b/src/TSGL/Rectangle.cpp @@ -14,11 +14,17 @@ namespace tsgl { * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and color. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat color, bool filled) : ConvexPolygon(4, filled, !filled) { - addVertex(x, y, color); - addVertex(x + width, y, color); - addVertex(x + width, y + height, color); - addVertex(x, y + height, color); +Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_QUADS; + myXScale = myWidth = width; + myYScale = myHeight = height; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color); + addVertex(-0.5, -0.5, 0, color); + addVertex(0.5, -0.5, 0, color); + addVertex(0.5, 0.5, 0, color); } /*! @@ -33,83 +39,77 @@ Rectangle::Rectangle(float x, float y, float width, float height, const ColorFlo * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and colors. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat color[], bool filled) : ConvexPolygon(4, filled, !filled) { - addVertex(x, y, color[0]); - addVertex(x + width, y, color[1]); - addVertex(x + width, y + height, color[2]); - addVertex(x, y + height, color[3]); +Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_QUADS; + myXScale = myWidth = width; + myYScale = myHeight = height; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color[0]); + addVertex(-0.5, -0.5, 0, color[1]); + addVertex(0.5, -0.5, 0, color[2]); + addVertex(0.5, 0.5, 0, color[3]); } -/*! - * \brief Explicitly constructs a Rectangle with different monocolored fill and outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor The color of the Rectangle's fill - * \param outlineColor The color of the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the left side of the Rectangle base to its right side. + * \param width The Rectangle's new width. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor, outlineColor); - addVertex(x + width, y, fillColor, outlineColor); - addVertex(x + width, y + height, fillColor, outlineColor); - addVertex(x, y + height, fillColor, outlineColor); +void Rectangle::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have a Rectangle with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = width; + myXScale = width; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with multicolored fill and monocolored outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor An array of colors for the Rectangle's fill - * \param outlineColor The color of the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the left side of the Rectangle base to its right side by the parameter amount. + * \param delta The amount by which to change the width of the Rectangle. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor[0], outlineColor); - addVertex(x + width, y, fillColor[1], outlineColor); - addVertex(x + width, y + height, fillColor[2], outlineColor); - addVertex(x, y + height, fillColor[3], outlineColor); +void Rectangle::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have a Rectangle with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth += delta; + myXScale += delta; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with monocolored fill and multicolored outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor The color of the Rectangle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the top side of the Rectangle base to its bottom side. + * \param height The Rectangle's new height. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor, outlineColor[0]); - addVertex(x + width, y, fillColor, outlineColor[1]); - addVertex(x + width, y + height, fillColor, outlineColor[2]); - addVertex(x, y + height, fillColor, outlineColor[3]); +void Rectangle::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = height; + myYScale = height; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a Rectangle with different multicolored fill and outline. - * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. - * \param width The width of the Rectangle. - * \param height The height of the Rectangle. - * \param fillColor An array of colors for the Circle's fill - * \param outlineColor An array of colors for the Rectangle's outline - * \return A new Rectangle with the specified top left corner, dimensions, and coloring. +/** + * \brief Mutates the distance from the top side of the Rectangle base to its bottom side by the parameter amount. + * \param delta The amount by which to change the height of the Rectangle. */ -Rectangle::Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(4, true, true) { - addVertex(x, y, fillColor[0], outlineColor[0]); - addVertex(x + width, y, fillColor[1], outlineColor[1]); - addVertex(x + width, y + height, fillColor[2], outlineColor[2]); - addVertex(x, y + height, fillColor[3], outlineColor[3]); +void Rectangle::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have a Rectangle with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); } } diff --git a/src/TSGL/Rectangle.h b/src/TSGL/Rectangle.h index 651bdc87f..b403057c1 100755 --- a/src/TSGL/Rectangle.h +++ b/src/TSGL/Rectangle.h @@ -15,20 +15,31 @@ namespace tsgl { */ class Rectangle : public ConvexPolygon { private: - + GLfloat myWidth, myHeight; public: + Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorGLfloat color); - Rectangle(float x, float y, float width, float height, const ColorFloat color, bool filled = true); + Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorGLfloat color[]); - Rectangle(float x, float y, float width, float height, const ColorFloat color[], bool filled = true); + /*! + * \brief Accessor for the width of the Rectangle. + * \details Returns the value of the myWidth private variable, a GLfloat. + */ + GLfloat getWidth() { return myWidth; } - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor); + /*! + * \brief Accessor for the height of the Rectangle. + * \details Returns the value of the myHeight private variable, a GLfloat. + */ + GLfloat getHeight() { return myHeight; } - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor); + void setWidth(GLfloat width); - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor, const ColorFloat outlineColor[]); + void setHeight(GLfloat height); - Rectangle(float x, float y, float width, float height, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + void changeWidthBy(GLfloat delta); + + void changeHeightBy(GLfloat delta); }; } diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index 7d02cb3d1..1e5f517a0 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -14,12 +14,15 @@ namespace tsgl { * \param filled Whether the regular polygon should be filled * (set to true by default). */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color, bool filled) : ConvexPolygon(sides, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), color); - } +RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + attribMutex.unlock(); + float delta = 2.0f / sides * PI; + for (int i = 0; i < sides; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color); + } } /*! @@ -34,91 +37,48 @@ RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const * \param filled Whether the regular polygon should be filled * (set to true by default). */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color[], bool filled) : ConvexPolygon(sides, filled, !filled) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), color[i]); - } +RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { + attribMutex.lock(); + myXScale = myYScale = myRadius = radius; + myZScale = 1; + mySides = sides; + attribMutex.unlock(); + float delta = 2.0f / sides * PI; + for (int i = 0; i < sides; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + } } -/*! - * \brief Explicitly constructs a new RegularPolygon with different monocolored fill and outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param fillColor The color of the regular polygon's fill. - * \param outlineColor The color of the regular polygon's outline. +/** + * \brief Mutates the distance from the center of the RegularPolygon base to its vertices. + * \param radius The RegularPolygon's new radius. */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor, outlineColor); - } +void RegularPolygon::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a RegularPolygon with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + attribMutex.unlock(); } -/*! - * \brief Explicitly constructs a new RegularPolygon with multicolored fill and monocolored outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor An array of colors for the regular polygon's fill. - * \param outlineColor The color of the regular polygon's outline. - */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor[i], outlineColor); - } -} - -/*! - * \brief Explicitly constructs a new RegularPolygon with monocolored fill and multicolored outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor The color of the regular polygon's fill. - * \param outlineColor An array of colors for the regular polygon's outline. - */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor, outlineColor[i]); - } -} - -/*! - * \brief Explicitly constructs a new RegularPolygon with different multicolored fill and outline. - * \details This function draws a regular polygon with the given center, radius, resolution - * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param fillColor An array of colors for the regular polygon's fill. - * \param outlineColor An array of colors for the regular polygon's outline. +/** + * \brief Mutates the distance from the center of the RegularPolygon to its vertices by the parameter amount. + * \param delta The amount by which to change the radius of the RegularPolygon. */ -RegularPolygon::RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(sides, true, true) { - //TODO: do we need any locking here? All the values we use below are from the constructor - float delta = 2.0f / sides * PI; - for (int i = 0; i < sides; ++i) { - addVertex(x+radius*cos(i*delta), y+radius*sin(i*delta), fillColor[i], outlineColor[i]); - } +void RegularPolygon::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a RegularPolygon with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myRadius += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/RegularPolygon.h b/src/TSGL/RegularPolygon.h index fb3b8ac0e..1779b1310 100644 --- a/src/TSGL/RegularPolygon.h +++ b/src/TSGL/RegularPolygon.h @@ -9,26 +9,35 @@ namespace tsgl { - /*! \class RegularPolygon - * \brief Draw a regular polygon. - * \details RegularPolygon is a class for holding ConvexPolygon data for a regular polygon. - */ - class RegularPolygon : public ConvexPolygon { - public: - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color, bool filled = true); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat color[], bool filled = true); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - RegularPolygon(float x, float y, float radius, int sides, const ColorFloat fillColor[], const ColorFloat outlineColor[]); - - - }; +/*! \class RegularPolygon +* \brief Draw a regular polygon. +* \details RegularPolygon is a class for holding ConvexPolygon data for a regular polygon. +*/ +class RegularPolygon : public ConvexPolygon { +protected: + GLfloat myRadius; + int mySides; +public: + RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorGLfloat color); + + RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorGLfloat color[]); + + /*! + * \brief Accessor for the number of sides of the RegularPolygon. + * \details Returns the value of the mySides private variable, an int. + */ + int getSides() { return mySides; } + + /*! + * \brief Accessor for the radius of the RegularPolygon. + * \details Returns the value of the myRadius private variable, a GLfloat. + */ + GLfloat getRadius() { return myRadius; } + + void setRadius(GLfloat radius); + + void changeRadiusBy(GLfloat delta); +}; } diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index 7bf8bf805..ea9c42809 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -11,87 +11,18 @@ namespace tsgl { * \warning You must inherit the parent's constructor if you are extending Shape. * \note Refer to the Shape class description for more details. */ -Shape::Shape() : Drawable() { - isTextured = false; - currentRotation = 0; - myCenterX = myCenterY = 0; -} - -/*! - * \brief Draw the Shape. - * \details This function actually draws the Shape to the Canvas. - * \note This function does nothing if the vertex buffer is not yet full. - * \note A message indicating that the Shape cannot be drawn yet will be given - * if the above condition is met (vertex buffer = not full). - */ -void Shape::draw() { - glBufferData(GL_ARRAY_BUFFER, numberOfVertices * 6 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); -} - - /*! - * \brief Adds another vertex to a Shape. - * \details This function initializes the next vertex in the Shape and adds it to a Shape buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Shape::addVertex(float x, float y, const ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - vertices[current] = x; - vertices[current + 1] = y; - vertices[current + 2] = color.R; - vertices[current + 3] = color.G; - vertices[current + 4] = color.B; - vertices[current + 5] = color.A; - current += 6; - if (current == numberOfVertices*6) { - init = true; - attribMutex.lock(); - - float minX, maxX; - minX = maxX = vertices[0]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6] < minX ) - minX = vertices[i*6]; - else if( vertices[i*6] > maxX ) - maxX = vertices[i*6]; - } - myCenterX = (minX+maxX)/2; - - float minY, maxY; - minY = maxY = vertices[1]; - //Find min and max X - for(int i = 0; i < numberOfVertices; i++) { - if( vertices[i*6+1] < minY ) - minY = vertices[i*6+1]; - else if( vertices[i*6+1] > maxY ) - maxY = vertices[i*6+1]; - } - myCenterY = (minY+maxY)/2; - - setRotationPoint(myCenterX, myCenterY); - - attribMutex.unlock(); - } -} +Shape::Shape(float x, float y, float z, float yaw, float pitch, float roll) : Drawable(x,y,z,yaw,pitch,roll) { } /** * \brief Sets the Shape to a new color. * \param c The new ColorFloat. */ -void Shape::setColor(ColorFloat c) { +void Shape::setColor(ColorGLfloat c) { for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c.R; - vertices[i*6 + 3] = c.G; - vertices[i*6 + 4] = c.B; - vertices[i*6 + 5] = c.A; + colors[i*4] = c.R; + colors[i*4 + 1] = c.G; + colors[i*4 + 2] = c.B; + colors[i*4 + 3] = c.A; } } @@ -99,91 +30,13 @@ void Shape::setColor(ColorFloat c) { * \brief Sets the Shape to a new array of colors. * \param c The new array of ColorFloats. */ -void Shape::setColor(ColorFloat c[]) { - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6 + 2] = c[i].R; - vertices[i*6 + 3] = c[i].G; - vertices[i*6 + 4] = c[i].B; - vertices[i*6 + 5] = c[i].A; - } -} - -/** - * \brief Alters the Shape's vertex locations. - * \param deltaX The difference between the new and old vertex X coordinates. - * \param deltaY The difference between the new and old vertex Y coordinates. - * \warning This will also alter the Shape's rotation point if and only if the - * old rotation point was at the Shape's old center. - */ -void Shape::moveShapeBy(float deltaX, float deltaY) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; - attribMutex.unlock(); -} - -/** - * \brief Moves the Shape to new coordinates. - * \param x The new center x coordinate. - * \param y The new center y coordinate. - * \warning This will also alter the Shape's rotation point if and only if the - * old rotation point was at the Shape's old center. - */ -void Shape::setCenter(float x, float y) { - float deltaX = x - myCenterX; //Change for x - float deltaY = y - myCenterY; //Change for y - attribMutex.lock(); - if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { - myRotationPointX = x; - myRotationPointY = y; - } - - myCenterX = x; - myCenterY = y; - - for(int i = 0; i < numberOfVertices; i++) { - vertices[i*6] += deltaX; //Transpose x - vertices[(i*6)+1] += deltaY; //Transpose y - } - attribMutex.unlock(); -} - -/*! - * \brief Mutator for the rotation of the Shape. - * \details Rotates the Shape vertices around myRotationPointX, myRotationPointY. - * \param radians Float value denoting how many radians to rotate the Shape. - */ -void Shape::setRotation(float radians) { - if(radians != currentRotation) { - attribMutex.lock(); - float pivotX = myRotationPointX; - float pivotY = myRotationPointY; - float s = sin(radians - currentRotation); - float c = cos(radians - currentRotation); - currentRotation = radians; +void Shape::setColor(ColorGLfloat c[]) { for(int i = 0; i < numberOfVertices; i++) { - float x = vertices[6*i]; - float y = vertices[6*i+1]; - x -= pivotX; - y -= pivotY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + pivotX; - y = ynew + pivotY; - vertices[6*i] = x; - vertices[6*i+1] = y; + colors[i*4] = c[i].R; + colors[i*4 + 1] = c[i].G; + colors[i*4 + 2] = c[i].B; + colors[i*4 + 3] = c[i].A; } - attribMutex.unlock(); - } } } \ No newline at end of file diff --git a/src/TSGL/Shape.h b/src/TSGL/Shape.h index 5eeef2c07..261f5ce26 100755 --- a/src/TSGL/Shape.h +++ b/src/TSGL/Shape.h @@ -27,35 +27,12 @@ namespace tsgl { * \details However, this is not recommended for normal use of the TSGL library. */ class Shape : public Drawable { - protected: - int numberOfVertices; - float* vertices; - GLenum geometryType; - bool init = false; - int current = 0; - float currentRotation; public: - Shape(); + Shape(float x, float y, float z, float yaw, float pitch, float roll); - virtual void draw(); + virtual void setColor(ColorGLfloat c); - virtual void addVertex(float x, float y, const ColorFloat &color = BLACK); - - virtual void setColor(ColorFloat c); - - virtual void setColor(ColorFloat c[]); - - virtual void moveShapeBy(float deltaX, float deltaY); - - virtual void setCenter(float x, float y); - - virtual void setRotation(float radians); - - /*! - * \brief Accessor that returns if Shape is processed and ready to be drawn - * \details This function returns true only if all vertices have been inserted into an array. - */ - virtual bool isProcessed() { return init; } + virtual void setColor(ColorGLfloat c[]); }; } diff --git a/src/TSGL/Spectrogram.cpp b/src/TSGL/Spectrogram.cpp index 843dc5daa..a0b85ecef 100644 --- a/src/TSGL/Spectrogram.cpp +++ b/src/TSGL/Spectrogram.cpp @@ -1,183 +1,183 @@ -#include "Spectrogram.h" +// #include "Spectrogram.h" -namespace tsgl { +// namespace tsgl { -const int Spectrogram::B = 16; -const float Spectrogram::PI = 3.149f; +// const int Spectrogram::B = 16; +// const float Spectrogram::PI = 3.149f; - /*! - * \brief Explicit Spectrogram constructor method. - * \details This is the explicit constructor for the Spectrogram class. - * \param drawMode Method used for displaying spectral data. Can be one of CIRCULAR - * or HORIZONTAL. - * \param width The width of the Spectrogram canvas. - * \param height The height of the Spectrogram canvas. This value is ignored for - * HORIZONTAL Spectrograms. Setting this to -1 sets the width automatically. - * \return A new Spectrogram with the specified drawing mode and size. - */ -Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { - for (int i = 0; i < NUM_COLORS; ++i) - omp_init_lock(&(writelock[i])); - omp_init_lock(&masterlock); - myWidth = width; - myHeight = (height > 0) ? height : width; - myDrawMode = drawMode; - if (myDrawMode == HORIZONTAL) - myHeight = NUM_COLORS; - else if (myDrawMode == VERTICAL) - myWidth = NUM_COLORS; +// /*! +// * \brief Explicit Spectrogram constructor method. +// * \details This is the explicit constructor for the Spectrogram class. +// * \param drawMode Method used for displaying spectral data. Can be one of CIRCULAR +// * or HORIZONTAL. +// * \param width The width of the Spectrogram canvas. +// * \param height The height of the Spectrogram canvas. This value is ignored for +// * HORIZONTAL Spectrograms. Setting this to -1 sets the width automatically. +// * \return A new Spectrogram with the specified drawing mode and size. +// */ +// Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { +// for (int i = 0; i < NUM_COLORS; ++i) +// omp_init_lock(&(writelock[i])); +// omp_init_lock(&masterlock); +// myWidth = width; +// myHeight = (height > 0) ? height : width; +// myDrawMode = drawMode; +// if (myDrawMode == HORIZONTAL) +// myHeight = NUM_COLORS; +// else if (myDrawMode == VERTICAL) +// myWidth = NUM_COLORS; - can = new Canvas(-1, 0, myWidth, myHeight ,""); - maxCount = 0; - count[0] = 0; - xx[0] = (myWidth)/2; - yy[0] = (myHeight)/2; - col[0] = WHITE; - black[0] = BLACK; - for (unsigned i = 1; i < NUM_COLORS; ++i) { - count[i] = 0; - xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2; - yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2; - col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); - black[i] = col[i] * 0.25f; - } - count[NUM_COLORS] = 0; - xx[NUM_COLORS] = xx[1]; - yy[NUM_COLORS] = yy[1]; - col[NUM_COLORS] = col[1]; - black[NUM_COLORS] = black[1]; - for (int k = 0; k < NUM_COLORS+1; ++k) { - maxx[k] = xx[k]; - maxy[k] = yy[k]; - } - can->start(); -} +// can = new Canvas(-1, 0, myWidth, myHeight ,""); +// maxCount = 0; +// count[0] = 0; +// xx[0] = (myWidth)/2; +// yy[0] = (myHeight)/2; +// col[0] = WHITE; +// black[0] = BLACK; +// for (unsigned i = 1; i < NUM_COLORS; ++i) { +// count[i] = 0; +// xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2; +// yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2; +// col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); +// black[i] = col[i] * 0.25f; +// } +// count[NUM_COLORS] = 0; +// xx[NUM_COLORS] = xx[1]; +// yy[NUM_COLORS] = yy[1]; +// col[NUM_COLORS] = col[1]; +// black[NUM_COLORS] = black[1]; +// for (int k = 0; k < NUM_COLORS+1; ++k) { +// maxx[k] = xx[k]; +// maxy[k] = yy[k]; +// } +// can->start(); +// } - /*! - * \brief Spectrogram destructor method. - * \details This is the destructor for the Spectrogram class. - * \details Frees up memory that was allocated to a Spectrogram instance. - */ -Spectrogram::~Spectrogram() { - for (int i = 0; i < NUM_COLORS; ++i) - omp_destroy_lock(&(writelock[i])); - omp_destroy_lock(&masterlock); - delete can; -} +// /*! +// * \brief Spectrogram destructor method. +// * \details This is the destructor for the Spectrogram class. +// * \details Frees up memory that was allocated to a Spectrogram instance. +// */ +// Spectrogram::~Spectrogram() { +// for (int i = 0; i < NUM_COLORS; ++i) +// omp_destroy_lock(&(writelock[i])); +// omp_destroy_lock(&masterlock); +// delete can; +// } - /*! - * \brief Updates a spectrogram with new data, using locks for thread safety. - * \details This function adds the value of weight to the hue specified - * by index, and adds the value (decay^n)* - * weight to all hues n steps away from index. - * \param index Index of the hue to update. Value is taken mod 256. - * \param weight The value to add to index. - * \param decay Falloff for weight upon adjacent values. - */ -void Spectrogram::updateLocked(int index, float weight, float decay) { - int i = index % NUM_COLORS; - omp_set_lock(&(writelock[i])); - count[i] += weight; - if (count[i] > maxCount) maxCount = count[i]; - omp_unset_lock(&(writelock[i])); - weight *= decay; - for (int k = 1; k < NUM_COLORS/2; ++k) { - i = (index + k) % NUM_COLORS; - omp_set_lock(&(writelock[i])); - count[i] += weight; - if (count[i] > maxCount) maxCount = count[i]; - omp_unset_lock(&(writelock[i])); - i = (index + NUM_COLORS - k) % NUM_COLORS; - omp_set_lock(&(writelock[i])); - count[i] += weight; - maxCount > count[i] ? true : maxCount = count[i]; - if (count[i] > maxCount) maxCount = count[i]; - omp_unset_lock(&(writelock[i])); - weight *= decay; - } -} +// /*! +// * \brief Updates a spectrogram with new data, using locks for thread safety. +// * \details This function adds the value of weight to the hue specified +// * by index, and adds the value (decay^n)* +// * weight to all hues n steps away from index. +// * \param index Index of the hue to update. Value is taken mod 256. +// * \param weight The value to add to index. +// * \param decay Falloff for weight upon adjacent values. +// */ +// void Spectrogram::updateLocked(int index, float weight, float decay) { +// int i = index % NUM_COLORS; +// omp_set_lock(&(writelock[i])); +// count[i] += weight; +// if (count[i] > maxCount) maxCount = count[i]; +// omp_unset_lock(&(writelock[i])); +// weight *= decay; +// for (int k = 1; k < NUM_COLORS/2; ++k) { +// i = (index + k) % NUM_COLORS; +// omp_set_lock(&(writelock[i])); +// count[i] += weight; +// if (count[i] > maxCount) maxCount = count[i]; +// omp_unset_lock(&(writelock[i])); +// i = (index + NUM_COLORS - k) % NUM_COLORS; +// omp_set_lock(&(writelock[i])); +// count[i] += weight; +// maxCount > count[i] ? true : maxCount = count[i]; +// if (count[i] > maxCount) maxCount = count[i]; +// omp_unset_lock(&(writelock[i])); +// weight *= decay; +// } +// } - /*! - * \brief Updates a spectrogram with new data, using critical sections for thread safety. - * \details This function adds the value of weight to the hue specified - * by index, and adds the value (decay^n)* - * weight to all hues n steps away from index. - * \param index Index of the hue to update. Value is taken mod 256. - * \param weight The value to add to index. - * \param decay Falloff for weight upon adjacent values. - */ -void Spectrogram::updateCritical(int index, float weight, float decay) { - int i = index % NUM_COLORS; - #pragma omp critical - { - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - weight *= decay; - for (int k = 1; k < NUM_COLORS/2; ++k) { - i = (index + k) % NUM_COLORS; - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - i = (index + NUM_COLORS - k) % NUM_COLORS; - count[i] += weight; - if (count[i] > maxCount) - maxCount = count[i]; - weight *= decay; - } - } -} +// /*! +// * \brief Updates a spectrogram with new data, using critical sections for thread safety. +// * \details This function adds the value of weight to the hue specified +// * by index, and adds the value (decay^n)* +// * weight to all hues n steps away from index. +// * \param index Index of the hue to update. Value is taken mod 256. +// * \param weight The value to add to index. +// * \param decay Falloff for weight upon adjacent values. +// */ +// void Spectrogram::updateCritical(int index, float weight, float decay) { +// int i = index % NUM_COLORS; +// #pragma omp critical +// { +// count[i] += weight; +// if (count[i] > maxCount) +// maxCount = count[i]; +// weight *= decay; +// for (int k = 1; k < NUM_COLORS/2; ++k) { +// i = (index + k) % NUM_COLORS; +// count[i] += weight; +// if (count[i] > maxCount) +// maxCount = count[i]; +// i = (index + NUM_COLORS - k) % NUM_COLORS; +// count[i] += weight; +// if (count[i] > maxCount) +// maxCount = count[i]; +// weight *= decay; +// } +// } +// } - /*! - * \brief Updates the image on the spectrogram. - * \details This function updates the Spectrogram's Canvas with the data since the last - * call to update() and redraws it. - * \param ratio The scaling of the visualizer. Accepts values between 0.0f and 1.0f. - */ -void Spectrogram::draw(float ratio) { - if (maxCount > 0) { - const float DELTA = (2*PI)/NUM_COLORS; - float localmax = maxCount; - float invcount = 1.0f/localmax; - float mult = ratio*myHeight*sqrt(invcount); - switch (myDrawMode) { - case RADIAL: - for (int k = 0; k < MAX_COLOR; ++k) { - float kroot = mult*sqrt(count[k]); - xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; - yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; - col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); - } - xx[NUM_COLORS] = xx[1]; - yy[NUM_COLORS] = yy[1]; - col[NUM_COLORS] = col[1]; - can->drawConvexPolygon(NUM_COLORS+1,maxx,maxy,black,true); - can->drawConvexPolygon(NUM_COLORS+1,xx,yy,col,true); - break; - case HORIZONTAL: - can->pauseDrawing(); - for (int k = 0; k < MAX_COLOR; ++k) - can->drawLine(0,k,(ratio*myWidth*count[k])/localmax,k,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); - can->resumeDrawing(); - break; - case VERTICAL: - can->pauseDrawing(); - // can->clear(); - for (int k = 0; k < MAX_COLOR; ++k) - can->drawLine(k,myHeight,k,myHeight-(ratio*myHeight*count[k])/localmax,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); - can->resumeDrawing(); - break; - } - } -} +// /*! +// * \brief Updates the image on the spectrogram. +// * \details This function updates the Spectrogram's Canvas with the data since the last +// * call to update() and redraws it. +// * \param ratio The scaling of the visualizer. Accepts values between 0.0f and 1.0f. +// */ +// void Spectrogram::draw(float ratio) { +// if (maxCount > 0) { +// const float DELTA = (2*PI)/NUM_COLORS; +// float localmax = maxCount; +// float invcount = 1.0f/localmax; +// float mult = ratio*myHeight*sqrt(invcount); +// switch (myDrawMode) { +// case RADIAL: +// for (int k = 0; k < MAX_COLOR; ++k) { +// float kroot = mult*sqrt(count[k]); +// xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; +// yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; +// col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); +// } +// xx[NUM_COLORS] = xx[1]; +// yy[NUM_COLORS] = yy[1]; +// col[NUM_COLORS] = col[1]; +// can->drawConvexPolygon(NUM_COLORS+1,maxx,maxy,black,true); +// can->drawConvexPolygon(NUM_COLORS+1,xx,yy,col,true); +// break; +// case HORIZONTAL: +// can->pauseDrawing(); +// for (int k = 0; k < MAX_COLOR; ++k) +// can->drawLine(0,k,(ratio*myWidth*count[k])/localmax,k,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); +// can->resumeDrawing(); +// break; +// case VERTICAL: +// can->pauseDrawing(); +// // can->clear(); +// for (int k = 0; k < MAX_COLOR; ++k) +// can->drawLine(k,myHeight,k,myHeight-(ratio*myHeight*count[k])/localmax,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); +// can->resumeDrawing(); +// break; +// } +// } +// } - /*! - * \brief Finishes the spectrogram. - * \details This function tells the Spectrogram to free all of its memory and close - * down its Canvas. - */ -void Spectrogram::finish() { - can->wait(); -} +// /*! +// * \brief Finishes the spectrogram. +// * \details This function tells the Spectrogram to free all of its memory and close +// * down its Canvas. +// */ +// void Spectrogram::finish() { +// can->wait(); +// } -} +// } diff --git a/src/TSGL/Spectrogram.h b/src/TSGL/Spectrogram.h index e06fc63ba..6ee052c45 100644 --- a/src/TSGL/Spectrogram.h +++ b/src/TSGL/Spectrogram.h @@ -1,56 +1,56 @@ -/* - * Spectrogram.h - */ +// /* +// * Spectrogram.h +// */ -#ifndef SRC_TSGL_SPECTROGRAM_H_ -#define SRC_TSGL_SPECTROGRAM_H_ +// #ifndef SRC_TSGL_SPECTROGRAM_H_ +// #define SRC_TSGL_SPECTROGRAM_H_ -#include +// #include -#include "Canvas.h" -#include "Color.h" +// #include "Canvas.h" +// #include "Color.h" -namespace tsgl { +// namespace tsgl { -enum SpectrogramDrawmode { - RADIAL = 0, - HORIZONTAL = 1, - VERTICAL = 2 -}; +// enum SpectrogramDrawmode { +// RADIAL = 0, +// HORIZONTAL = 1, +// VERTICAL = 2 +// }; -/*! \class Spectrogram - * \brief Displays a spectrogram of a given data set. - * \details Spectrogram is a class for visualizing data as a color spectrum. - * This data will typically be hues, but Spectrogram will accept any data - * mapping to an integer value between 0 and 255. - */ -class Spectrogram { -private: - static const int B; //Border - static const float PI; +// /*! \class Spectrogram +// * \brief Displays a spectrogram of a given data set. +// * \details Spectrogram is a class for visualizing data as a color spectrum. +// * This data will typically be hues, but Spectrogram will accept any data +// * mapping to an integer value between 0 and 255. +// */ +// class Spectrogram { +// private: +// static const int B; //Border +// static const float PI; - omp_lock_t writelock[NUM_COLORS], masterlock; - int myHeight, myWidth; - float maxCount; - int xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; - float count[NUM_COLORS+1]; - ColorFloat col[NUM_COLORS+1], black[NUM_COLORS+1]; - SpectrogramDrawmode myDrawMode; - Canvas* can; -public: - Spectrogram(SpectrogramDrawmode drawMode, int width, int height = -1); +// omp_lock_t writelock[NUM_COLORS], masterlock; +// int myHeight, myWidth; +// float maxCount; +// int xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; +// float count[NUM_COLORS+1]; +// ColorFloat col[NUM_COLORS+1], black[NUM_COLORS+1]; +// SpectrogramDrawmode myDrawMode; +// Canvas* can; +// public: +// Spectrogram(SpectrogramDrawmode drawMode, int width, int height = -1); - ~Spectrogram(); +// ~Spectrogram(); - void updateLocked(int index, float weight = 1.0f, float decay = 0.8f); +// void updateLocked(int index, float weight = 1.0f, float decay = 0.8f); - void updateCritical(int index, float weight = 1.0f, float decay = 0.8f); +// void updateCritical(int index, float weight = 1.0f, float decay = 0.8f); - void draw(float ratio); +// void draw(float ratio); - void finish(); -}; +// void finish(); +// }; -} +// } -#endif /* SRC_TSGL_SPECTROGRAM_H_ */ +// #endif /* SRC_TSGL_SPECTROGRAM_H_ */ diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 79fac046e..bb2c88148 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -16,7 +16,7 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ -Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Object3D(x, y, z, yaw, pitch, roll) { +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } @@ -59,7 +59,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ -Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Object3D(x, y, z, yaw, pitch, roll) { +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } diff --git a/src/TSGL/Sphere.h b/src/TSGL/Sphere.h index 74561a3e4..81aeaf015 100644 --- a/src/TSGL/Sphere.h +++ b/src/TSGL/Sphere.h @@ -1,11 +1,11 @@ /* - * Sphere.h extends Object3D and provides a class for drawing a sphere. + * Sphere.h extends Drawable and provides a class for drawing a sphere. */ #ifndef SPHERE_H_ #define SPHERE_H_ -#include "Object3D.h" // For extending our Object3D object +#include "Drawable.h" // For extending our Drawable object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Sphere with colored vertices. * \details Sphere is a class for holding vertex data for a Sphere with non-negative radius. */ -class Sphere : public Object3D { +class Sphere : public Drawable { protected: GLfloat myRadius; int horizontalSections, verticalSections; diff --git a/src/TSGL/Square.cpp b/src/TSGL/Square.cpp index 15dfe0708..289bea6be 100644 --- a/src/TSGL/Square.cpp +++ b/src/TSGL/Square.cpp @@ -12,8 +12,17 @@ namespace tsgl { * \param filled Whether the Square should be filled * (set to true by default). */ -Square::Square(float x, float y, float sideLength, const ColorFloat color, bool filled) -: Rectangle(x,y,sideLength,sideLength,color,filled) { } //Create an Rectangle with equal width and height +Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_QUADS; + myXScale = myYScale = mySideLength = sideLength; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color); + addVertex(-0.5, -0.5, 0, color); + addVertex(0.5, -0.5, 0, color); + addVertex(0.5, 0.5, 0, color); +} /*! * \brief Explicitly constructs a new Square with multicolored fill or outline. @@ -25,55 +34,46 @@ Square::Square(float x, float y, float sideLength, const ColorFloat color, bool * \param filled Whether the Square should be filled * (set to true by default). */ -Square::Square(float x, float y, float sideLength, const ColorFloat color[], bool filled) -: Rectangle(x,y,sideLength,sideLength,color,filled) { } //Create an Rectangle with equal width and height +Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_QUADS; + myXScale = myYScale = mySideLength = sideLength; + myZScale = 1; + attribMutex.unlock(); + addVertex(-0.5, 0.5, 0, color[0]); + addVertex(-0.5, -0.5, 0, color[1]); + addVertex(0.5, -0.5, 0, color[2]); + addVertex(0.5, 0.5, 0, color[3]); +} -/*! - * \brief Explicitly constructs a new Square with different monocolored fill and outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor The color of the Square's fill. - * \param outlineColor The color of the Square's outline. +/** + * \brief Mutates the distance between opposite sides of the Square. + * \param sideLength The Square's new side length. */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height +void Square::setSideLength(GLfloat sideLength) { + if (sideLength <= 0) { + TsglDebug("Cannot have a Square with sideLength less than or equal to 0."); + return; + } + attribMutex.lock(); + mySideLength = sideLength; + myXScale = myYScale = sideLength; + attribMutex.unlock(); +} -/*! - * \brief Explicitly constructs a new Square with multicolored fill and monocolored outline. - * \details This function draws a square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor An array of colors for the Square's fill. - * \param outlineColor The color of the Square's outline. +/** + * \brief Mutates the distance between opposite sides of the Square by the parameter amount. + * \param delta The amount by which to change the side length of the Square. */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height - -/*! - * \brief Explicitly constructs a new Square with monocolored fill and multicolored outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor The color of the Square's fill. - * \param outlineColor An array of colors for the Square's outline. - */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor[]) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height - -/*! - * \brief Explicitly constructs a new Square with different multicolored fill and outline. - * \details This function draws a Square with the given upper left corner, sidelength, fillColor, and outline color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. - * \param sideLength The side length of the Square in pixels. - * \param fillColor An array of colors for the Square's fill. - * \param outlineColor An array of colors for the Square's outline. - */ -Square::Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor[]) -: Rectangle(x,y,sideLength,sideLength,fillColor,outlineColor) { } //Create an Rectangle with equal width and height - +void Square::changeSideLengthBy(GLfloat delta) { + if (mySideLength + delta <= 0) { + TsglDebug("Cannot have a Square with sideLength less than or equal to 0."); + return; + } + attribMutex.lock(); + mySideLength += delta; + myXScale += delta; + myYScale += delta; + attribMutex.unlock(); +} } \ No newline at end of file diff --git a/src/TSGL/Square.h b/src/TSGL/Square.h index e0f2bf9cb..0975f01f3 100644 --- a/src/TSGL/Square.h +++ b/src/TSGL/Square.h @@ -1,31 +1,35 @@ /* -* Square.h extends Rectangle and provides a class for drawing a square to a Canvas. +* Square.h extends ConvexPolygon and provides a class for drawing a square to a Canvas. */ #ifndef SQUARE_H_ #define SQUARE_H_ -#include "Rectangle.h" // For extending our Rectangle object +#include "ConvexPolygon.h" // For extending our Rectangle object namespace tsgl { - /*! \class Square - * \brief Draw a square. - * \details Square is a class for holding Shape data for a square. - */ - class Square : public Rectangle { - public: - Square(float x, float y, float sideLength, const ColorFloat color, bool filled = true); - - Square(float x, float y, float sideLength, const ColorFloat color[], bool filled = true); - - Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor); - - Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor); - - Square(float x, float y, float sideLength, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - Square(float x, float y, float sideLength, const ColorFloat fillColor[], const ColorFloat outlineColor[]); +/*! \class Square +* \brief Draw a square. +* \details Square is a class for holding Shape data for a square. +*/ +class Square : public ConvexPolygon { +protected: + GLfloat mySideLength; +public: + Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat color); + + Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat color[]); + + /*! + * \brief Accessor for the side length of the Square. + * \details Returns the value of the mySideLength private variable, a GLfloat. + */ + GLfloat getSideLength() { return mySideLength; } + + void setSideLength(GLfloat sideLength); + + void changeSideLengthBy(GLfloat delta); }; diff --git a/src/TSGL/Star.cpp b/src/TSGL/Star.cpp index 6af22e788..e90d3a3ac 100644 --- a/src/TSGL/Star.cpp +++ b/src/TSGL/Star.cpp @@ -16,18 +16,23 @@ namespace tsgl { * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float radius, int points, ColorFloat color, bool filled, bool ninja) : ConcavePolygon(points*2, filled, !filled) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), color); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), color); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), color); - } +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorGLfloat color, bool ninja = false) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + //TODO: maybe take "ninja" out, decide how we want the stars to be + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = 1; + myPoints = points; + attribMutex.unlock(); + float delta = 2.0f / points * PI; + for(int i = 0; i < points; ++i) { + addVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, color); + if( ninja ) + addVertex(cos(i*delta), sin(i*delta), 0, color); + else + addVertex(cos((i+0.5)*delta), sin((i+0.5)*delta), 0, color); + } } /*! @@ -44,125 +49,46 @@ Star::Star(float x, float y, float radius, int points, ColorFloat color, bool fi * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float radius, int points, ColorFloat color[], bool filled, bool ninja) : ConcavePolygon(points*2, filled, !filled) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), color[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), color[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), color[i]); - } +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorGLfloat color[], bool ninja = false) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + //TODO: maybe take "ninja" out, decide how we want the stars to be + attribMutex.lock(); + myRadius = radius; + myXScale = radius; + myYScale = radius; + myZScale = 1; + myPoints = points; + attribMutex.unlock(); + float delta = 2.0f / points * PI; + for(int i = 0; i < points; ++i) { + addVertex(0.5*cos(i*delta), 0.5*sin(i*delta), 0, color[i]); + if( ninja ) + addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + else + addVertex(cos(((float)i+0.5)*delta), sin(((float)i+0.5)*delta), 0, color[i]); + } } - /*! - * \brief Explicitly constructs a new Star with different monocolored fill and outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor The color of the star's fill. - * \param outlineColor The color of the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor, outlineColor); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor, outlineColor); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor, outlineColor); - } -} - - /*! - * \brief Explicitly constructs a new Star with multicolored fill and monocolored outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor An array of colors for the star's fill. - * \param outlineColor The color of the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor[i], outlineColor); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor[i], outlineColor); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor[i], outlineColor); - } +void Star::setRadius(GLfloat radius) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale = radius; + myYScale = radius; + myRadius = radius; + attribMutex.unlock(); } - /*! - * \brief Explicitly constructs a new Star with monocolored fill and multicolored outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor The color of the star's fill. - * \param outlineColor An array of colors for the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor, outlineColor[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor, outlineColor[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor, outlineColor[i]); - } -} - - /*! - * \brief Explicitly constructs a new Star with different multicolored fill and outline. - * \details This function draws a star with the given center, - * radius, points, and color. - * \param x The x coordinate of the star's center. - * \param y The y coordinate of the star's center. - * \param radius The radius of the star in pixels. - * \param points The number of points to use in the star. - * \param fillColor An array of colors for the star's fill. - * \param outlineColor An array of colors for the star's outline. - * \param ninja The ninja setting of the star, making the star points spin differently if true - * (set to false by default). - */ -Star::Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja) : ConcavePolygon(points*2, true, true) { - //TODO: maybe take "ninja" out, decide how we want the stars to be - myRadius = radius; - myPoints = points; - float delta = 2.0f / points * PI; - for(int i = 0; i < points; ++i) { - addVertex(x+(radius/2)*cos(i*delta), y+(radius/2)*sin(i*delta), fillColor[i], outlineColor[i]); - if( ninja ) - addVertex(x+(radius*cos(i*delta)), y+(radius*sin(i*delta)), fillColor[i], outlineColor[i]); - else - addVertex(x+(radius*cos((i+0.5)*delta)), y+(radius*sin((i+0.5)*delta)), fillColor[i], outlineColor[i]); - } +void Star::changeRadiusBy(GLfloat delta) { + if (myRadius + delta <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } + attribMutex.lock(); + myXScale += delta; + myYScale += delta; + myRadius += delta; + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/Star.h b/src/TSGL/Star.h index f62b6e701..b64cb9ca1 100644 --- a/src/TSGL/Star.h +++ b/src/TSGL/Star.h @@ -15,21 +15,18 @@ namespace tsgl { */ class Star : public ConcavePolygon { private: - float myRadius; - int myPoints; + GLfloat myRadius; + int myPoints; public: - Star(float x, float y, float radius, int points, ColorFloat color, bool filled = true, bool ninja = false); + Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorGLfloat color, bool ninja = false); - Star(float x, float y, float radius, int points, ColorFloat color[], bool filled = true, bool ninja = false); + Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorGLfloat color[], bool ninja = false); - Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false); + void setRadius(GLfloat radius); - Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false); - - Star(float x, float y, float radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false); - - Star(float x, float y, float radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false); + void changeRadiusBy(GLfloat delta); + GLfloat getRadius() { return myRadius; } }; } diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 8784d1dea..062ccef2e 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -1,226 +1,226 @@ -#include "Text.h" -#include "iostream" - -namespace tsgl { - -/*! - * \brief Explicitly constructs a new Text instance. - * \details This is the constructor for the Text class. - * \param text The string to draw. - * \param loader A reference pointer to the TextureHandler with which to load the font. - * \param x The x coordinate. - * \param y The y coordinate. - * \param fontsize The size of the text in pixels. - * \param color A reference to the ColorFloat to use. - * \return A new Text instance with the specified string, position, and color. - */ -Text::Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color) { - isTextured = true; // Let the Canvas know we're a textured object - myString = text; - myLoader = new TextureHandler(); - myX = x; - myY = y; - myFontSize = fontsize; - myColor = color; - myRotation = 0; - myCenterX = 0; - myCenterY = 0; - vertices = new float[32]; // Allocate the vertices - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - - setRotationPoint(myCenterX, myCenterY); -} - -/*! - * \brief Draw the Text. - * \details This function actually draws the Text to the Canvas. - */ -void Text::draw() { - vertices[0] = myX; // Pre-init the array with the start coords - vertices[1] = myY; - - vertices[2] = vertices[10] = vertices[18] = vertices[26] = myColor.R; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = myColor.G; // (Default to opaque white) - vertices[4] = vertices[12] = vertices[20] = vertices[28] = myColor.B; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = myColor.A; - - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left - vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right - - myLoader->drawText(myString, myFontSize, vertices, myCenterX, myCenterY, myRotation); -} - -/*! - * \brief Alter the Text's string - * \details This function changes myString to the parameter text - * \param text The text to change myString to. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setText(std::wstring text) { - myString = text; - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); - } -} - -/*! - * \brief Alter the Text's font size - * \details This function changes myFontSize to the parameter fontsize. - * \param fontsize The new fontsize. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setFontSize(int fontsize) { - myFontSize = fontsize; - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); - } -} - -/*! - * \brief Alter the Text's font - * \details This function changes myLoader's font to the parameter font. - * \param filename The new font file name. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setFont(std::string filename) { - myLoader->loadFont(filename); - bool shiftRotationPoint = false; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - shiftRotationPoint = true; - } - myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - if(shiftRotationPoint) { - setRotationPoint(myCenterX, myCenterY); - } -} - -/*! - * \brief Alter the Text's lower left hand corner location - * \details This function changes myX and myY to the parameter x and y. - * \param x The new x-coordinate for myX. - * \param y The new y-coordinate for myY. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setBottomLeftCorner(float x, float y) { - float deltaX = x - myX; - float deltaY = y - myY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; - myX = x; - myY = y; -} - -/*! - * \brief Alter the Text's lower left hand corner location - * \details This function changes myX and myY to the parameter x and y. - * \param x The new x-coordinate for myX. - * \param y The new y-coordinate for myY. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::setCenter(float x, float y) { - float deltaX = x - myCenterX; - float deltaY = y - myCenterY; - myX += deltaX; - myY += deltaY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - setRotationPoint(x, y); - } - myCenterX = x; - myCenterY = y; -} - -/*! - * \brief Alter the Text's location by deltaX and deltaY. - * \details This function changes all coordinate variables by the parameter deltaX and deltaY - * \param deltaX The amount to change x-coordinates by. - * \param deltaY The amount to change y-coordinates by. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. - */ -void Text::moveTextBy(float deltaX, float deltaY) { - myX += deltaX; - myY += deltaY; - if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { - myRotationPointX += deltaX; - myRotationPointY += deltaY; - } - myCenterX += deltaX; - myCenterY += deltaY; -} - -/*! - * \brief Mutator for the rotation of the Text. - * \details Rotates the Text vertices around centerX, centerY. - * \param radians Float value denoting how many radians to rotate the Text. - */ -void Text::setRotation(float radians) { - // myRotation = radians; - if(radians != myRotation) { - attribMutex.lock(); - - // distance between myCenter and bottom left corner - float deltaX = std::roundf(myCenterX - myX); - float deltaY = std::roundf(myCenterY - myY); - - //deal with rotation variables - float s = sin(radians - myRotation); - float c = cos(radians - myRotation); - myRotation = radians; - - //rotate myCenter around myRotationPoint - float x = myCenterX; - float y = myCenterY; - x -= myRotationPointX; - y -= myRotationPointY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - x = xnew + myRotationPointX; - y = ynew + myRotationPointY; - myCenterX = x; - myCenterY = y; - - //calculate new location of bottom left corner - myX = myCenterX - deltaX; - myY = myCenterY - deltaY; - attribMutex.unlock(); - } -} - -/*! - * \brief Alter the Text's color - * \details This function changes myColor to the parameter ColorFloat - * \param color The ColorFloat to change myColor to. - */ -void Text::setColor(const ColorFloat& color) { - myColor = color; -} - -Text::~Text() { - delete myLoader; - delete[] vertices; -} - - - -} \ No newline at end of file +// #include "Text.h" +// #include "iostream" + +// namespace tsgl { + +// /*! +// * \brief Explicitly constructs a new Text instance. +// * \details This is the constructor for the Text class. +// * \param text The string to draw. +// * \param loader A reference pointer to the TextureHandler with which to load the font. +// * \param x The x coordinate. +// * \param y The y coordinate. +// * \param fontsize The size of the text in pixels. +// * \param color A reference to the ColorFloat to use. +// * \return A new Text instance with the specified string, position, and color. +// */ +// Text::Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color) { +// isTextured = true; // Let the Canvas know we're a textured object +// myString = text; +// myLoader = new TextureHandler(); +// myX = x; +// myY = y; +// myFontSize = fontsize; +// myColor = color; +// myRotation = 0; +// myCenterX = 0; +// myCenterY = 0; +// vertices = new float[32]; // Allocate the vertices +// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); + +// setRotationPoint(myCenterX, myCenterY); +// } + +// /*! +// * \brief Draw the Text. +// * \details This function actually draws the Text to the Canvas. +// */ +// void Text::draw() { +// vertices[0] = myX; // Pre-init the array with the start coords +// vertices[1] = myY; + +// vertices[2] = vertices[10] = vertices[18] = vertices[26] = myColor.R; // Texture color of the coords +// vertices[3] = vertices[11] = vertices[19] = vertices[27] = myColor.G; // (Default to opaque white) +// vertices[4] = vertices[12] = vertices[20] = vertices[28] = myColor.B; +// vertices[5] = vertices[13] = vertices[21] = vertices[29] = myColor.A; + +// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left +// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right +// vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left +// vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right + +// myLoader->drawText(myString, myFontSize, vertices, myCenterX, myCenterY, myRotation); +// } + +// /*! +// * \brief Alter the Text's string +// * \details This function changes myString to the parameter text +// * \param text The text to change myString to. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::setText(std::wstring text) { +// myString = text; +// bool shiftRotationPoint = false; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// shiftRotationPoint = true; +// } +// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); +// if(shiftRotationPoint) { +// setRotationPoint(myCenterX, myCenterY); +// } +// } + +// /*! +// * \brief Alter the Text's font size +// * \details This function changes myFontSize to the parameter fontsize. +// * \param fontsize The new fontsize. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::setFontSize(int fontsize) { +// myFontSize = fontsize; +// bool shiftRotationPoint = false; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// shiftRotationPoint = true; +// } +// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); +// if(shiftRotationPoint) { +// setRotationPoint(myCenterX, myCenterY); +// } +// } + +// /*! +// * \brief Alter the Text's font +// * \details This function changes myLoader's font to the parameter font. +// * \param filename The new font file name. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::setFont(std::string filename) { +// myLoader->loadFont(filename); +// bool shiftRotationPoint = false; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// shiftRotationPoint = true; +// } +// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); +// if(shiftRotationPoint) { +// setRotationPoint(myCenterX, myCenterY); +// } +// } + +// /*! +// * \brief Alter the Text's lower left hand corner location +// * \details This function changes myX and myY to the parameter x and y. +// * \param x The new x-coordinate for myX. +// * \param y The new y-coordinate for myY. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::setBottomLeftCorner(float x, float y) { +// float deltaX = x - myX; +// float deltaY = y - myY; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// myRotationPointX += deltaX; +// myRotationPointY += deltaY; +// } +// myCenterX += deltaX; +// myCenterY += deltaY; +// myX = x; +// myY = y; +// } + +// /*! +// * \brief Alter the Text's lower left hand corner location +// * \details This function changes myX and myY to the parameter x and y. +// * \param x The new x-coordinate for myX. +// * \param y The new y-coordinate for myY. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::setCenter(float x, float y) { +// float deltaX = x - myCenterX; +// float deltaY = y - myCenterY; +// myX += deltaX; +// myY += deltaY; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// setRotationPoint(x, y); +// } +// myCenterX = x; +// myCenterY = y; +// } + +// /*! +// * \brief Alter the Text's location by deltaX and deltaY. +// * \details This function changes all coordinate variables by the parameter deltaX and deltaY +// * \param deltaX The amount to change x-coordinates by. +// * \param deltaY The amount to change y-coordinates by. +// * \warning This will also alter the Text's rotation point to the new center if and only if +// * the old rotation point was at the Text's old center. +// */ +// void Text::moveTextBy(float deltaX, float deltaY) { +// myX += deltaX; +// myY += deltaY; +// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { +// myRotationPointX += deltaX; +// myRotationPointY += deltaY; +// } +// myCenterX += deltaX; +// myCenterY += deltaY; +// } + +// /*! +// * \brief Mutator for the rotation of the Text. +// * \details Rotates the Text vertices around centerX, centerY. +// * \param radians Float value denoting how many radians to rotate the Text. +// */ +// void Text::setRotation(float radians) { +// // myRotation = radians; +// if(radians != myRotation) { +// attribMutex.lock(); + +// // distance between myCenter and bottom left corner +// float deltaX = std::roundf(myCenterX - myX); +// float deltaY = std::roundf(myCenterY - myY); + +// //deal with rotation variables +// float s = sin(radians - myRotation); +// float c = cos(radians - myRotation); +// myRotation = radians; + +// //rotate myCenter around myRotationPoint +// float x = myCenterX; +// float y = myCenterY; +// x -= myRotationPointX; +// y -= myRotationPointY; +// float xnew = x * c - y * s; +// float ynew = x * s + y * c; +// x = xnew + myRotationPointX; +// y = ynew + myRotationPointY; +// myCenterX = x; +// myCenterY = y; + +// //calculate new location of bottom left corner +// myX = myCenterX - deltaX; +// myY = myCenterY - deltaY; +// attribMutex.unlock(); +// } +// } + +// /*! +// * \brief Alter the Text's color +// * \details This function changes myColor to the parameter ColorFloat +// * \param color The ColorFloat to change myColor to. +// */ +// void Text::setColor(const ColorFloat& color) { +// myColor = color; +// } + +// Text::~Text() { +// delete myLoader; +// delete[] vertices; +// } + + + +// } \ No newline at end of file diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index 230f4865b..1364ad451 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -1,54 +1,54 @@ -/* - * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. - */ +// /* +// * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. +// */ -#ifndef TEXT_H_ -#define TEXT_H_ +// #ifndef TEXT_H_ +// #define TEXT_H_ -#include "Drawable.h" // For extending our Shape object -#include "TextureHandler.h" +// #include "Drawable.h" // For extending our Shape object +// #include "TextureHandler.h" -namespace tsgl { +// namespace tsgl { -/*! \class Text - * \brief Draw a string of text. - * \details Text is a class for holding the data necessary for rendering a string of text. - * \note Text is aligned by the upper-left corner. - * \note Fonts supported by FreeType are also supported. - */ -class Text : public Drawable { - private: - ColorFloat myColor; - unsigned int myFontSize; - TextureHandler* myLoader; - float * vertices; - std::wstring myString; - float myX, myY; - float myRotation; - public: - Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color); +// /*! \class Text +// * \brief Draw a string of text. +// * \details Text is a class for holding the data necessary for rendering a string of text. +// * \note Text is aligned by the upper-left corner. +// * \note Fonts supported by FreeType are also supported. +// */ +// class Text : public Drawable { +// private: +// ColorFloat myColor; +// unsigned int myFontSize; +// TextureHandler* myLoader; +// float * vertices; +// std::wstring myString; +// float myX, myY; +// float myRotation; +// public: +// Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color); - virtual void draw(); +// virtual void draw(); - virtual void setText(std::wstring text); +// virtual void setText(std::wstring text); - virtual void setFontSize(int fontsize); +// virtual void setFontSize(int fontsize); - virtual void setFont(std::string filename); +// virtual void setFont(std::string filename); - virtual void setBottomLeftCorner(float x, float y); +// virtual void setBottomLeftCorner(float x, float y); - virtual void setCenter(float x, float y); +// virtual void setCenter(float x, float y); - virtual void moveTextBy(float deltaX, float deltaY); +// virtual void moveTextBy(float deltaX, float deltaY); - virtual void setRotation(float radians); +// virtual void setRotation(float radians); - virtual void setColor(const ColorFloat& color); +// virtual void setColor(const ColorFloat& color); - ~Text(); -}; +// ~Text(); +// }; -} +// } -#endif /* TEXT_H_ */ \ No newline at end of file +// #endif /* TEXT_H_ */ \ No newline at end of file diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index 026de96be..990b1bb82 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -1,795 +1,795 @@ -#include "TextureHandler.h" - -namespace tsgl { - - //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) - #ifndef STB_DEFINE - #define STB_IMAGE_WRITE_IMPLEMENTATION - #include "stb/stb_image_write.h" - #define STB_IMAGE_IMPLEMENTATION - #include "stb/stb_image.h" - #define STB_DEFINE -//It may look truly awful....but its an easy way to turn off warnings -//solely for stb.h. Sorry :'( +// #include "TextureHandler.h" + +// namespace tsgl { + +// //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) +// #ifndef STB_DEFINE +// #define STB_IMAGE_WRITE_IMPLEMENTATION +// #include "stb/stb_image_write.h" +// #define STB_IMAGE_IMPLEMENTATION +// #include "stb/stb_image.h" +// #define STB_DEFINE +// //It may look truly awful....but its an easy way to turn off warnings +// //solely for stb.h. Sorry :'( +// // #pragma GCC diagnostic push +// // #pragma GCC diagnostic ignored "-fpermissive" // #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-fpermissive" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wwrite-strings" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-result" - #include "stb/stb.h" -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop -#pragma GCC diagnostic pop - #endif - - //List of default fonts to check for -#ifndef DEFAULTFONTS -#define DEFAULTFONTS -#ifdef _WIN32 - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "C:\\Windows\\Fonts\\ARIALUNI.ttf", - "C:\\Windows\\Fonts\\ARIAL.ttf", - "C:\\Windows\\Fonts\\COUR.ttf", - "C:\\Windows\\Fonts\\COURI.ttf" - }; -#endif -#ifdef __APPLE__ - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "/Library/Fonts/Arial.ttf", - "/Library/Fonts/Courier New.ttf", - "/Library/Fonts/Georgia.ttf", - "/opt/X11/share/fonts/TTF/VeraSe.ttf", - }; -#endif -#ifdef __linux__ - const char* DEFAULTFONTPATHS[] = { - "../assets/freefont/FreeSerif.ttf", - "./assets/freefont/FreeSerif.ttf", - "./FreeSerif.ttf", - "/usr/share/fonts/dejavu/DejaVuSerif.ttf", - "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", - "/usr/share/fonts/TTF/DejaVuSerif.ttf", - "/usr/share/fonts/TTF/arial.ttf", - "/usr/share/fonts/TTF/cour.ttf", - "/usr/share/fonts/TTF/couri.ttf" - }; -#endif -#endif - -#define GL_GLEXT_PROTOTYPES - -/*! - * \brief Default TextureHandler constructor method. - * \details This is the default constructor for theTextureHandler Canvas class. - * \return A new TextureHandler instance. - */ -TextureHandler::TextureHandler() { - fontLibrary = nullptr; - fontFace = nullptr; -} - -/*! - * \brief TextureHandler destructor method. - * \details This is the destructor for the TextureHandler class. - * \details Frees up memory that was allocated to a TextureHandler instance. - */ -TextureHandler::~TextureHandler() { - for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { - glDeleteTextures(1, &(it->second)); - } - - for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { - FT_Done_Face(it->second); - } - FT_Done_FreeType(fontLibrary); -} - -void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, - const unsigned int &width, const unsigned int &height, - int glMode) { - // Generate the OpenGL texture object - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - if (glMode == GL_ALPHA) { - unsigned char* newBuffer = new unsigned char[width * height * 4]; - unsigned maxSize = width * height; - for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { - newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); - delete[] newBuffer; - } else { - if (glMode == GL_RED) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -} - -void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { - // Generate the OpenGL texture object - GLtexture texture; - - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - if (glMode == GL_ALPHA) { - unsigned char* newBuffer = new unsigned char[width * height * 4]; - unsigned maxSize = width * height; - for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { - newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); - delete[] newBuffer; - } else { - if (glMode == GL_RED) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - float* vertices = new float[32]; - vertices[0] = x; - vertices[1] = y + height; - vertices[8] = x + width; - vertices[9] = y + height; - vertices[16] = x + width; - vertices[17] = y; - vertices[24] = x; - vertices[25] = y; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords - vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; - vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; - vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; - vertices[6] = vertices[7] = 0.0f; // Texture coords of top left - vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right - vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left - vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right - - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDeleteTextures(1, &texture); - - delete[] vertices; -} - -/*! - * \brief Draws text. - * \details Draws the text specified by its parameters onto a Canvas. - * \param text The UTF-8 encoded string of text to be drawn. - * \param font_size The size of the text in pixels. - * \param vertices An array of vertex data for the bonding box of the text. - * \note vertices will be partially automatically set by drawText() - * itself in order to draw / kern the text properly, but the color, starting - * position, and texture coordinates will be left unchanged. - * \note If no font is loaded before calling this function, TSGL will attempt to locate a - * default font at ../assets/freefont/FreeMono.ttf. - * \return True if successful, false otherwise. - * \bug If the default font cannot be located, TSGL will crash. - */ -bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { - const wchar_t* string = text.c_str(); - if(fontFace == nullptr) { //If no font is set, load up a default one - bool found = false; - for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { - if (fileExists(DEFAULTFONTPATHS[i])) { - TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW - loadFont(DEFAULTFONTPATHS[i]); - found = true; - break; - } - } - if (!found) { - TsglErr("No suitable fonts found...exiting"); //NEW - exit(44); - } - } - - FT_GlyphSlot glyph = fontFace->glyph; - FT_UInt current_glyph_index, previous_glyph_index = 0; - int penX = vertices[0], - penY = vertices[1]; - - bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); - if (error) { - fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); - return false; - } - - bool use_kerning = FT_HAS_KERNING(fontFace); - - for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - - if (use_kerning && previous_glyph_index && current_glyph_index) { - FT_Vector delta; - FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); - penX += delta.x >> 6; - penY += delta.y >> 6; - } - - error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "FT_Load_Char failed\n"); - return false; - } - - previous_glyph_index = current_glyph_index; - - int glMode = GL_ALPHA; - - char fontMode = glyph->bitmap.pixel_mode; - if (fontMode == FT_PIXEL_MODE_MONO) - glMode = GL_RED; - else if (fontMode == FT_PIXEL_MODE_GRAY) - glMode = GL_ALPHA; - else if (fontMode == FT_PIXEL_MODE_LCD) - glMode = GL_RGB; - else if (fontMode == FT_PIXEL_MODE_LCD_V) - glMode = GL_RGB; -#ifndef _WIN32 - else if (fontMode == FT_PIXEL_MODE_BGRA) - glMode = GL_RGBA; -#endif - - GLtexture texture; - createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); - glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - vertices[0] = vertices[16] = penX + glyph->bitmap_left; - vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; - vertices[1] = vertices[9] = penY - glyph->bitmap_top; - vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; - - - float s = sin(rotation); - float c = cos(rotation); - for(int i = 0; i < 4; i++) { - float x = vertices[8*i]; - float y = vertices[8*i+1]; - x -= centerX; - y -= centerY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + centerX; - y = ynew + centerY; - vertices[8*i] = x; - vertices[8*i+1] = y; - } - - penX += glyph->advance.x >> 6; - penY += glyph->advance.y >> 6; - - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character - - glDeleteTextures(1, &texture); - } - return true; -} - -/*! - * \brief Loads a font. - * \details Loads a font from the library given by filename. - * \param filename The file name of the font to be loaded. - * \warning If the font cannot be found then an error message is printed out. - * \warning If the font library is not correctly installed then an error message is printed out. - * \warning If the font is not supported then an error message is printed out. - * \return True if successful, false otherwise. - */ -bool TextureHandler::loadFont(const std::string& filename) { - if (fontLibrary == nullptr) { - if (FT_Init_FreeType(&fontLibrary)) { - fprintf(stderr, "An error occurred during freetype font library initialization\n"); - return false; - } - } - - if(filename == "") { - fontFace = nullptr; - return true; - } - - if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already - FT_Face tmp_face; - int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); - if (error == FT_Err_Unknown_File_Format) { - fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" - "font format is unsupported\n", filename.c_str()); - return false; - } else if (error) { - fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); - return false; - } - - loadedFonts[filename] = tmp_face; - fontFace = tmp_face; - FT_Select_Charmap(fontFace , ft_encoding_unicode); - } else { - fontFace = loadedFonts[filename]; - } - - return true; -} - -void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { - const wchar_t* string = text.c_str(); - if(fontFace == nullptr) { //If no font is set, load up a default one - bool found = false; - for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { - if (fileExists(DEFAULTFONTPATHS[i])) { - TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW - loadFont(DEFAULTFONTPATHS[i]); - found = true; - break; - } - } - if (!found) { - TsglErr("No suitable fonts found...exiting"); //NEW - exit(44); - } - } - FT_GlyphSlot glyph = fontFace->glyph; - FT_UInt current_glyph_index, previous_glyph_index = 0; - int penX = leftX; - int penY = bottomY; - - int minX = leftX; - int minY = bottomY; - int maxX = leftX; - int maxY = bottomY; - - int currentRightX, currentTopY, currentBottomY; - - bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); - if (error) { - fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); - return; - } - - bool use_kerning = FT_HAS_KERNING(fontFace); - - for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - - if (use_kerning && previous_glyph_index && current_glyph_index) { - FT_Vector delta; - FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); - penX += delta.x >> 6; - penY += delta.y >> 6; - } - - error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "FT_Load_Char falied\n"); - return; - } - - previous_glyph_index = current_glyph_index; - - currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; - currentTopY = penY - glyph->bitmap_top; - currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; - - maxX = currentRightX; - if(currentBottomY > maxY) { - maxY = currentBottomY; - } - if(currentTopY < minY) { - minY = currentTopY; - } - - penX += glyph->advance.x >> 6; - penY += glyph->advance.y >> 6; - } - - centerX = (minX + maxX) / 2; - centerY = (minY + maxY) / 2; -} - -/*! - * \brief Loads an image. - * \details Loads a .png, .jpeg, or .bmp image from a file. - * \param filename The file name of the picture. - * \param width A reference variable for holding the width of the picture. - * \param height A reference variable for holding the height of the picture. - * \param texture A reference variable for holding the texture of the picture. - * (same as return value) - * \return The texture that created from the loaded image. - */ -GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { - if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already - texture = 0; - std::string extension = filename.substr(filename.find_last_of('.')); - if (extension == ".png") - loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); - else if (extension == ".jpg" || extension == ".jpeg") - loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); - else if (extension == ".bmp") - loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); - else { - fprintf(stderr, "File extension not found\n"); - return 0; - } - } else { - texture = loadedTextures[filename]; - } - - return texture; -} - -GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself - - // Data read from the header of the BMP file - unsigned char header[54]; // Each BMP file begins by a 54-bytes header - unsigned int imageSize; // = width*height*3 - // Actual RGB data - unsigned char * data; - - // Open the file -#ifdef _WIN32 - FILE* file; - fopen_s(&file, filename, "rb"); -#else - FILE* file = fopen(filename, "rb"); -#endif - - if (!file) { - fprintf(stderr, "Can't open %s: no such file\n", filename); - return 0; - } - - if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem - fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); - fclose(file); - return 0; - } - - if (header[0] != 'B' || header[1] != 'M') { - fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); - fclose(file); - return 0; - } - - imageSize = width = height = 0; - // Get info out of header as 4 byte unsigned ints - for (int i = 3; i >= 0; i--) - imageSize = (imageSize << 8) | header[0x22 + i]; - for (int i = 3; i >= 0; i--) - width = (width << 8) | header[0x12 + i]; - for (int i = 3; i >= 0; i--) - height = (height << 8) | header[0x16 + i]; - - int components = imageSize / width / height; - - // Some BMP files are misformatted, guess missing information - if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component - - // Create a buffer - data = new unsigned char[imageSize]; - - // Read the actual data from the file into the buffer - if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem - fprintf(stderr, "%s: file ended unexpectedly\n", filename); - fclose(file); - return 0; - } - - //Everything is in memory now, the file can be closed - fclose(file); - - char tmp; - //Reverse the endian-ness of the colors - if (components == 4) { - for (unsigned int i = 0; i < imageSize; i += 4) { - tmp = data[i]; - data[i] = data[i + 3]; - data[i + 3] = tmp; - tmp = data[i + 1]; - data[i + 1] = data[i + 2]; - data[i + 2] = tmp; - } - } else if (components == 3) { - for (unsigned int i = 0; i < imageSize; i += 3) { - tmp = data[i]; - data[i] = data[i + 1]; - data[i + 1] = tmp; - } - } - - // Flip the image vertically, since BMPs are loaded bottom to top - for (unsigned int j = 0; j < height - (height / 2); j++) { - for (unsigned int i = 0; i < components * width; i++) { - int s1 = components * width * j + i; - int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j - tmp = data[s1]; - data[s1] = data[s2]; - data[s2] = tmp; - } - } - - if (components == 3) - components = GL_RGB; - else if (components == 4) - components = GL_RGBA; - - createGLtextureFromBuffer(texture, data, width, height, components); - - delete[] data; - - return texture; -} - -/*! - * \brief Gets the dimensions of an image - * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. - * \param filename The file name of the picture. - * \param width A reference variable for holding the width of the picture. - * \param height A reference variable for holding the height of the picture. - * \return The texture that created from the loaded image. - */ -void TextureHandler::getDimensions(std::string filename, int &width, int &height) { - int w = 0, h = 0; - stbi_info(filename.c_str(), &w, &h, 0); - width = w; height = h; -} - -GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - unsigned char *data; - int w = 0, h = 0; - TsglDebug(std::string("Loading ") + filename); - data = stbi_load(filename, &w, &h, 0, 4); - assert(data); - if (!data) { - TsglErr(std::string("Loading ") + filename + " failed"); - return texture; - } - TsglDebug(std::string("Loading ") + filename + " succeeded"); - TsglDebug(to_string(w) + "," + to_string(h)); - createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); - width = w, height = h; - free(data); - return texture; -} - -GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const { - unsigned char *data; - int w = 0, h = 0; - TsglDebug(std::string("Loading ") + filename); - data = stbi_load(filename, &w, &h, 0, 4); - assert(data); - if (!data) { - TsglErr(std::string("Loading ") + filename + " failed"); - return texture; - } - TsglDebug(std::string("Loading ") + filename + " succeeded"); - TsglDebug(to_string(w) + "," + to_string(h)); - createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); - width = w, height = h; - free(data); - return texture; -} - -/*! - * \brief Saves an Image. - * \details Saves an Image to file that was captured from a Canvas object. - * \param filename The name of the file to save the Image to. - * \param pixels The pixel data for the Image. - * \param width The width of the Image. - * \param height The height of the Image. - * \return True if successful, false otherwise. - */ -bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, - unsigned int width, unsigned int height) const { - std::string extension = filename.substr(filename.find_last_of('.')); - bool success = false; - if (extension == ".png") - success = saveToPNG(filename.c_str(), pixels, width, height); - else if (extension == ".jpg" || extension == ".jpeg") - fprintf(stderr, "JPG saving not implemented yet\n"); - else if (extension == ".bmp") - success = saveToBMP(filename.c_str(), pixels, width, height); - else - fprintf(stderr, "File extension not found\n"); - return success; -} - -bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { - unsigned char header[54]; // Each BMP file begins by a 54-bytes header - unsigned int imageSize = w * h * 3; // Byte-size of the data for the image - unsigned int totalSize = imageSize + 54; - - // Open the file -#ifdef _WIN32 - FILE* file; - fopen_s(&file, filename, "wb"); -#else - FILE* file = fopen(filename, "wb"); -#endif - - if (!file) { - fprintf(stderr, "Can't open %s: no such file\n", filename); - return false; - } - - unsigned char padding = 4 - (w * 3) % 4; - if (padding == 4) padding = 0; - int rawdatasize = (w * 3 + padding) * h; - - header[0] = 'B'; - header[1] = 'M'; - header[2] = (unsigned char) totalSize; - header[3] = (unsigned char)(totalSize >> 8); - header[4] = (unsigned char)(totalSize >> 16); - header[5] = (unsigned char)(totalSize >> 24); - for (unsigned i = 6; i <= 9; ++i) - header[i] = 0; - header[10] = 54; - for (unsigned i = 11; i <= 13; ++i) - header[i] = 0; - header[14] = 40; - for (unsigned i = 15; i <= 17; ++i) - header[i] = 0; - header[18] = (unsigned char) w; - header[19] = (unsigned char)(w >> 8); - header[20] = (unsigned char)(w >> 16); - header[21] = (unsigned char)(w >> 24); - header[22] = (unsigned char) h; - header[23] = (unsigned char)(h >> 8); - header[24] = (unsigned char)(h >> 16); - header[25] = (unsigned char)(h >> 24); - header[26] = 1; - header[27] = 0; - header[28] = 24; - header[29] = 0; - for (unsigned i = 30; i <= 33; ++i) - header[i] = 0; - header[34] = (unsigned char) rawdatasize; - header[35] = (unsigned char)(rawdatasize >> 8); - header[36] = (unsigned char)(rawdatasize >> 16); - header[37] = (unsigned char)(rawdatasize >> 24); - header[38] = 19; - header[39] = 11; - header[40] = 0; - header[41] = 0; - header[42] = 19; - header[43] = 11; - header[44] = 0; - header[45] = 0; - for (unsigned i = 46; i <= 53; ++i) - header[i] = 0; - - unsigned char *rawdata = new unsigned char[rawdatasize]; - - unsigned rawpos = 0, datapos = 0; - for (unsigned j = 0; j < h; ++j) { - for (unsigned i = 0; i < w; ++i) { - rawdata[rawpos] = pixels[datapos+2]; - rawdata[rawpos+1] = pixels[datapos+1]; - rawdata[rawpos+2] = pixels[datapos]; - rawpos += 3; - datapos += 3; - } - for (unsigned i = 0; i < padding; ++i) { - rawdata[rawpos++] = 0; - } - } - - fwrite(header, 54, 1, file); - fwrite(rawdata, 1, rawdatasize, file); - fclose(file); - - delete[] rawdata; - - return true; -} - -bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { - // Flip the image, since for some reason the library call - // flips the image upside down when it saves - for (unsigned int j = 0; j < h - (h / 2); j++) { - for (unsigned int i = 0; i < 3 * w; i++) { - int s1 = 3 * w * j + i; - int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j - char tmp = pixels[s1]; - pixels[s1] = pixels[s2]; - pixels[s2] = tmp; - } - } - stbi_write_png(filename, w, h, 3, pixels, 0); - return true; -} - -//-------------------------Unit testing--------------------------------------------- -/*! - * \brief Runs the Unit tests for TextureHandler. - */ -void TextureHandler::runTests() { - TsglDebug("Testing TextureHandler class..."); - TextureHandler tester; - tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); - TsglDebug("Unit tests for TextureHandler complete."); - std::cout << std::endl; -} - -bool TextureHandler::testLoadFont(TextureHandler& test) { - int passed = 0; //Passed tests - int failed = 0; //Failed tests - //Test 1: Loading in the font at the start - if(test.fontFace == nullptr) { - test.loadFont("../assets/freefont/FreeMono.ttf"); - if(test.fontFace != nullptr) { - passed++; - } else { - failed++; - TsglErr("Test 1, Loading font for testLoadFont() failed!"); - } - } - - if(passed == 1 && failed == 0) { - TsglDebug("Unit test for loading in fonts passed!"); - return true; - } else { - TsglErr("This many tests passed for testLoadFont: "); - std::cout << " " << passed << std::endl; - TsglErr("This many tests failed for testLoadFont: "); - std::cout << " " << failed << std::endl; - return false; - } -} -//----------------------------End Unit testing--------------------------------------- -} +// #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wsign-compare" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wstrict-aliasing" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wwrite-strings" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wtype-limits" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wunused-but-set-variable" +// #pragma GCC diagnostic push +// #pragma GCC diagnostic ignored "-Wunused-result" +// #include "stb/stb.h" +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #pragma GCC diagnostic pop +// #endif + +// //List of default fonts to check for +// #ifndef DEFAULTFONTS +// #define DEFAULTFONTS +// #ifdef _WIN32 +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "C:\\Windows\\Fonts\\ARIALUNI.ttf", +// "C:\\Windows\\Fonts\\ARIAL.ttf", +// "C:\\Windows\\Fonts\\COUR.ttf", +// "C:\\Windows\\Fonts\\COURI.ttf" +// }; +// #endif +// #ifdef __APPLE__ +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "/Library/Fonts/Arial.ttf", +// "/Library/Fonts/Courier New.ttf", +// "/Library/Fonts/Georgia.ttf", +// "/opt/X11/share/fonts/TTF/VeraSe.ttf", +// }; +// #endif +// #ifdef __linux__ +// const char* DEFAULTFONTPATHS[] = { +// "../assets/freefont/FreeSerif.ttf", +// "./assets/freefont/FreeSerif.ttf", +// "./FreeSerif.ttf", +// "/usr/share/fonts/dejavu/DejaVuSerif.ttf", +// "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", +// "/usr/share/fonts/TTF/DejaVuSerif.ttf", +// "/usr/share/fonts/TTF/arial.ttf", +// "/usr/share/fonts/TTF/cour.ttf", +// "/usr/share/fonts/TTF/couri.ttf" +// }; +// #endif +// #endif + +// #define GL_GLEXT_PROTOTYPES + +// /*! +// * \brief Default TextureHandler constructor method. +// * \details This is the default constructor for theTextureHandler Canvas class. +// * \return A new TextureHandler instance. +// */ +// TextureHandler::TextureHandler() { +// fontLibrary = nullptr; +// fontFace = nullptr; +// } + +// /*! +// * \brief TextureHandler destructor method. +// * \details This is the destructor for the TextureHandler class. +// * \details Frees up memory that was allocated to a TextureHandler instance. +// */ +// TextureHandler::~TextureHandler() { +// for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { +// glDeleteTextures(1, &(it->second)); +// } + +// for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { +// FT_Done_Face(it->second); +// } +// FT_Done_FreeType(fontLibrary); +// } + +// void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, +// const unsigned int &width, const unsigned int &height, +// int glMode) { +// // Generate the OpenGL texture object +// glGenTextures(1, &texture); +// glBindTexture(GL_TEXTURE_2D, texture); + +// if (glMode == GL_ALPHA) { +// unsigned char* newBuffer = new unsigned char[width * height * 4]; +// unsigned maxSize = width * height; +// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { +// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; +// } + +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); +// delete[] newBuffer; +// } else { +// if (glMode == GL_RED) { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// } else { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +// } +// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); +// } + +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// } + +// void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { +// // Generate the OpenGL texture object +// GLtexture texture; + +// glGenTextures(1, &texture); +// glBindTexture(GL_TEXTURE_2D, texture); + +// if (glMode == GL_ALPHA) { +// unsigned char* newBuffer = new unsigned char[width * height * 4]; +// unsigned maxSize = width * height; +// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { +// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; +// } + +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); +// delete[] newBuffer; +// } else { +// if (glMode == GL_RED) { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// } else { +// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +// } +// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); +// } + +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + +// float* vertices = new float[32]; +// vertices[0] = x; +// vertices[1] = y + height; +// vertices[8] = x + width; +// vertices[9] = y + height; +// vertices[16] = x + width; +// vertices[17] = y; +// vertices[24] = x; +// vertices[25] = y; +// vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords +// vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; +// vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; +// vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; +// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left +// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right +// vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left +// vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right + +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); +// glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + +// glDeleteTextures(1, &texture); + +// delete[] vertices; +// } + +// /*! +// * \brief Draws text. +// * \details Draws the text specified by its parameters onto a Canvas. +// * \param text The UTF-8 encoded string of text to be drawn. +// * \param font_size The size of the text in pixels. +// * \param vertices An array of vertex data for the bonding box of the text. +// * \note vertices will be partially automatically set by drawText() +// * itself in order to draw / kern the text properly, but the color, starting +// * position, and texture coordinates will be left unchanged. +// * \note If no font is loaded before calling this function, TSGL will attempt to locate a +// * default font at ../assets/freefont/FreeMono.ttf. +// * \return True if successful, false otherwise. +// * \bug If the default font cannot be located, TSGL will crash. +// */ +// bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { +// const wchar_t* string = text.c_str(); +// if(fontFace == nullptr) { //If no font is set, load up a default one +// bool found = false; +// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { +// if (fileExists(DEFAULTFONTPATHS[i])) { +// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW +// loadFont(DEFAULTFONTPATHS[i]); +// found = true; +// break; +// } +// } +// if (!found) { +// TsglErr("No suitable fonts found...exiting"); //NEW +// exit(44); +// } +// } + +// FT_GlyphSlot glyph = fontFace->glyph; +// FT_UInt current_glyph_index, previous_glyph_index = 0; +// int penX = vertices[0], +// penY = vertices[1]; + +// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); +// if (error) { +// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); +// return false; +// } + +// bool use_kerning = FT_HAS_KERNING(fontFace); + +// for (unsigned int i = 0; i < text.size(); i++) { +// current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + +// if (use_kerning && previous_glyph_index && current_glyph_index) { +// FT_Vector delta; +// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); +// penX += delta.x >> 6; +// penY += delta.y >> 6; +// } + +// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); +// if (error) { +// fprintf(stderr, "FT_Load_Char failed\n"); +// return false; +// } + +// previous_glyph_index = current_glyph_index; + +// int glMode = GL_ALPHA; + +// char fontMode = glyph->bitmap.pixel_mode; +// if (fontMode == FT_PIXEL_MODE_MONO) +// glMode = GL_RED; +// else if (fontMode == FT_PIXEL_MODE_GRAY) +// glMode = GL_ALPHA; +// else if (fontMode == FT_PIXEL_MODE_LCD) +// glMode = GL_RGB; +// else if (fontMode == FT_PIXEL_MODE_LCD_V) +// glMode = GL_RGB; +// #ifndef _WIN32 +// else if (fontMode == FT_PIXEL_MODE_BGRA) +// glMode = GL_RGBA; +// #endif + +// GLtexture texture; +// createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); +// glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +// vertices[0] = vertices[16] = penX + glyph->bitmap_left; +// vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; +// vertices[1] = vertices[9] = penY - glyph->bitmap_top; +// vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; + + +// float s = sin(rotation); +// float c = cos(rotation); +// for(int i = 0; i < 4; i++) { +// float x = vertices[8*i]; +// float y = vertices[8*i+1]; +// x -= centerX; +// y -= centerY; +// float xnew = x * c - y * s; +// float ynew = x * s + y * c; + +// x = xnew + centerX; +// y = ynew + centerY; +// vertices[8*i] = x; +// vertices[8*i+1] = y; +// } + +// penX += glyph->advance.x >> 6; +// penY += glyph->advance.y >> 6; + +// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer +// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character + +// glDeleteTextures(1, &texture); +// } +// return true; +// } + +// /*! +// * \brief Loads a font. +// * \details Loads a font from the library given by filename. +// * \param filename The file name of the font to be loaded. +// * \warning If the font cannot be found then an error message is printed out. +// * \warning If the font library is not correctly installed then an error message is printed out. +// * \warning If the font is not supported then an error message is printed out. +// * \return True if successful, false otherwise. +// */ +// bool TextureHandler::loadFont(const std::string& filename) { +// if (fontLibrary == nullptr) { +// if (FT_Init_FreeType(&fontLibrary)) { +// fprintf(stderr, "An error occurred during freetype font library initialization\n"); +// return false; +// } +// } + +// if(filename == "") { +// fontFace = nullptr; +// return true; +// } + +// if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already +// FT_Face tmp_face; +// int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); +// if (error == FT_Err_Unknown_File_Format) { +// fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" +// "font format is unsupported\n", filename.c_str()); +// return false; +// } else if (error) { +// fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); +// return false; +// } + +// loadedFonts[filename] = tmp_face; +// fontFace = tmp_face; +// FT_Select_Charmap(fontFace , ft_encoding_unicode); +// } else { +// fontFace = loadedFonts[filename]; +// } + +// return true; +// } + +// void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { +// const wchar_t* string = text.c_str(); +// if(fontFace == nullptr) { //If no font is set, load up a default one +// bool found = false; +// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { +// if (fileExists(DEFAULTFONTPATHS[i])) { +// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW +// loadFont(DEFAULTFONTPATHS[i]); +// found = true; +// break; +// } +// } +// if (!found) { +// TsglErr("No suitable fonts found...exiting"); //NEW +// exit(44); +// } +// } +// FT_GlyphSlot glyph = fontFace->glyph; +// FT_UInt current_glyph_index, previous_glyph_index = 0; +// int penX = leftX; +// int penY = bottomY; + +// int minX = leftX; +// int minY = bottomY; +// int maxX = leftX; +// int maxY = bottomY; + +// int currentRightX, currentTopY, currentBottomY; + +// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); +// if (error) { +// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); +// return; +// } + +// bool use_kerning = FT_HAS_KERNING(fontFace); + +// for (unsigned int i = 0; i < text.size(); i++) { +// current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + +// if (use_kerning && previous_glyph_index && current_glyph_index) { +// FT_Vector delta; +// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); +// penX += delta.x >> 6; +// penY += delta.y >> 6; +// } + +// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); +// if (error) { +// fprintf(stderr, "FT_Load_Char falied\n"); +// return; +// } + +// previous_glyph_index = current_glyph_index; + +// currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; +// currentTopY = penY - glyph->bitmap_top; +// currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; + +// maxX = currentRightX; +// if(currentBottomY > maxY) { +// maxY = currentBottomY; +// } +// if(currentTopY < minY) { +// minY = currentTopY; +// } + +// penX += glyph->advance.x >> 6; +// penY += glyph->advance.y >> 6; +// } + +// centerX = (minX + maxX) / 2; +// centerY = (minY + maxY) / 2; +// } + +// /*! +// * \brief Loads an image. +// * \details Loads a .png, .jpeg, or .bmp image from a file. +// * \param filename The file name of the picture. +// * \param width A reference variable for holding the width of the picture. +// * \param height A reference variable for holding the height of the picture. +// * \param texture A reference variable for holding the texture of the picture. +// * (same as return value) +// * \return The texture that created from the loaded image. +// */ +// GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { +// if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already +// texture = 0; +// std::string extension = filename.substr(filename.find_last_of('.')); +// if (extension == ".png") +// loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); +// else if (extension == ".jpg" || extension == ".jpeg") +// loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); +// else if (extension == ".bmp") +// loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); +// else { +// fprintf(stderr, "File extension not found\n"); +// return 0; +// } +// } else { +// texture = loadedTextures[filename]; +// } + +// return texture; +// } + +// GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself + +// // Data read from the header of the BMP file +// unsigned char header[54]; // Each BMP file begins by a 54-bytes header +// unsigned int imageSize; // = width*height*3 +// // Actual RGB data +// unsigned char * data; + +// // Open the file +// #ifdef _WIN32 +// FILE* file; +// fopen_s(&file, filename, "rb"); +// #else +// FILE* file = fopen(filename, "rb"); +// #endif + +// if (!file) { +// fprintf(stderr, "Can't open %s: no such file\n", filename); +// return 0; +// } + +// if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem +// fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); +// fclose(file); +// return 0; +// } + +// if (header[0] != 'B' || header[1] != 'M') { +// fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); +// fclose(file); +// return 0; +// } + +// imageSize = width = height = 0; +// // Get info out of header as 4 byte unsigned ints +// for (int i = 3; i >= 0; i--) +// imageSize = (imageSize << 8) | header[0x22 + i]; +// for (int i = 3; i >= 0; i--) +// width = (width << 8) | header[0x12 + i]; +// for (int i = 3; i >= 0; i--) +// height = (height << 8) | header[0x16 + i]; + +// int components = imageSize / width / height; + +// // Some BMP files are misformatted, guess missing information +// if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component + +// // Create a buffer +// data = new unsigned char[imageSize]; + +// // Read the actual data from the file into the buffer +// if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem +// fprintf(stderr, "%s: file ended unexpectedly\n", filename); +// fclose(file); +// return 0; +// } + +// //Everything is in memory now, the file can be closed +// fclose(file); + +// char tmp; +// //Reverse the endian-ness of the colors +// if (components == 4) { +// for (unsigned int i = 0; i < imageSize; i += 4) { +// tmp = data[i]; +// data[i] = data[i + 3]; +// data[i + 3] = tmp; +// tmp = data[i + 1]; +// data[i + 1] = data[i + 2]; +// data[i + 2] = tmp; +// } +// } else if (components == 3) { +// for (unsigned int i = 0; i < imageSize; i += 3) { +// tmp = data[i]; +// data[i] = data[i + 1]; +// data[i + 1] = tmp; +// } +// } + +// // Flip the image vertically, since BMPs are loaded bottom to top +// for (unsigned int j = 0; j < height - (height / 2); j++) { +// for (unsigned int i = 0; i < components * width; i++) { +// int s1 = components * width * j + i; +// int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j +// tmp = data[s1]; +// data[s1] = data[s2]; +// data[s2] = tmp; +// } +// } + +// if (components == 3) +// components = GL_RGB; +// else if (components == 4) +// components = GL_RGBA; + +// createGLtextureFromBuffer(texture, data, width, height, components); + +// delete[] data; + +// return texture; +// } + +// /*! +// * \brief Gets the dimensions of an image +// * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. +// * \param filename The file name of the picture. +// * \param width A reference variable for holding the width of the picture. +// * \param height A reference variable for holding the height of the picture. +// * \return The texture that created from the loaded image. +// */ +// void TextureHandler::getDimensions(std::string filename, int &width, int &height) { +// int w = 0, h = 0; +// stbi_info(filename.c_str(), &w, &h, 0); +// width = w; height = h; +// } + +// GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// unsigned char *data; +// int w = 0, h = 0; +// TsglDebug(std::string("Loading ") + filename); +// data = stbi_load(filename, &w, &h, 0, 4); +// assert(data); +// if (!data) { +// TsglErr(std::string("Loading ") + filename + " failed"); +// return texture; +// } +// TsglDebug(std::string("Loading ") + filename + " succeeded"); +// TsglDebug(to_string(w) + "," + to_string(h)); +// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); +// width = w, height = h; +// free(data); +// return texture; +// } + +// GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const { +// unsigned char *data; +// int w = 0, h = 0; +// TsglDebug(std::string("Loading ") + filename); +// data = stbi_load(filename, &w, &h, 0, 4); +// assert(data); +// if (!data) { +// TsglErr(std::string("Loading ") + filename + " failed"); +// return texture; +// } +// TsglDebug(std::string("Loading ") + filename + " succeeded"); +// TsglDebug(to_string(w) + "," + to_string(h)); +// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); +// width = w, height = h; +// free(data); +// return texture; +// } + +// /*! +// * \brief Saves an Image. +// * \details Saves an Image to file that was captured from a Canvas object. +// * \param filename The name of the file to save the Image to. +// * \param pixels The pixel data for the Image. +// * \param width The width of the Image. +// * \param height The height of the Image. +// * \return True if successful, false otherwise. +// */ +// bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, +// unsigned int width, unsigned int height) const { +// std::string extension = filename.substr(filename.find_last_of('.')); +// bool success = false; +// if (extension == ".png") +// success = saveToPNG(filename.c_str(), pixels, width, height); +// else if (extension == ".jpg" || extension == ".jpeg") +// fprintf(stderr, "JPG saving not implemented yet\n"); +// else if (extension == ".bmp") +// success = saveToBMP(filename.c_str(), pixels, width, height); +// else +// fprintf(stderr, "File extension not found\n"); +// return success; +// } + +// bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { +// unsigned char header[54]; // Each BMP file begins by a 54-bytes header +// unsigned int imageSize = w * h * 3; // Byte-size of the data for the image +// unsigned int totalSize = imageSize + 54; + +// // Open the file +// #ifdef _WIN32 +// FILE* file; +// fopen_s(&file, filename, "wb"); +// #else +// FILE* file = fopen(filename, "wb"); +// #endif + +// if (!file) { +// fprintf(stderr, "Can't open %s: no such file\n", filename); +// return false; +// } + +// unsigned char padding = 4 - (w * 3) % 4; +// if (padding == 4) padding = 0; +// int rawdatasize = (w * 3 + padding) * h; + +// header[0] = 'B'; +// header[1] = 'M'; +// header[2] = (unsigned char) totalSize; +// header[3] = (unsigned char)(totalSize >> 8); +// header[4] = (unsigned char)(totalSize >> 16); +// header[5] = (unsigned char)(totalSize >> 24); +// for (unsigned i = 6; i <= 9; ++i) +// header[i] = 0; +// header[10] = 54; +// for (unsigned i = 11; i <= 13; ++i) +// header[i] = 0; +// header[14] = 40; +// for (unsigned i = 15; i <= 17; ++i) +// header[i] = 0; +// header[18] = (unsigned char) w; +// header[19] = (unsigned char)(w >> 8); +// header[20] = (unsigned char)(w >> 16); +// header[21] = (unsigned char)(w >> 24); +// header[22] = (unsigned char) h; +// header[23] = (unsigned char)(h >> 8); +// header[24] = (unsigned char)(h >> 16); +// header[25] = (unsigned char)(h >> 24); +// header[26] = 1; +// header[27] = 0; +// header[28] = 24; +// header[29] = 0; +// for (unsigned i = 30; i <= 33; ++i) +// header[i] = 0; +// header[34] = (unsigned char) rawdatasize; +// header[35] = (unsigned char)(rawdatasize >> 8); +// header[36] = (unsigned char)(rawdatasize >> 16); +// header[37] = (unsigned char)(rawdatasize >> 24); +// header[38] = 19; +// header[39] = 11; +// header[40] = 0; +// header[41] = 0; +// header[42] = 19; +// header[43] = 11; +// header[44] = 0; +// header[45] = 0; +// for (unsigned i = 46; i <= 53; ++i) +// header[i] = 0; + +// unsigned char *rawdata = new unsigned char[rawdatasize]; + +// unsigned rawpos = 0, datapos = 0; +// for (unsigned j = 0; j < h; ++j) { +// for (unsigned i = 0; i < w; ++i) { +// rawdata[rawpos] = pixels[datapos+2]; +// rawdata[rawpos+1] = pixels[datapos+1]; +// rawdata[rawpos+2] = pixels[datapos]; +// rawpos += 3; +// datapos += 3; +// } +// for (unsigned i = 0; i < padding; ++i) { +// rawdata[rawpos++] = 0; +// } +// } + +// fwrite(header, 54, 1, file); +// fwrite(rawdata, 1, rawdatasize, file); +// fclose(file); + +// delete[] rawdata; + +// return true; +// } + +// bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { +// // Flip the image, since for some reason the library call +// // flips the image upside down when it saves +// for (unsigned int j = 0; j < h - (h / 2); j++) { +// for (unsigned int i = 0; i < 3 * w; i++) { +// int s1 = 3 * w * j + i; +// int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j +// char tmp = pixels[s1]; +// pixels[s1] = pixels[s2]; +// pixels[s2] = tmp; +// } +// } +// stbi_write_png(filename, w, h, 3, pixels, 0); +// return true; +// } + +// //-------------------------Unit testing--------------------------------------------- +// /*! +// * \brief Runs the Unit tests for TextureHandler. +// */ +// void TextureHandler::runTests() { +// TsglDebug("Testing TextureHandler class..."); +// TextureHandler tester; +// tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); +// TsglDebug("Unit tests for TextureHandler complete."); +// std::cout << std::endl; +// } + +// bool TextureHandler::testLoadFont(TextureHandler& test) { +// int passed = 0; //Passed tests +// int failed = 0; //Failed tests +// //Test 1: Loading in the font at the start +// if(test.fontFace == nullptr) { +// test.loadFont("../assets/freefont/FreeMono.ttf"); +// if(test.fontFace != nullptr) { +// passed++; +// } else { +// failed++; +// TsglErr("Test 1, Loading font for testLoadFont() failed!"); +// } +// } + +// if(passed == 1 && failed == 0) { +// TsglDebug("Unit test for loading in fonts passed!"); +// return true; +// } else { +// TsglErr("This many tests passed for testLoadFont: "); +// std::cout << " " << passed << std::endl; +// TsglErr("This many tests failed for testLoadFont: "); +// std::cout << " " << failed << std::endl; +// return false; +// } +// } +// //----------------------------End Unit testing--------------------------------------- +// } diff --git a/src/TSGL/TextureHandler.h b/src/TSGL/TextureHandler.h index 2017dbf19..1832ef3a0 100644 --- a/src/TSGL/TextureHandler.h +++ b/src/TSGL/TextureHandler.h @@ -1,94 +1,94 @@ -/* - * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. - */ - -#ifndef TEXTURELOADER_H_ -#define TEXTURELOADER_H_ - -#include -#include - -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#include // Needed for GL function calls - -#ifdef _WIN32 - #include - #include - #include -//#else -// #include -// #include -#endif - -#include // For GL functions -#include -#include -#include -#include - -#include "Error.h" -#include "TsglAssert.h" // For unit testing purposes -#include "Util.h" // For testing for the existence of files - -typedef GLuint GLtexture; - -namespace tsgl { - -/*! \class TextureHandler - * \brief Handles saving, loading, and rendering of images and textures. - * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas - * and CartesianCanvas through the use of GLTextures. - */ -class TextureHandler { - private: - typedef std::unordered_map TextureMap; - typedef std::unordered_map FontMap; - - TextureMap loadedTextures; - FontMap loadedFonts; - FT_Library fontLibrary; - FT_Face fontFace; - - static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, - const unsigned int &height, int glMode); +// /* +// * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. +// */ + +// #ifndef TEXTURELOADER_H_ +// #define TEXTURELOADER_H_ + +// #include +// #include + +// #include FT_FREETYPE_H +// #include FT_GLYPH_H + +// #include // Needed for GL function calls + +// #ifdef _WIN32 +// #include +// #include +// #include +// //#else +// // #include +// // #include +// #endif + +// #include // For GL functions +// #include +// #include +// #include +// #include + +// #include "Error.h" +// #include "TsglAssert.h" // For unit testing purposes +// #include "Util.h" // For testing for the existence of files + +// typedef GLuint GLtexture; + +// namespace tsgl { + +// /*! \class TextureHandler +// * \brief Handles saving, loading, and rendering of images and textures. +// * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas +// * and CartesianCanvas through the use of GLTextures. +// */ +// class TextureHandler { +// private: +// typedef std::unordered_map TextureMap; +// typedef std::unordered_map FontMap; + +// TextureMap loadedTextures; +// FontMap loadedFonts; +// FT_Library fontLibrary; +// FT_Face fontFace; + +// static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, +// const unsigned int &height, int glMode); - GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; - GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; - GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, - GLtexture &texture) const; +// GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; +// GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; +// GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, +// GLtexture &texture) const; - bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; - bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; +// bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; +// bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; - static bool testLoadFont(TextureHandler& test); +// static bool testLoadFont(TextureHandler& test); - public: - TextureHandler(); +// public: +// TextureHandler(); - ~TextureHandler(); +// ~TextureHandler(); - bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); +// bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); - bool loadFont(const std::string& filename); +// bool loadFont(const std::string& filename); - void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); +// void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); - static void getDimensions(std::string filename, int &width, int &height); +// static void getDimensions(std::string filename, int &width, int &height); - GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); +// GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); - bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; +// bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; - void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); +// void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); - static void runTests(); -}; +// static void runTests(); +// }; -} +// } -#endif /* TEXTURELOADER_H_ */ +// #endif /* TEXTURELOADER_H_ */ diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index 9b7f64401..a00cca242 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -7,19 +7,23 @@ namespace tsgl { * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. + * \param z1 The z coordinate of the first endpoint. * \param x2 The x coordinate of the second endpoint. * \param y2 The y coordinate of the second endpoint. + * \param z2 The z coordinate of the second endpoint. * \param x3 The x coordinate of the third endpoint. * \param y3 The y coordinate of the third endpoint. + * \param z3 The z coordinate of the third endpoint. + * \param yaw The yaw of the triangle's rotation. + * \param pitch The pitch of the triangle's rotation. + * \param roll The roll of the triangle's rotation. * \param color The color of the Triangle. - * \param filled Whether the Triangle should be filled - * (set to true by default). * \return A new Triangle with the specified vertices and color. */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color, bool filled) : ConvexPolygon(3, filled, !filled) { - addVertex(x1, y1, color); - addVertex(x2, y2, color); - addVertex(x3, y3, color); +Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { + addVertex(x1, y1, z1, color); + addVertex(x2, y2, z2, color); + addVertex(x3, y3, z3, color); } /*! @@ -27,94 +31,22 @@ Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFl * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. + * \param z1 The z coordinate of the first endpoint. * \param x2 The x coordinate of the second endpoint. * \param y2 The y coordinate of the second endpoint. + * \param z2 The z coordinate of the second endpoint. * \param x3 The x coordinate of the third endpoint. * \param y3 The y coordinate of the third endpoint. + * \param z3 The z coordinate of the third endpoint. + * \param yaw The yaw of the triangle's rotation. + * \param pitch The pitch of the triangle's rotation. + * \param roll The roll of the triangle's rotation. * \param color An array of colors for the Triangle's vertices. - * \param filled Whether the Triangle should be filled - * (set to true by default). * \return A new Triangle with the specified vertices and color. */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color[], bool filled) : ConvexPolygon(3, filled, !filled) { - addVertex(x1, y1, color[0]); - addVertex(x2, y2, color[1]); - addVertex(x3, y3, color[2]); -} - -/*! - * \brief Explicitly constructs a new Triangle with different monocolored fill and outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor The color of the Triangle's fill. - * \param outlineColor The color of the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor, outlineColor); - addVertex(x2, y2, fillColor, outlineColor); - addVertex(x3, y3, fillColor, outlineColor); -} - -/*! - * \brief Explicitly constructs a new Triangle with multicolored fill and monocolored outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor The color of the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor[0], outlineColor); - addVertex(x2, y2, fillColor[1], outlineColor); - addVertex(x3, y3, fillColor[2], outlineColor); -} - -/*! - * \brief Explicitly constructs a new Triangle with monocolored fill and multicolored outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor The color of the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor[]) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor, outlineColor[0]); - addVertex(x2, y2, fillColor, outlineColor[1]); - addVertex(x3, y3, fillColor, outlineColor[2]); -} - -/*! - * \brief Explicitly constructs a new Triangle with different multicolored fill and outline. - * \details This is the constructor for the Triangle class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param x3 The x coordinate of the third endpoint. - * \param y3 The y coordinate of the third endpoint. - * \param fillColor An array of colors for the Triangle's fill. - * \param outlineColor An array of colors for the Triangle's outline. - * \return A new Triangle with the specified vertices and color. - */ -Triangle::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor[]) : ConvexPolygon(3, true, true) { - addVertex(x1, y1, fillColor[0], outlineColor[0]); - addVertex(x2, y2, fillColor[1], outlineColor[1]); - addVertex(x3, y3, fillColor[2], outlineColor[2]); +Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { + addVertex(x1, y1, z1, color[0]); + addVertex(x2, y2, z2, color[1]); + addVertex(x3, y3, z3, color[2]); } } diff --git a/src/TSGL/Triangle.h b/src/TSGL/Triangle.h index 9a533108d..73124d228 100755 --- a/src/TSGL/Triangle.h +++ b/src/TSGL/Triangle.h @@ -17,17 +17,9 @@ class Triangle : public ConvexPolygon { private: public: - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color, bool filled = true); + Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color); - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat color[], bool filled = true); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor, const ColorFloat outlineColor[]); - - Triangle(int x1, int y1, int x2, int y2, int x3, int y3, const ColorFloat fillColor[], const ColorFloat outlineColor[]); + Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color[]); }; } diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index f67bcdd33..66070c56c 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -5,6 +5,7 @@ namespace tsgl { /*! * \brief Explicitly construct a new TriangleStrip with monocolored fill or outline. * \details Explicit constructor for a TriangleStrip object. + * \param x * \param numVertices The number of vertices. * \param x An array of x parameters for the vertices * \param y An array of y parameters for the vertices @@ -13,9 +14,13 @@ namespace tsgl { * (set to true by default). * \return A new TriangleStrip with the specified vertices and color. */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat color, bool filled) : ConvexPolygon(numVertices, filled, !filled) { +TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color); + addVertex(x[i], y[i], z[i], color); } } @@ -30,73 +35,13 @@ TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat color * (set to true by default). * \return A new TriangleStrip with the specified vertices and color. */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat color[], bool filled) : ConvexPolygon(numVertices, filled, !filled) { +TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { + attribMutex.lock(); + geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], color[i]); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with different monocolored fill and outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor The color of the TriangleStrip's fill. - * \param outlineColor The color of the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with multicolored fill and monocolored outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor An array of colors for the TriangleStrip's fill. - * \param outlineColor The color of the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with monocolored fill and multicolored outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor The color of the TriangleStrip's fill. - * \param outlineColor An array of colors for the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor, outlineColor[i]); - } -} - -/*! - * \brief Explicitly construct a new TriangleStrip with different multicolored fill and outline. - * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param fillColor An array of colors for the TriangleStrip's fill. - * \param outlineColor An array of colors for the TriangleStrip's outline. - * \return A new TriangleStrip with the specified vertices and color. - */ -TriangleStrip::TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]) : ConvexPolygon(numVertices, true, true) { - for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], fillColor[i], outlineColor[i]); + addVertex(x[i], y[i], z[i], color[i]); } } } diff --git a/src/TSGL/TriangleStrip.h b/src/TSGL/TriangleStrip.h index db8052c46..db38a5ae4 100755 --- a/src/TSGL/TriangleStrip.h +++ b/src/TSGL/TriangleStrip.h @@ -24,17 +24,9 @@ class TriangleStrip : public ConvexPolygon { private: public: - TriangleStrip(int numVertices, int x[], int y[], ColorFloat color, bool filled = true); + TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorGLfloat color); - TriangleStrip(int numVertices, int x[], int y[], ColorFloat color[], bool filled = true); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[]); - - TriangleStrip(int numVertices, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[]); + TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorGLfloat color[]); }; } diff --git a/src/TSGL/VisualTaskQueue.cpp b/src/TSGL/VisualTaskQueue.cpp index 077794257..95dc8c2da 100644 --- a/src/TSGL/VisualTaskQueue.cpp +++ b/src/TSGL/VisualTaskQueue.cpp @@ -1,153 +1,153 @@ -#include +// #include -namespace tsgl { +// namespace tsgl { - /*! - * \brief Default VisualTaskQueue constructor method. - * \details This is the default constructor for the VisualTaskQueue class. - * \param elements The maximum number of elements to be drawn on the VisualTaskQueue. Setting this to higher than - * the actual number of elements may result in some unused, empty rectangle. Setting this to lower than - * the actual number of elements may result in some rectangles being drawn off the VisualTaskQueue Canvas. - * \param sideLength The side length in pixels of the task rectangles to be drawn on the VisualTaskQueue Canvas. - * \param aspec The approximate aspect ratio of height/width for the VisualTaskQueue Canvas. - * \param spacing The space in pixels between the rectangles representing elements in the VisualTaskQueue. - * \param borderLength The space in pixels between the outer VisualTaskQueue rectangles and the border of the - * VisualTaskQueue Canvas. - * \return A new VisualTaskQueue with the specified maximum number of elements, rectangle side length, - * approximate aspect ratio, spacing between rectangles, and spacing around the borders. - */ -VisualTaskQueue::VisualTaskQueue(int elements, int sideLength, float aspect, int spacing, int borderLength) { - showingLegend = false; - space = spacing; - border = borderLength; - totalElements = elements; - rowLength = ceil(sqrt(totalElements/aspect)); //Number of elements per row - blockSize = sideLength; - vcan = new Canvas(0,-1,2*border+(blockSize+space)*rowLength,2*border+(blockSize+space)*elements/rowLength,"Thread colors"); - vcan->start(); - reset(); -} +// /*! +// * \brief Default VisualTaskQueue constructor method. +// * \details This is the default constructor for the VisualTaskQueue class. +// * \param elements The maximum number of elements to be drawn on the VisualTaskQueue. Setting this to higher than +// * the actual number of elements may result in some unused, empty rectangle. Setting this to lower than +// * the actual number of elements may result in some rectangles being drawn off the VisualTaskQueue Canvas. +// * \param sideLength The side length in pixels of the task rectangles to be drawn on the VisualTaskQueue Canvas. +// * \param aspec The approximate aspect ratio of height/width for the VisualTaskQueue Canvas. +// * \param spacing The space in pixels between the rectangles representing elements in the VisualTaskQueue. +// * \param borderLength The space in pixels between the outer VisualTaskQueue rectangles and the border of the +// * VisualTaskQueue Canvas. +// * \return A new VisualTaskQueue with the specified maximum number of elements, rectangle side length, +// * approximate aspect ratio, spacing between rectangles, and spacing around the borders. +// */ +// VisualTaskQueue::VisualTaskQueue(int elements, int sideLength, float aspect, int spacing, int borderLength) { +// showingLegend = false; +// space = spacing; +// border = borderLength; +// totalElements = elements; +// rowLength = ceil(sqrt(totalElements/aspect)); //Number of elements per row +// blockSize = sideLength; +// vcan = new Canvas(0,-1,2*border+(blockSize+space)*rowLength,2*border+(blockSize+space)*elements/rowLength,"Thread colors"); +// vcan->start(); +// reset(); +// } - /*! - * \brief VisualTaskQueue destructor method. - * \details This is the destructor for the VisualTaskQueue class. - * \details Frees up memory that was allocated to a VisualTaskQueue instance. - */ -VisualTaskQueue::~VisualTaskQueue() { - delete vcan; - if (showingLegend) - delete lcan; -} +// /*! +// * \brief VisualTaskQueue destructor method. +// * \details This is the destructor for the VisualTaskQueue class. +// * \details Frees up memory that was allocated to a VisualTaskQueue instance. +// */ +// VisualTaskQueue::~VisualTaskQueue() { +// delete vcan; +// if (showingLegend) +// delete lcan; +// } - /*! - * \brief Shows a key/legend for the VisualTaskQueue. - * \details This function opens up a separate Canvas displaying a legend for the VisualTaskQueue, showing which - * colors correspond to which threads. - * \param threads The number of threads the VisualTaskQueue is using. - */ -void VisualTaskQueue::showLegend(int threads) { - bool canContinue = false; - #pragma omp critical - { - if (!showingLegend) { - showingLegend = true; - canContinue = true; - } - } - if (canContinue) { - const int TEXTW = 24, GAP = 4; - if (threads == -1) - threads = omp_get_num_threads(); +// /*! +// * \brief Shows a key/legend for the VisualTaskQueue. +// * \details This function opens up a separate Canvas displaying a legend for the VisualTaskQueue, showing which +// * colors correspond to which threads. +// * \param threads The number of threads the VisualTaskQueue is using. +// */ +// void VisualTaskQueue::showLegend(int threads) { +// bool canContinue = false; +// #pragma omp critical +// { +// if (!showingLegend) { +// showingLegend = true; +// canContinue = true; +// } +// } +// if (canContinue) { +// const int TEXTW = 24, GAP = 4; +// if (threads == -1) +// threads = omp_get_num_threads(); - //Ugly calculations :( - int offset = border+space; - int xStart = border; - int xDelta = TEXTW*2; - int yStart = TEXTW + offset; - int yDelta = blockSize+space; - int oheight = vcan->getWindowHeight(); - int myHeight = TEXTW + (threads+1) * yDelta; - if (myHeight > oheight) - myHeight = oheight; - int perColumn = (myHeight-yStart)/yDelta; - int yCutoff = yStart + yDelta*perColumn-blockSize; - int myWidth = 2*border + ((threads)/perColumn)*xDelta+blockSize+TEXTW; - #ifdef _WIN32 - if (myWidth < 116); //Magic number for Windows windows... - myWidth = 116; - #endif +// //Ugly calculations :( +// int offset = border+space; +// int xStart = border; +// int xDelta = TEXTW*2; +// int yStart = TEXTW + offset; +// int yDelta = blockSize+space; +// int oheight = vcan->getWindowHeight(); +// int myHeight = TEXTW + (threads+1) * yDelta; +// if (myHeight > oheight) +// myHeight = oheight; +// int perColumn = (myHeight-yStart)/yDelta; +// int yCutoff = yStart + yDelta*perColumn-blockSize; +// int myWidth = 2*border + ((threads)/perColumn)*xDelta+blockSize+TEXTW; +// #ifdef _WIN32 +// if (myWidth < 116); //Magic number for Windows windows... +// myWidth = 116; +// #endif - //Actually draw things - lcan = new Canvas(vcan->getWindowX()+vcan->getWindowWidth(),vcan->getWindowY(),myWidth,myHeight,""); - std::cout << lcan->getWindowWidth(); - lcan->start(); - lcan->drawText("Legend:",TEXTW/2,TEXTW,TEXTW,BLACK); - int xx = xStart, yy = yStart; - for (int i = 0; i < threads; ++i) { - lcan->drawRectangle(xx,yy,blockSize,blockSize,Colors::highContrastColor(i)); - lcan->drawText(to_string(i),xx+blockSize+GAP,yy+blockSize,TEXTW/2); - yy += yDelta; - if (yy > yCutoff) { - yy = yStart; - xx += xDelta; - } - } - } -} +// //Actually draw things +// lcan = new Canvas(vcan->getWindowX()+vcan->getWindowWidth(),vcan->getWindowY(),myWidth,myHeight,""); +// std::cout << lcan->getWindowWidth(); +// lcan->start(); +// lcan->drawText("Legend:",TEXTW/2,TEXTW,TEXTW,BLACK); +// int xx = xStart, yy = yStart; +// for (int i = 0; i < threads; ++i) { +// lcan->drawRectangle(xx,yy,blockSize,blockSize,Colors::highContrastColor(i)); +// lcan->drawText(to_string(i),xx+blockSize+GAP,yy+blockSize,TEXTW/2); +// yy += yDelta; +// if (yy > yCutoff) { +// yy = yStart; +// xx += xDelta; +// } +// } +// } +// } - /*! - * \brief Updates the state of the VisualTaskQueue. - * \details This function updates an element of the VisualTaskQueue with a new state. - * \param index The index of the element to update. - * \param state The new state to put the element in. Must be one of RUNNING or FINISHED. - */ -void VisualTaskQueue::update(int index, VQState state) { - int x = index % rowLength; - int y = index / rowLength; - vcan->drawRectangle( - border+x*(blockSize+space),border+y*(blockSize+space), - blockSize,blockSize, - Colors::blend( - Colors::highContrastColor(omp_get_thread_num()),(state == RUNNING) ? BLACK : WHITE,0.5f - ),true - ); -} +// /*! +// * \brief Updates the state of the VisualTaskQueue. +// * \details This function updates an element of the VisualTaskQueue with a new state. +// * \param index The index of the element to update. +// * \param state The new state to put the element in. Must be one of RUNNING or FINISHED. +// */ +// void VisualTaskQueue::update(int index, VQState state) { +// int x = index % rowLength; +// int y = index / rowLength; +// vcan->drawRectangle( +// border+x*(blockSize+space),border+y*(blockSize+space), +// blockSize,blockSize, +// Colors::blend( +// Colors::highContrastColor(omp_get_thread_num()),(state == RUNNING) ? BLACK : WHITE,0.5f +// ),true +// ); +// } - /*! - * \brief Resets all of the elements in the VisualTaskQueue. - * \details This function tells VisualTaskQueue to clear the state information of all of the elements. - */ -void VisualTaskQueue::reset() { - for (int i = 0; i < totalElements; ++i) { - int x = i % rowLength; - int y = i / rowLength; - vcan->drawRectangle( - border+x*(blockSize+space),border+y*(blockSize+space), - blockSize,blockSize, - WHITE,true - ); - } -} +// /*! +// * \brief Resets all of the elements in the VisualTaskQueue. +// * \details This function tells VisualTaskQueue to clear the state information of all of the elements. +// */ +// void VisualTaskQueue::reset() { +// for (int i = 0; i < totalElements; ++i) { +// int x = i % rowLength; +// int y = i / rowLength; +// vcan->drawRectangle( +// border+x*(blockSize+space),border+y*(blockSize+space), +// blockSize,blockSize, +// WHITE,true +// ); +// } +// } - /*! - * \brief Closes the visual queue. - * \details This function closes and destroys the internal Canvas created by the VisualTaskQueue. - * \warning Do not attempt to reset() or update() the VisualTaskQueue after closing it. - */ -void VisualTaskQueue::close() { - if (lcan->isOpen()) - lcan->close(); - lcan->wait(); - if (showingLegend) { - if (vcan->isOpen()) - vcan->close(); - vcan->wait(); - } -} +// /*! +// * \brief Closes the visual queue. +// * \details This function closes and destroys the internal Canvas created by the VisualTaskQueue. +// * \warning Do not attempt to reset() or update() the VisualTaskQueue after closing it. +// */ +// void VisualTaskQueue::close() { +// if (lcan->isOpen()) +// lcan->close(); +// lcan->wait(); +// if (showingLegend) { +// if (vcan->isOpen()) +// vcan->close(); +// vcan->wait(); +// } +// } -void VisualTaskQueue::sleep() { - lcan->sleep(); - vcan->sleep(); -} +// void VisualTaskQueue::sleep() { +// lcan->sleep(); +// vcan->sleep(); +// } -} +// } diff --git a/src/TSGL/VisualTaskQueue.h b/src/TSGL/VisualTaskQueue.h index 601243cf7..348ec0006 100644 --- a/src/TSGL/VisualTaskQueue.h +++ b/src/TSGL/VisualTaskQueue.h @@ -1,60 +1,60 @@ -/* - * VisualTaskQueue.h provides a visual reprsentation of a generic parallel task queue - */ +// /* +// * VisualTaskQueue.h provides a visual reprsentation of a generic parallel task queue +// */ -#ifndef VISUALTASKQUEUE_H_ -#define VISUALTASKQUEUE_H_ +// #ifndef VISUALTASKQUEUE_H_ +// #define VISUALTASKQUEUE_H_ -#include -#include +// #include +// #include -#include "Canvas.h" +// #include "Canvas.h" -namespace tsgl { +// namespace tsgl { -/*! \brief Enum for states of elements in the VisualTaskQueue - * \details VQState is an enum for the valid states of an element in the VisualTaskQueue. - * \details RUNNING specifies an element is currently being worked on by some thread. - * \details FINISHED specifies an element has been completed by some thread - */ -enum VQState { - RUNNING = 0, - FINISHED = 1 -}; +// /*! \brief Enum for states of elements in the VisualTaskQueue +// * \details VQState is an enum for the valid states of an element in the VisualTaskQueue. +// * \details RUNNING specifies an element is currently being worked on by some thread. +// * \details FINISHED specifies an element has been completed by some thread +// */ +// enum VQState { +// RUNNING = 0, +// FINISHED = 1 +// }; -/*! \class VisualTaskQueue - * \brief Provides a a visualization tool for a parallel queue of elements. - * \details VisualTaskQueue is a self-contained Canvas intended to help visualize the progress of a parallel queue - * of taks or elements. - * \details Given a maximum queue length of N elements, a VisualTaskQueue will display N - * rectangles on its internal Canvas. These rectangles can be in one of three states: cleared, running, or - * finished. Cleared elements are always displayed in white, whereas running elements are displayed in a - * darker shade of the current thread's color, and finished elements are displayed in a lighter shade of the - * color of the thread the completed the element. - */ -class VisualTaskQueue { -private: - int space, border; - bool showingLegend; - Canvas *vcan, *lcan; - int rowLength, blockSize, totalElements; -public: +// /*! \class VisualTaskQueue +// * \brief Provides a a visualization tool for a parallel queue of elements. +// * \details VisualTaskQueue is a self-contained Canvas intended to help visualize the progress of a parallel queue +// * of taks or elements. +// * \details Given a maximum queue length of N elements, a VisualTaskQueue will display N +// * rectangles on its internal Canvas. These rectangles can be in one of three states: cleared, running, or +// * finished. Cleared elements are always displayed in white, whereas running elements are displayed in a +// * darker shade of the current thread's color, and finished elements are displayed in a lighter shade of the +// * color of the thread the completed the element. +// */ +// class VisualTaskQueue { +// private: +// int space, border; +// bool showingLegend; +// Canvas *vcan, *lcan; +// int rowLength, blockSize, totalElements; +// public: - VisualTaskQueue(int elements, int sideLength = 12, float aspect = 1.0f, int spacing = 2, int borderLength = 8); +// VisualTaskQueue(int elements, int sideLength = 12, float aspect = 1.0f, int spacing = 2, int borderLength = 8); - ~VisualTaskQueue(); +// ~VisualTaskQueue(); - void showLegend(int threads = -1); +// void showLegend(int threads = -1); - void update(int index, VQState state); +// void update(int index, VQState state); - void reset(); +// void reset(); - void close(); +// void close(); - void sleep(); -}; +// void sleep(); +// }; -} +// } -#endif /* VISUALTASKQUEUE_H_ */ +// #endif /* VISUALTASKQUEUE_H_ */ diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 9dbc513a0..814701197 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -5,46 +5,29 @@ using namespace tsgl; void arrowFunction(Canvas& c) { - int xs[4] = {250, 250, 750, 750}; - int ys[4] = {250, 750, 250, 750}; - ColorFloat color[2]; - color[0] = BLUE; - color[1] = YELLOW; - - //Draw double headed arrow moving around Canvas - Arrow* doubleArrow = new Arrow(500, 500, 250, 250, WHITE, true); + ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1) }; + Arrow* doubleArrow = new Arrow(0, 0, 0, 2,0,0,0, colors, true); c.add(doubleArrow); - - for(int i = 0; i < 4; i++) { - - int x = xs[i], y = ys[i]; - - // draw Arrows outlining a square centered at x, y - for(int i = -100; i <= 100; i+= 20) { - c.drawArrow(x, y, x+i, y-100, PURPLE); - c.drawArrow(x, y, x-100, y+i, GREEN); - c.drawArrow(x, y, x+100, y+i, color); - c.drawArrow(x, y, x+i, y+100, RED); - } - } - - int x = 250, y = 250; - int count = 0; - + // doubleArrow->setCenterX(1); + // doubleArrow->setRotationPoint(0,0,0); + // doubleArrow->setYaw(45); + // doubleArrow->setColor(ColorGLfloat(1,0,0,1)); + float floatVal = 0.0f; + GLfloat delta = 0.05; while( c.isOpen() ) { - if (count == 200) { - c.remove(doubleArrow); - count = 201; - } else if (count == 300) { - c.add(doubleArrow); - count = 301; - } else if (count < 300) { - count++; - } c.sleep(); - x += 10; if(x > 1000) x = 250; - y += 30; if(y > 1000) y = 250; - doubleArrow->moveHead(x, y); + // doubleArrow->setCenterX(sin(floatVal/90)); + // doubleArrow->setCenterY(sin(floatVal/90)); + // doubleArrow->setCenterZ(sin(floatVal/90)); + // doubleArrow->setYaw(floatVal); + // doubleArrow->setPitch(floatVal); + // doubleArrow->setRoll(floatVal); + // doubleArrow->setLength(sin(floatVal/90) + 2); + // if (doubleArrow->getLength() > 3 || doubleArrow->getLength() < 1) { + // delta *= -1; + // } + // doubleArrow->changeLengthBy(delta); + floatVal += 1; } delete doubleArrow; diff --git a/src/tests/testBallroom.cpp b/src/tests/testBallroom.cpp index dfb41cafb..e9181cba6 100644 --- a/src/tests/testBallroom.cpp +++ b/src/tests/testBallroom.cpp @@ -76,10 +76,10 @@ class BouncingBall { Canvas * can; public: Vector2 pos, vel, acc; - ColorFloat color; + ColorGLfloat color; int rad; bool bounced; - BouncingBall(int x, int y, int r, int w, int h, ColorFloat c, Canvas * can) { + BouncingBall(int x, int y, int r, int w, int h, ColorGLfloat c, Canvas * can) { pos = Vector2(x,y); vel = Vector2(0,0); acc = Vector2(0,0); @@ -89,11 +89,11 @@ class BouncingBall { rh = h; color = c; bounced = false; - circle = new Circle(x,y,r,c); - circle->setLayer(1); + circle = new Circle(x,y,0,r,0,0,0,c); + // circle->setLayer(1); can->add(circle); } - BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorFloat c, Canvas * canvas) { + BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorGLfloat c, Canvas * canvas) { pos = Vector2(x,y); vel = Vector2(vx,vy); acc = Vector2(0,0.1f); @@ -105,8 +105,8 @@ class BouncingBall { color = c; bounced = false; can = canvas; - circle = new Circle(x,y,r,c); - circle->setLayer(1); + circle = new Circle(x,y,0,r,0,0,0,c); + // circle->setLayer(1); can->add(circle); } ~BouncingBall() { @@ -149,7 +149,7 @@ class BouncingBall { } calcSpeed(); calcDir(); - circle->setCenter(pos.x,pos.y); + circle->setCenter(pos.x,pos.y,0); } void setRoomSize(int w, int h) { rw = w; @@ -173,7 +173,7 @@ class BouncingBall { o->calcSpeed(); o->calcDir(); bounced = true; - circle->setCenter(pos.x, pos.y); + circle->setCenter(pos.x, pos.y,0); } bool collides(BouncingBall *o) { return ((pos-o->pos).length() <= (rad+o->rad)); @@ -197,8 +197,8 @@ class BallRoom { gravity = 0.1f; attract = true; can = canvas; - mouseCircle = new Circle(0,0,25,ColorFloat(1.0f,0.5f,0.5f,0.5f)); - mouseCircle->setLayer(2); + mouseCircle = new Circle(0,0,0,1,0,0,0,ColorGLfloat(1.0,0.5,0.5,0.5)); + // mouseCircle->setLayer(2); can->add(mouseCircle); } ~BallRoom() { @@ -209,10 +209,10 @@ class BallRoom { } delete mouseCircle; } - void addBall(int x, int y, int r, ColorFloat c = WHITE) { + void addBall(int x, int y, int r, ColorGLfloat c = ColorGLfloat(1,1,1,1)) { addBall(x,y,0,0,r,c); } - void addBall(int x, int y, int vx, int vy, int r, ColorFloat c = WHITE) { + void addBall(int x, int y, int vx, int vy, int r, ColorGLfloat c = ColorGLfloat(1,1,1,1)) { BouncingBall* b = new BouncingBall(x,y,vx,vy,r,width,height,c, can); const int MAXFAIL = 1000; int fails = 0; @@ -230,11 +230,11 @@ class BallRoom { void step(Canvas* c) { int mx = c->getMouseX(), my = c->getMouseY(); Vector2 mvec(mx,my); - mouseCircle->setCenter(mx, my); + mouseCircle->setCenter(mx, my, 0); if (attract) { - mouseCircle->setColor(ColorFloat(0.5f,1.0f,1.0f,0.5f)); + mouseCircle->setColor(ColorGLfloat(0.5,1.0,1.0,0.5)); } else { - mouseCircle->setColor(ColorFloat(1.0f,0.5f,0.5f,0.5f)); + mouseCircle->setColor(ColorGLfloat(1.0,0.5,0.5,0.5)); } for (it = balls.begin(); it != balls.end(); ++it) { BouncingBall *b = (*it); @@ -294,14 +294,14 @@ void ballroomFunction(Canvas& can) { float speed = 5.0f; float dir = 2 * 3.14159f * (rand() % 100) / 100.0f; b.addBall(25 + rand() % (WW-50),25 + rand() % (WH-50),speed*cos(dir),speed*sin(dir),10, - ColorInt(64 + rand() % 192,64 + rand() % 192,64 + rand() % 192,255)); + ColorGLfloat((64 + rand() % 192) / 255,(64 + rand() % 192) / 255,(64 + rand() % 192) / 255,1)); } can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { b.toggleAttract(); }); -// ColorFloat clearcolor = ColorInt(0,0,0,16); +// ColorGLfloat clearcolor = ColorInt(0,0,0,16); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp new file mode 100644 index 000000000..ed71498f4 --- /dev/null +++ b/src/tests/testCircle.cpp @@ -0,0 +1,63 @@ +/* + * testCircle.cpp + * + * Usage: ./testCircle + */ + +#include +#include + +using namespace tsgl; + +void circleFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Circle * circle = new Circle(0,0,0,1,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // circle->setCenterX(2); + // circle->setRotationPoint(0,0,0); + can.add(circle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // circle->setCenterX(sin(floatVal/90)); + // circle->setCenterY(sin(floatVal/90)); + // circle->setCenterZ(sin(floatVal/90)); + // circle->setYaw(floatVal); + // circle->setPitch(floatVal); + // circle->setRoll(floatVal); + // circle->setRadius(sin(floatVal/90) + 1); + // if (circle->getRadius() > 3 || circle->getRadius() < 1) { + // delta *= -1; + // circle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // circle->changeRadiusBy(delta); + // if (delta > 0) { + // circle->setColor(colors); + // } else { + // circle->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } + + delete circle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Circle"); + c.setBackgroundColor(BLACK); + c.run(circleFunction); +} \ No newline at end of file diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp index 56c61c714..1361b41da 100644 --- a/src/tests/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon.cpp @@ -31,9 +31,10 @@ void concavePolygonFunction(Canvas& can) { int x[PSIZE], xx[PSIZE]; int y[PSIZE], yy[PSIZE]; - ColorFloat color[PSIZE]; + ColorGLfloat color[PSIZE]; for (unsigned i = 0; i < PSIZE; ++i) - color[i] = Colors::randomColor(1.0f); + color[i] = ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1); + x[0] = 100; y[0] = 100; x[1] = 200; y[1] = 100; @@ -49,28 +50,29 @@ void concavePolygonFunction(Canvas& can) { for (int i = 0; i < PSIZE; ++i) { if (i % 2 == 0) { - xx[i] = can.getWindowWidth() / 2 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = can.getWindowHeight() / 2 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); + xx[i] = 0 + 2.5 * sin((1.0f*i)/(PSIZE) * PI * 2); + yy[i] = 0 - 2.5 * cos((1.0f*i)/(PSIZE) * PI * 2); } else { - xx[i] = can.getWindowWidth() / 2 + 300 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = can.getWindowHeight() / 2 - 300 * cos((1.0f*i)/(PSIZE) * PI * 2); + xx[i] = 0 + 1.5 * sin((1.0f*i)/(PSIZE) * PI * 2); + yy[i] = 0 - 1.5 * cos((1.0f*i)/(PSIZE) * PI * 2); } } - ConcavePolygon * c1 = new ConcavePolygon(11, x, y, color, false); - ConcavePolygon * c2 = new ConcavePolygon(PSIZE, xx, yy, color, true); - can.add(c1); can.add(c2); + // ConcavePolygon * c1 = new ConcavePolygon(11, x, y, color, false); + ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,ColorGLfloat(1,0,0,1)); + // can.add(c1); + can.add(c2); while (can.isOpen()) { // Checks to see if the window has been closed can.sleep(); // note: when you call drawConcavePolygon, you MUST give it the correct size. // otherwise, it is always wrong and inconsistent in how it is wrong. can.pauseDrawing(); - c1->setCenter(can.getWindowWidth() / 2 + 450 * sin((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2), can.getWindowHeight() / 2 - 450 * cos((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2) ); + // c1->setCenter(can.getWindowWidth() / 2 + 450 * sin((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2), can.getWindowHeight() / 2 - 450 * cos((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2) ); can.resumeDrawing(); } - delete c1; + // delete c1; delete c2; } diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp new file mode 100644 index 000000000..4dcf6d883 --- /dev/null +++ b/src/tests/testConvexPolygon.cpp @@ -0,0 +1,59 @@ +/* + * testConvexPolygon.cpp + * + * Usage: ./testConvexPolygon + */ + +#include +#include + +using namespace tsgl; + +void convexPolygonFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + float x[] = { -0.5,-0.5,0 ,0.25,0.5,0.5,0.25 }; + float y[] = { -0.5,0.25,0.5,0.4 ,0.1,-0.1,-0.5 }; + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // cp->setCenterX(2); + // cp->setRotationPoint(0,0,0); + can.add(cp); + float floatVal = 0.0f; + while (can.isOpen()) { + can.sleep(); + // cp->setCenterX(sin(floatVal/90)); + // cp->setCenterY(sin(floatVal/90)); + // cp->setCenterZ(sin(floatVal/90)); + // cp->setYaw(floatVal); + // cp->setPitch(floatVal); + // cp->setRoll(floatVal); + // if (floatVal < 200) { + // cp->setColor(colors); + // } else { + // cp->setColor(ColorGLfloat(1,0,0,1)); + // if (floatVal > 400) { + // floatVal = 0; + // cp->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // } + floatVal += 1; + } + + delete cp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon"); + c.setBackgroundColor(BLACK); + c.run(convexPolygonFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp new file mode 100644 index 000000000..6d6ccbeed --- /dev/null +++ b/src/tests/testEllipse.cpp @@ -0,0 +1,69 @@ +/* + * testEllipse.cpp + * + * Usage: ./testEllipse + */ + +#include +#include + +using namespace tsgl; + +void ellipseFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Ellipse * ellipse = new Ellipse(0,0,0,1,2,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // ellipse->setCenterX(2); + // ellipse->setRotationPoint(0,0,0); + can.add(ellipse); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // ellipse->setCenterX(sin(floatVal/90)); + // ellipse->setCenterY(sin(floatVal/90)); + // ellipse->setCenterZ(sin(floatVal/90)); + // ellipse->setYaw(floatVal); + // ellipse->setPitch(floatVal); + // ellipse->setRoll(floatVal); + // ellipse->setXRadius(sin(floatVal/90) + 1); + // ellipse->setYRadius(sin(floatVal/90) + 2); + // if (ellipse->getXRadius() > 3 || ellipse->getXRadius() < 1) { + // delta *= -1; + // ellipse->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // ellipse->changeXRadiusBy(delta); + // if (ellipse->getYRadius() > 3 || ellipse->getYRadius() < 1) { + // delta *= -1; + // ellipse->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // ellipse->changeYRadiusBy(delta); + // if (delta > 0) { + // ellipse->setColor(colors); + // } else { + // ellipse->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } + + delete ellipse; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipse"); + c.setBackgroundColor(BLACK); + c.run(ellipseFunction); +} \ No newline at end of file diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp new file mode 100644 index 000000000..fd2e205e5 --- /dev/null +++ b/src/tests/testRectangle.cpp @@ -0,0 +1,66 @@ +/* + * testRectangle.cpp + * + * Usage: ./testRectangle + */ + +#include +#include + +using namespace tsgl; + +void rectangleFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Rectangle * rectangle = new Rectangle(0,0,0,1,2,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // rectangle->setCenterX(2); + // rectangle->setRotationPoint(0,0,0); + can.add(rectangle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // rectangle->setCenterX(sin(floatVal/90)); + // rectangle->setCenterY(sin(floatVal/90)); + // rectangle->setCenterZ(sin(floatVal/90)); + // rectangle->setYaw(floatVal); + // rectangle->setPitch(floatVal); + // rectangle->setRoll(floatVal); + // rectangle->setWidth(sin(floatVal/90) + 1); + // rectangle->setHeight(sin(floatVal/90) + 2); + // if (rectangle->getWidth() > 2 || rectangle->getWidth() < 1) { + // delta *= -1; + // // rectangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // rectangle->changeWidthBy(delta); + // if (rectangle->getHeight() > 3 || rectangle->getHeight() < 1) { + // delta *= -1; + // // rectangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // rectangle->changeHeightBy(delta); + // if (delta > 0) { + // rectangle->setColor(colors); + // } else { + // rectangle->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } + + delete rectangle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Rectangle"); + c.setBackgroundColor(BLACK); + c.run(rectangleFunction); +} \ No newline at end of file diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp new file mode 100644 index 000000000..6b6373059 --- /dev/null +++ b/src/tests/testRegularPolygon.cpp @@ -0,0 +1,60 @@ +/* + * testRegularPolygon.cpp + * + * Usage: ./testRegularPolygon + */ + +#include +#include + +using namespace tsgl; + +void rpFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + RegularPolygon * rp = new RegularPolygon(0,0,0,1,7,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // rp->setCenterX(2); + // rp->setRotationPoint(0,0,0); + can.add(rp); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // rp->setCenterX(sin(floatVal/90)); + // rp->setCenterY(sin(floatVal/90)); + // rp->setCenterZ(sin(floatVal/90)); + // rp->setYaw(floatVal); + // rp->setPitch(floatVal); + // rp->setRoll(floatVal); + // rp->setRadius(sin(floatVal/90) + 3); + // if (rp->getRadius() > 3 || rp->getRadius() < 1) { + // delta *= -1; + // rp->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // rp->changeRadiusBy(delta); + // if (delta > 0) { + // rp->setColor(colors); + // } else { + // rp->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } + + delete rp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon"); + c.setBackgroundColor(BLACK); + c.run(rpFunction); +} \ No newline at end of file diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp new file mode 100644 index 000000000..afbf159ae --- /dev/null +++ b/src/tests/testSquare.cpp @@ -0,0 +1,60 @@ +/* + * testSquare.cpp + * + * Usage: ./testSquare + */ + +#include +#include + +using namespace tsgl; + +void squareFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Square * square = new Square(0,0,0,1,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // square->setCenterX(2); + // square->setRotationPoint(0,0,0); + can.add(square); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // square->setCenterX(sin(floatVal/90)); + // square->setCenterY(sin(floatVal/90)); + // square->setCenterZ(sin(floatVal/90)); + // square->setYaw(floatVal); + // square->setPitch(floatVal); + // square->setRoll(floatVal); + // square->setSideLength(sin(floatVal/90) + 3); + // if (square->getSideLength() > 3 || square->getSideLength() < 1) { + // delta *= -1; + // // square->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // square->changeSideLengthBy(delta); + // if (delta > 0) { + // square->setColor(colors); + // } else { + // square->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } + + delete square; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Square"); + c.setBackgroundColor(BLACK); + c.run(squareFunction); +} \ No newline at end of file diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 561ef0989..01ebfda3c 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -1,5 +1,6 @@ /** * testStar.cpp tests displaying the Star class + * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. */ #include using namespace tsgl; @@ -8,40 +9,44 @@ int main() { Canvas c(-1, -1, 1000, 1000, "Stars", FRAME * 13); c.start(); - int xs[4] = {250, 250, 750, 750}; - int ys[4] = {250, 750, 250, 750}; - - ColorFloat * colors = new ColorFloat[16]; - colors[0] = YELLOW; + ColorGLfloat * colors = new ColorGLfloat[16]; + colors[0] = ColorGLfloat(1,0,0,1); for(int i = 1; i < 16; i ++) { - colors[i] = GREEN; + colors[i] = ColorGLfloat(0,1,0,1); } - float rotation = 0; - Star * s1 = new Star(xs[2], ys[2], 125, 8, colors, colors, true); - Star * s2 = new Star(xs[3], ys[3], 75, 9, PURPLE, BLUE, false); - Star * s3 = new Star(xs[0], ys[0], 100, 6, RED, true, true); - Star * s4 = new Star(xs[1], ys[1], 50, 7, BLUE, false, false); - c.add(s1); - c.add(s2); - c.add(s3); - c.add(s4); + Star * s1 = new Star(0, 0, 0, 1, 5, 0,0,0, colors, true); + s1->displayOutlineEdges(false); + // s1->setColor(ColorGLfloat(1,0,0,1)); + c.add(s1); - while( c.isOpen() ) { - c.sleep(); - c.pauseDrawing(); - rotation += PI / 3; - s1->setRotation(rotation); - c.resumeDrawing(); - c.sleepFor(1); - } + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (c.isOpen()) { + c.sleep(); + // s1->setCenterX(sin(floatVal/90)); + // s1->setCenterY(sin(floatVal/90)); + // s1->setCenterZ(sin(floatVal/90)); + // s1->setYaw(floatVal); + // s1->setPitch(floatVal); + // s1->setRoll(floatVal); + // s1->setRadius(sin(floatVal/90) + 3); + // if (s1->getRadius() > 3 || s1->getRadius() < 1) { + // delta *= -1; + // // s1->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // s1->changeRadiusBy(delta); + // if (delta > 0) { + // s1->setColor(colors); + // } else { + // s1->setColor(ColorGLfloat(1,0,0,1)); + // } + floatVal += 1; + } c.wait(); delete[] colors; - delete s1; - delete s2; - delete s3; - delete s4; + // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. return 0; } \ No newline at end of file diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp new file mode 100644 index 000000000..b1c7a5e20 --- /dev/null +++ b/src/tests/testTriangle.cpp @@ -0,0 +1,58 @@ +/* + * testTriangle.cpp + * + * Usage: ./testTriangle + */ + +#include +#include + +using namespace tsgl; + +void triangleFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + Triangle * triangle = new Triangle(-0.5,-0.5,0,0,0.5,0,0.5,-0.5,0,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // triangle->setCenterX(2); + // triangle->setRotationPoint(0,0,0); + can.add(triangle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // triangle->setCenterX(sin(floatVal/90)); + // triangle->setCenterY(sin(floatVal/90)); + // triangle->setCenterZ(sin(floatVal/90)); + // triangle->setYaw(floatVal); + // triangle->setPitch(floatVal); + // triangle->setRoll(floatVal); + if (floatVal < 200) { + triangle->setColor(colors); + } else { + triangle->setColor(ColorGLfloat(1,0,0,1)); + if (floatVal > 400) { + floatVal = 0; + triangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + } + } + floatVal += 1; + } + + delete triangle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Triangle"); + c.setBackgroundColor(BLACK); + c.run(triangleFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp new file mode 100644 index 000000000..393403145 --- /dev/null +++ b/src/tests/testTriangleStrip.cpp @@ -0,0 +1,61 @@ +/* + * testTriangleStrip.cpp + * + * Usage: ./testTriangleStrip + */ + +#include +#include + +using namespace tsgl; + +void triangleStripFunction(Canvas& can) { + ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), + ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), + ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), + ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), + ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), + ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), + ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), + ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + float x[] = { 0,-0.5,0.5,-0.5,0.5,0 }; + float y[] = { -1,-0.5,-0.5,0.5,0.5,1 }; + float z[] = { 0,0.5,0.5,0.5,0.5,0 }; + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + // ts->setCenterX(2); + // ts->setRotationPoint(0,0,0); + can.add(ts); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // ts->setCenterX(sin(floatVal/90)); + // ts->setCenterY(sin(floatVal/90)); + // ts->setCenterZ(sin(floatVal/90)); + // ts->setYaw(floatVal); + // ts->setPitch(floatVal); + // ts->setRoll(floatVal); + // if (floatVal < 200) { + // ts->setColor(colors); + // } else { + // ts->setColor(ColorGLfloat(1,0,0,1)); + // if (floatVal > 400) { + // floatVal = 0; + // ts->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // } + // } + floatVal += 1; + } + + delete ts; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip"); + c.setBackgroundColor(BLACK); + c.run(triangleStripFunction); +} \ No newline at end of file From 8fbc727424f4d2a025ea1eb3f127bb203cee2d60 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Sun, 26 Apr 2020 19:27:52 -0400 Subject: [PATCH 021/105] ConcavePolygon stuff fixed! And lines tested! --- Makefile | 1 + src/TSGL/Arrow.cpp | 169 +++++++------- src/TSGL/Arrow.h | 9 +- src/TSGL/Canvas.cpp | 4 +- src/TSGL/ConcavePolygon.cpp | 382 ++++++------------------------- src/TSGL/ConcavePolygon.h | 29 +-- src/TSGL/Drawable.cpp | 4 + src/TSGL/Line.cpp | 46 ++-- src/TSGL/Line.h | 2 +- src/TSGL/Polyline.cpp | 13 +- src/TSGL/Shape.cpp | 4 +- src/tests/testArrows.cpp | 14 +- src/tests/testConcavePolygon.cpp | 57 ++--- src/tests/testLines.cpp | 64 ++++++ src/tests/testStar.cpp | 24 +- 15 files changed, 322 insertions(+), 500 deletions(-) create mode 100644 src/tests/testLines.cpp diff --git a/Makefile b/Makefile index 1efe70a7d..e207df789 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,7 @@ BINARIES= \ bin/testCircle \ bin/testEllipse \ bin/testEllipsoid \ + bin/testLines \ bin/testPrism \ bin/testPyramid \ bin/testRectangle \ diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index 9d2f915c9..364552601 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -3,45 +3,79 @@ namespace tsgl { /*! -* \brief Explicitly constructs a new monocolored Line. -* \details This is the constructor for the Line class. -* \param x1 The x coordinate of the first endpoint. -* \param y1 The y coordinate of the first endpoint. -* \param x2 The x coordinate of the second endpoint. -* \param y2 The y coordinate of the second endpoint. -* \param color The reference variable to the color of the Line. -* \return A new Line with the specified endpoints and color. -*/ + * \brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x The x coordinate of the center of the arrow. + * \param y The y coordinate of the center of the arrow. + * \param z The z coordinate of the center of the arrow. + * \param length The length of the arrow. + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color A ColorGLfloats for the color of the Arrow. + * \return A new Arrow with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. + */ Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { - headX = -0.5; headY = 0; - tailX = 0.5; tailY = 0; + attribMutex.lock(); myXScale = length; myLength = length; isDoubleArrow = doubleArrow; - headColor = color; - tailColor = color; - generateVertices(); + attribMutex.unlock(); + addVertex(-0.4, 0.02, 0, color); + addVertex(-0.4, 0.05, 0, color); + addVertex(-0.5, 0, 0, color); + addVertex(-0.4, -0.05, 0, color); + addVertex(-0.4, -0.02, 0, color); + + if( isDoubleArrow ) { + addVertex(0.4, -0.02, 0, color); + addVertex(0.4, -0.05, 0, color); + addVertex(0.5, 0, 0, color); + addVertex(0.4, 0.05, 0, color); + addVertex(0.4, 0.02, 0, color); + } else { + addVertex(0.5, -.02, 0, color); + addVertex(0.5, .02, 0, color); + } } /*! -* \brief Explicitly constructs a new multicolored Line. -* \details This is the constructor for the Line class. -* \param x1 The x coordinate of the first endpoint. -* \param y1 The y coordinate of the first endpoint. -* \param x2 The x coordinate of the second endpoint. -* \param y2 The y coordinate of the second endpoint. -* \param color An array of colors for the line endpoints. -* \return A new Line with the specified endpoints and endpoint colors. -*/ + * \brief Explicitly constructs a new Arrow. + * \details This is the constructor for the Arrow class. + * \param x The x coordinate of the center of the arrow. + * \param y The y coordinate of the center of the arrow. + * \param z The z coordinate of the center of the arrow. + * \param length The length of the arrow. + * \param yaw The yaw of the arrow. + * \param pitch The pitch of the arrow. + * \param roll The roll of the arrow. + * \param color An array of ColorGLfloats for the colors of the Arrow. + * \return A new Arrow with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. + */ Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { - headX = -0.5; headY = 0; - tailX = 0.5; tailY = 0; + attribMutex.lock(); myXScale = length; myLength = length; isDoubleArrow = doubleArrow; - headColor = color[0]; - tailColor = color[1]; - generateVertices(); + attribMutex.unlock(); + addVertex(-0.4, 0.02, 0, color[0]); + addVertex(-0.4, 0.05, 0, color[0]); + addVertex(-0.5, 0, 0, color[0]); + addVertex(-0.4, -0.05, 0, color[0]); + addVertex(-0.4, -0.02, 0, color[0]); + + if( isDoubleArrow ) { + addVertex(0.4, -0.02, 0, color[1]); + addVertex(0.4, -0.05, 0, color[1]); + addVertex(0.5, 0, 0, color[1]); + addVertex(0.4, 0.05, 0, color[1]); + addVertex(0.4, 0.02, 0, color[1]); + } else { + addVertex(0.5, -0.02, 0, color[1]); + addVertex(0.5, 0.02, 0, color[1]); + } } void Arrow::setLength(GLfloat length) { @@ -66,67 +100,26 @@ void Arrow::changeLengthBy(GLfloat delta) { attribMutex.unlock(); } -/*! -* \brief private method helping constructor initialize vertices array for monocolored arrow -*/ -void Arrow::generateVertices() { - //TODO: figure out locking for this since we are adding vertices, which uses the lock - makeArrowHead(-0.5, 0, -1, 0, headColor); - - if( isDoubleArrow ) { - makeArrowHead(0.5, 0, 1, 0, tailColor); - } else { - float a, b; //Offsets for vertices - // if( tailY < headY ) a = 1; - // else a = -1; - a = -.02; - // if( tailX > headX ) b = 1; - // else b = -1; - b = .02; - - // addVertex(tailX-a, tailY-b, 0, tailColor); - // addVertex(tailX+a, tailY+b, 0, tailColor); - addVertex(tailX, -b, 0, tailColor); - addVertex(tailX, b, 0, tailColor); +/** + * \brief Sets the Arrow to a new color. + * \param c The new array of ColorGLfloats. + * \note Overrides Shape::setColor(ColorGLfloat c[]). + */ +void Arrow::setColor(ColorGLfloat c[]) { + for(int i = 0; i < 7; i++) { + colors[i*4] = c[i/5].R; + colors[i*4 + 1] = c[i/5].G; + colors[i*4 + 2] = c[i/5].B; + colors[i*4 + 3] = c[i/5].A; } -} - -/*! -* \brief private method helping constructor for the arrow heads -*/ -void Arrow::makeArrowHead(float x, float y, float deltaX, float deltaY, ColorGLfloat color) { - - float a, b; - // if( deltaY > 0 ) a = 1; - // else a = -1; - a = -.02; - if( deltaX < 0 ) b = .02; - else b = -.02; - // b = 1; - - // float angle = atan( deltaY / deltaX ); - float angle = 0; - // float s = sin( angle ), c = cos( angle ); - float s = 0, c = 1; - // float x1 = -10*c-(-5)*s, x2 = 2*c - 0*s, x3 = -10*c-5*s; - // float y1 = -10*s+(-5)*c, y2 = 2*s + 0*c, y3 = -10*s+5*c; - float x1 = -0.1, x2 = .02, x3 = -0.1; - float y1 = -.05, y2 = 0, y3 = .05; - // if we have an arrow pointing left, rotate it pi radians ( sin = 0, cos = -1) - if (deltaX < 0) { - x1 = -x1, x2 = -x2, x3 = -x3; - y1 = -y1, y2 = -y2, y3 = -y3; + if (isDoubleArrow) { + for(int i = 7; i < 10; i++) { + colors[i*4] = c[1].R; + colors[i*4 + 1] = c[1].G; + colors[i*4 + 2] = c[1].B; + colors[i*4 + 3] = c[1].A; + } } - // transpose the triangle to the end of the line - x1 += x, x2 += x, x3 += x; - y1 += y, y2 += y, y3 += y; - - // addVertex( (x1+x3)/2+a, (y1+y3)/2+b, 0, color ); - addVertex(x1, +b, 0, color); - addVertex(x1, y1, 0, color); - addVertex(x2, y2, 0, color); - addVertex(x3, y3, 0, color); - // addVertex( (x1+x3)/2-a, (y1+y3)/2-b, 0, color ); - addVertex(x3, -b, 0, color); } + } \ No newline at end of file diff --git a/src/TSGL/Arrow.h b/src/TSGL/Arrow.h index 3a4a7b7bd..87d17ea32 100644 --- a/src/TSGL/Arrow.h +++ b/src/TSGL/Arrow.h @@ -15,13 +15,8 @@ namespace tsgl { */ class Arrow : public ConcavePolygon { private: - float headX, headY, tailX, tailY; bool isDoubleArrow; GLfloat myLength; - ColorGLfloat headColor; - ColorGLfloat tailColor; - void makeArrowHead(float x, float y, float deltaX, float deltaY, const ColorGLfloat color); // Helps constructor by calculating the Arrow Head's coordinates - void generateVertices(); public: Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow = false); @@ -33,6 +28,10 @@ class Arrow : public ConcavePolygon { void changeLengthBy(GLfloat delta); GLfloat getLength() { return myLength; } + + void setColor(ColorGLfloat c) { Shape::setColor(c); } + + void setColor(ColorGLfloat c[]); }; } diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index ed061a8f8..9f1408255 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -236,7 +236,9 @@ void Canvas::draw() if (objectBuffer.size() > 0) { for (unsigned int i = 0; i < objectBuffer.size(); i++) { Drawable* d = objectBuffer[i]; - d->draw(); + if(d->isProcessed()) { + d->draw(); + } // if(d->isProcessed()) { // if (!d->getIsTextured()) { // d->draw(); diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index b8eca9be2..3978b6878 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -11,14 +11,10 @@ namespace tsgl { ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); edgesOutlined = false; - geometryType = GL_TRIANGLES; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices+1; - size = numberOfOutlineVertices * 3; - tsize = 0; - csize = 0; - dirty = false; - outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; vertices = new GLfloat[numberOfOutlineVertices * 3]; colors = new GLfloat[numberOfOutlineVertices * 4]; myXScale = myYScale = myZScale = 1; @@ -36,17 +32,13 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); edgesOutlined = false; - geometryType = GL_TRIANGLES; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices+1; - size = numberOfOutlineVertices * 3; - tsize = 0; - csize = 0; - dirty = false; - outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; vertices = new GLfloat[numberOfOutlineVertices * 3]; colors = new GLfloat[numberOfOutlineVertices * 4]; myXScale = myYScale = myZScale = 1; @@ -67,17 +59,13 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); edgesOutlined = false; - geometryType = GL_TRIANGLES; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices+1; - size = numberOfOutlineVertices * 3; - tsize = 0; - csize = 0; - dirty = false; - outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; vertices = new GLfloat[numberOfOutlineVertices * 3]; colors = new GLfloat[numberOfOutlineVertices * 4]; myXScale = myYScale = myZScale = 1; @@ -111,309 +99,79 @@ void ConcavePolygon::addVertex(float x, float y, float z, ColorGLfloat &color) { colors[currentColor + 3] = color.A; currentVertex += 3; currentColor += 4; - dirty = true; attribMutex.unlock(); - if (currentVertex == size-3) { + if (currentVertex == numberOfVertices*3) { attribMutex.lock(); - vertices[currentVertex] = vertices[0]; - vertices[currentVertex + 1] = vertices[1]; - vertices[currentVertex + 2] = vertices[2]; - colors[currentColor] = colors[0]; - colors[currentColor + 1] = vertices[1]; - colors[currentColor + 2] = vertices[2]; - colors[currentColor + 3] = vertices[3]; outlineArray = new GLfloat[numberOfOutlineVertices*4]; std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); - preprocess(); init = true; attribMutex.unlock(); } } - /*! - * \brief Determines if two lines intersect. - * \details Simulates two lines inside of a ConcavePolygon object and determines whether - * those two lines intersect. - * \param p0_x The x coordinate of the first point of the first line. - * \param p0_y The y coordinate of the first point of the first line. - * \param p1_x The x coordinate of the second point of the first line. - * \param p1_y The y coordinate of the second point of the first line. - * \param p2_x The x coordinate of the first point of the second line. - * \param p2_y The y coordinate of the first point of the second line. - * \param p3_x The x coordinate of the second point of the second line. - * \param p3_y The y coordinate of the second point of the second line. - * \returns true if the lines do intersect, false if otherwise. - */ -bool ConcavePolygon::intersects(float p0_x, float p0_y, float p1_x, float p1_y, - float p2_x, float p2_y, float p3_x, float p3_y) { - float s1_x, s1_y, s2_x, s2_y; - s1_x = p1_x - p0_x; s1_y = p1_y - p0_y; - s2_x = p3_x - p2_x; s2_y = p3_y - p2_y; - - float s, t; - s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); - t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); - - return (s >= 0 && s <= 1 && t >= 0 && t <= 1); -} - - /*! - * \brief Determines whether a point resides inside of a Triangle. - * \details Simulates a Triangle and point inside of a ConcavePolygon object and determines whether the point resides inside of - * the Triangle. - * \param px The x coordinate of the point. - * \param py The y coordinate of the point. - * \param x1 The x coordinate of the first vertex of the Triangle. - * \param y1 The y coordinate of the first vertex of the Triangle. - * \param x2 The x coordinate of the second vertex of the Triangle. - * \param y2 The y coordinate of the second vertex of the Triangle. - * \param x3 The x coordinate of the third vertex of the Triangle. - * \param y3 The y coordinate of the third vertex of the Triangle. - * \returns true if the point does reside in the Triangle, false if otherwise. - */ -bool ConcavePolygon::pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3) -{ - bool b1 = ( (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2) ) <= 0.0f; - bool b2 = ( (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3) ) <= 0.0f; - bool b3 = ( (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1) ) <= 0.0f; - - return ((b1 == b2) && (b2 == b3)); -} - - /*! - * \brief Process the the ConcavePolygon vertices. - * \details This function alters the vertices array so that it will render a Concave polygon correctly - * \note This function does nothing if the vertex buffer is not yet full. - * \warning This is an order of n-cubed operation, and is thus VERY SLOW. - */ -void ConcavePolygon::preprocess() { - if (dirty) { - dirty = false; - std::queue newvertices; - std::queue newcolors; - - bool clockwise = ( - ( - (vertices[3]-vertices[0]) * (vertices[7]-vertices[4]) - - (vertices[4]-vertices[1]) * (vertices[6]-vertices[3]) - ) < 0.0); - - for (int i = 0; i < size-6; i += 3) { - float x1 = vertices[i], y1 = vertices[i+1]; - for (int j = i+3; j < size-3; j += 3) { - float x2 = vertices[j], y2 = vertices[j+1]; - for (int k = j+3; k < size; k += 3) { - float x3 = vertices[k], y3 = vertices[k+1]; - - bool open = true; - for (int n = 0; n < size-3; n += 3) { - float x4 = vertices[n], y4 = vertices[n+1], x5 = vertices[n+3],y5 = vertices[n+4]; - if (pointInTriangle(x4,y4,x1,y1,x2,y2,x3,y3) || pointInTriangle(x5,y5,x1,y1,x2,y2,x3,y3)) { - open = false; break; - } - if (intersects(x1,y1,x2,y2,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x2==x5 && y2==y5) || (x1==x5 && y1==y5) || (x2==x4 && y2==y4)) ) { - open = false; break; - } - } - if (intersects(x2,y2,x3,y3,x4,y4,x5,y5)) { - if ( !( (x2==x4 && y2==y4) || (x3==x5 && y3==y5) || (x2==x5 && y2==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - if (intersects(x1,y1,x3,y3,x4,y4,x5,y5)) { - if ( !( (x1==x4 && y1==y4) || (x3==x5 && y3==y5) || (x1==x5 && y1==y5) || (x3==x4 && y3==y4)) ) { - open = false; break; - } - } - } - - //If the angle is not open (intersects something), draw nothing - if (!open) - continue; - - //If the angle is concave, draw nothing - if ( ( ( (x2-x1) * (y3-y2) - (y2-y1) * (x3-x2) ) <= 0.0) != clockwise) { - continue; - } - - newvertices.push(x1); - newvertices.push(y1); - newvertices.push(vertices[i+2]); - newcolors.push(colors[4*i/3]); - newcolors.push(colors[4*i/3+1]); - newcolors.push(colors[4*i/3+2]); - newcolors.push(colors[4*i/3+3]); - newvertices.push(x2); - newvertices.push(y2); - newvertices.push(vertices[j+2]); - newcolors.push(colors[4*j/3]); - newcolors.push(colors[4*j/3+1]); - newcolors.push(colors[4*j/3+2]); - newcolors.push(colors[4*j/3+3]); - newvertices.push(x3); - newvertices.push(y3); - newvertices.push(vertices[k+2]); - newcolors.push(colors[4*k/3]); - newcolors.push(colors[4*k/3+1]); - newcolors.push(colors[4*k/3+2]); - newcolors.push(colors[4*k/3+3]); - } - } - } - - tsize = newvertices.size(); - delete[] vertices; - vertices = new GLfloat[tsize]; - for (int i = 0; i < tsize; ++i) { - vertices[i] = newvertices.front(); - newvertices.pop(); - } - - csize = newcolors.size(); - delete[] colors; - colors = new GLfloat[csize]; - for (int i = 0; i < csize; ++i) { - colors[i] = newcolors.front(); - newcolors.pop(); - } - - numberOfVertices = tsize / 3; - - } - - //Debug Outline - // for (int i = 0; i < size; i += 6) { - // vertices[i+2] = 1.0f; - // vertices[i+3] = 1.0f; - // vertices[i+4] = 1.0f; - // vertices[i+5] = 1.0f; - // } - // glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), vertices, GL_DYNAMIC_DRAW); - // glDrawArrays(GL_LINE_STRIP, 0, length); -} - -//----------------------------------------------Unit testing------------------------------ /*! - * \brief Runs the Unit tests. - * \details Runs the Unit tests for the ConcavePolygon class. intersects() and pointInTriangle() are tested. + * \brief Draw the ConcavePolygon. + * \details This function actually draws the ConcavePolygon to the Canvas. + * \note This function overrides Drawable::draw() + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the Drawable cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). */ -void ConcavePolygon::runTests() { - TsglDebug("Testing ConcavePolygon class...."); - tsglAssert(testIntersects(), "Unit test for intersecting lines failed!"); - tsglAssert(testPointITriangle(), "Unit test for pointInTriangle() failed!"); - TsglDebug("Unit tests for ConcavePolygon complete."); - std::cout << std::endl; -} - -bool ConcavePolygon::testIntersects() { - int passed = 0; - int failed = 0; - ConcavePolygon c1(0,0,0,10,0,0,0); - - //Test 1: Intersecting lines - float x1, y1, x2, y2, x3, y3, x4, y4 = 0.0; - x1 = 230.0; //Set up the points so that it simulates two intersecting lines - y1 = 230.0; - x2 = 250.0; - y2 = 400.0; - x3 = 200.0; - y3 = 250.0; - x4 = 400.0; - y4 = 250.0; - - //They SHOULD intersect - if(c1.intersects(x1, y1, x2, y2, x3, y3, x4, y4)) { - passed++; - } else { - failed++; - TsglErr("Test 1, Intersecting lines for testIntersects() failed!"); - } - - x1 = y1 = x2 = y2 = x3 = y3 = x4 = y4 = 0.0; //Reset the x's and y's for the next test - - //Test 2: Parallel lines - x1 = 250.0; //Set up the points so that it simulates two parallel lines in the Canvas - y1 = 250.0; - x2 = 250.0; - y2 = 400.0; - x3 = 200.0; - y3 = 250.0; - x4 = 200.0; - y4 = 400.0; - - //They should NOT intersect, so if it returns false it passed - if(c1.intersects(x1, y1, x2, y2, x3, y3, x4, y4)) { - failed++; - TsglErr("Test 1, Parallel lines for testIntersects() failed!"); - } else { - passed++; - } - - //Results - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for intersecting lines passed!"); - return true; - } else { - TsglErr("This many passed for testIntersects(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testIntersects(): "); - std::cout << " " << failed << std::endl; - return false; - } -} - -bool ConcavePolygon::testPointITriangle() { - int passed = 0; - int failed = 0; - ConcavePolygon c2(0,0,0,10,0,0,0); - //Test 1: Point is in the triangle - float px, py, x1, y1, x2, y2, x3, y3 = 0.0; - - //Simulate a triangle and a point inside of it - x1 = 40.0; //Vertices... - y1 = 250.0; - x2 = 50.0; - y2 = 80.0; - x3 = 250.0; - y3 = 150.0; - px = 50.0; //Point coordinates... - py = 175.0; - - //Point SHOULD be in triangle - if(c2.pointInTriangle(px, py, x1, y1, x2, y2, x3, y3)) { - passed++; - } else { - failed++; - TsglErr("Test 1, Point = in triangle for testPointITriangle() failed!"); +void ConcavePolygon::draw() { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; } - - //Test 2: Point not in triangle - px = py = 0.0; //Reset the point - - px = 400.0; //Give it new coordinates - py = 400.0; - - //Point should NOT be in triangle, so it should return false - if(c2.pointInTriangle(px, py, x1, y1, x2, y2, x3, y3)) { - failed++; - TsglErr("Test 2, Point = NOT in triangle for testPointITriangle() failed!"); - } else { - passed++; + glPushMatrix(); + glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); + glRotatef(myCurrentYaw, 0, 0, 1); + glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentRoll, 1, 0, 0); + glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); + glScalef(myXScale, myYScale, myZScale); + + /* extra stencil buffer stuff, because it's concave */ + glClearStencil(0); + glEnable(GL_STENCIL_TEST); + glDisable(GL_CULL_FACE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_NEVER, 0, 1); + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + /* end */ + + /* We have a color array and a vertex array */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_FLOAT, 0, colors); + + glDrawArrays(geometryType, 0, numberOfVertices); + + /* extra stencil buffer stuff, because it's concave */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_FLOAT, 0, colors); + + glDrawArrays(geometryType, 0, numberOfVertices); + + glDisable(GL_STENCIL_TEST); + /* end */ + + if (edgesOutlined) { + glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); + glColorPointer(4, GL_FLOAT, 0, outlineArray); + + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); } - //Results: - if(passed == 2 && failed == 0) { - TsglDebug("Unit test for point in triangle passed!"); - return true; - } else { - TsglErr("This many passed for testPointITriangle(): "); - std::cout << " " << passed << std::endl; - TsglErr("This many failed for testPointITriangle(): "); - std::cout << " " << failed << std::endl; - return false; - } + glPopMatrix(); + + /* Cleanup states */ + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); } -//---------------------------------------------End Unit testing----------------------- } diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index dc700a5e6..c7f12617a 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -25,33 +25,16 @@ namespace tsgl { * \note Calling draw() before all vertices have been added will do nothing. */ class ConcavePolygon : public Shape { - private: - bool dirty; // Whether the new vertex buffer is dirty - int size, // Number of floating point numbers in vertices - tsize, // Number of floating point numbers in tarray - csize, // Number of floating point numbers in colors array - length; // Number of vertices in vertices (size / 6) - - static bool testIntersects(); // Unit test for intersects() - static bool testPointITriangle(); // Unit test for pointInTriangle() - - public: - ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); - - ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color); - - ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, int x[], int y[], float yaw, float pitch, float roll, ColorGLfloat color[]); - - bool intersects(float p0_x, float p0_y, float p1_x, float p1_y, - float p2_x, float p2_y, float p3_x, float p3_y); - - bool pointInTriangle (float px, float py, float x1, float y1, float x2, float y2, float x3, float y3); + protected: + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); void addVertex(float x, float y, float z, ColorGLfloat &color); + public: + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color); - void preprocess(); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color[]); - static void runTests(); + virtual void draw(); }; } diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index f2b37401d..8a50a1dc9 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -31,6 +31,10 @@ Drawable::Drawable(float x, float y, float z, float yaw, float pitch, float roll * if the above condition is met (vertex buffer = not full). */ void Drawable::draw() { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } glPushMatrix(); glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); glRotatef(myCurrentYaw, 0, 0, 1); diff --git a/src/TSGL/Line.cpp b/src/TSGL/Line.cpp index b79afa597..c9e199256 100644 --- a/src/TSGL/Line.cpp +++ b/src/TSGL/Line.cpp @@ -5,33 +5,51 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Line. * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. + * \param x The x coordinate of the center of the line. + * \param y The y coordinate of the center of the line. + * \param z The z coordinate of the center of the line. + * \param length The length of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. * \param color The reference variable to the color of the Line. - * \return A new Line with the specified endpoints and color. + * \return A new Line with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the line will be drawn directly parallel to the x-axis. */ Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color) : Polyline(x,y,z,2,yaw,pitch,roll) { + if (length <= 0) + TsglDebug("Cannot have a line with length less than or equal to 0."); + attribMutex.lock(); + myXScale = length; + myLength = length; + attribMutex.unlock(); addVertex(-0.5, 0, 0, color); addVertex(0.5, 0, 0, color); - myXScale = length; } /*! * \brief Explicitly constructs a new Line. * \details This is the constructor for the Line class. - * \param x1 The x coordinate of the first endpoint. - * \param y1 The y coordinate of the first endpoint. - * \param x2 The x coordinate of the second endpoint. - * \param y2 The y coordinate of the second endpoint. - * \param color An array for the colors of the line endpoints. - * \return A new Line with the specified endpoints and colors. + * \param x The x coordinate of the center of the line. + * \param y The y coordinate of the center of the line. + * \param z The z coordinate of the center of the line. + * \param length The length of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the colors of the Line. + * \return A new Line with the specified length and color. + * \note At 0,0,0 yaw,pitch,roll, the line will be drawn directly parallel to the x-axis. */ Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[]) : Polyline(x,y,z,2,yaw,pitch,roll) { + if (length <= 0) + TsglDebug("Cannot have a line with length less than or equal to 0."); + attribMutex.lock(); + myXScale = length; + myLength = length; + attribMutex.unlock(); addVertex(-0.5, 0, 0, color[0]); addVertex(0.5, 0, 0, color[1]); - myXScale = length; } /** @@ -53,7 +71,7 @@ void Line::setLength(GLfloat length) { * \brief Mutates the line's length by the parameter value. * \param delta The difference between the new and old line lengths. */ -void Line::changeLineLengthBy(GLfloat delta) { +void Line::changeLengthBy(GLfloat delta) { if (myLength + delta <= 0) { TsglDebug("Cannot have a Line with length less than or equal to 0."); return; diff --git a/src/TSGL/Line.h b/src/TSGL/Line.h index c72da4c24..426db71be 100755 --- a/src/TSGL/Line.h +++ b/src/TSGL/Line.h @@ -23,7 +23,7 @@ class Line : public Polyline { void setLength(GLfloat length); - void changeLineLengthBy(GLfloat delta); + void changeLengthBy(GLfloat delta); /** * \brief Returns the length of the line. diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index 75e7357bb..2ec324eda 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -18,10 +18,15 @@ namespace tsgl { Polyline::Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll) : Shape(x,y,z,yaw,pitch,roll) { if (numVertices < 2) TsglDebug("Cannot have a line with fewer than 2 vertices."); + attribMutex.lock(); numberOfVertices = numVertices; - vertices = new float[numberOfVertices*6]; - init = false; + numberOfOutlineVertices = 0; + edgesOutlined = false; + myXScale = myYScale = myZScale = 1; + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; geometryType = GL_LINE_STRIP; + attribMutex.unlock(); } /*! @@ -50,10 +55,10 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; geometryType = GL_LINE_STRIP; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color); } - attribMutex.unlock(); } /*! @@ -82,10 +87,10 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 3]; colors = new GLfloat[numberOfVertices * 4]; geometryType = GL_LINE_STRIP; + attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color[i]); } - attribMutex.unlock(); } /*! diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index ea9c42809..ba401f688 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -15,7 +15,7 @@ Shape::Shape(float x, float y, float z, float yaw, float pitch, float roll) : Dr /** * \brief Sets the Shape to a new color. - * \param c The new ColorFloat. + * \param c The new ColorGLfloat. */ void Shape::setColor(ColorGLfloat c) { for(int i = 0; i < numberOfVertices; i++) { @@ -28,7 +28,7 @@ void Shape::setColor(ColorGLfloat c) { /** * \brief Sets the Shape to a new array of colors. - * \param c The new array of ColorFloats. + * \param c The new array of ColorGLfloats. */ void Shape::setColor(ColorGLfloat c[]) { for(int i = 0; i < numberOfVertices; i++) { diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 814701197..c81fe66e5 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -6,12 +6,14 @@ using namespace tsgl; void arrowFunction(Canvas& c) { ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1) }; - Arrow* doubleArrow = new Arrow(0, 0, 0, 2,0,0,0, colors, true); + Arrow* doubleArrow = new Arrow(0, 0, 0, 2,0,0,0, colors, false); + Arrow* arrow2 = new Arrow(0,0,-1,2,90,0,0,ColorGLfloat(0,0,1,0.65), true); c.add(doubleArrow); + c.add(arrow2); // doubleArrow->setCenterX(1); // doubleArrow->setRotationPoint(0,0,0); // doubleArrow->setYaw(45); - // doubleArrow->setColor(ColorGLfloat(1,0,0,1)); + doubleArrow->setColor(colors); float floatVal = 0.0f; GLfloat delta = 0.05; while( c.isOpen() ) { @@ -23,10 +25,10 @@ void arrowFunction(Canvas& c) { // doubleArrow->setPitch(floatVal); // doubleArrow->setRoll(floatVal); // doubleArrow->setLength(sin(floatVal/90) + 2); - // if (doubleArrow->getLength() > 3 || doubleArrow->getLength() < 1) { - // delta *= -1; - // } - // doubleArrow->changeLengthBy(delta); + if (doubleArrow->getLength() > 3 || doubleArrow->getLength() < 1) { + delta *= -1; + } + doubleArrow->changeLengthBy(delta); floatVal += 1; } diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp index 1361b41da..2106a5c1d 100644 --- a/src/tests/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon.cpp @@ -14,14 +14,12 @@ using namespace tsgl; * \note See http://www.mathopenref.com/polygonconcave.html * \details * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. + * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. + * - Fill the arrays of integers, \b xx and \b yy, with specific values. * - While the Canvas is open: * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. + * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. * . * . * \param can Reference to the Canvas being drawn to. @@ -29,50 +27,43 @@ using namespace tsgl; void concavePolygonFunction(Canvas& can) { const int PSIZE = 64; - int x[PSIZE], xx[PSIZE]; - int y[PSIZE], yy[PSIZE]; + float xx[PSIZE]; + float yy[PSIZE]; ColorGLfloat color[PSIZE]; for (unsigned i = 0; i < PSIZE; ++i) color[i] = ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1); + color[1] = color[PSIZE-1]; - x[0] = 100; y[0] = 100; - x[1] = 200; y[1] = 100; - x[2] = 200; y[2] = 200; - x[3] = 300; y[3] = 200; - x[4] = 300; y[4] = 100; - x[5] = 400; y[5] = 100; - x[6] = 400; y[6] = 400; - x[7] = 300; y[7] = 300; - x[8] = 250; y[8] = 400; - x[9] = 200; y[9] = 300; - x[10] = 100; y[10] = 400; - - for (int i = 0; i < PSIZE; ++i) { + xx[0] = 0; + yy[0] = 0; + for (int i = 0; i < PSIZE-1; ++i) { if (i % 2 == 0) { - xx[i] = 0 + 2.5 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = 0 - 2.5 * cos((1.0f*i)/(PSIZE) * PI * 2); + xx[i+1] = 0 + 2.5 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 2.5 * cos((1.0f*i)/(PSIZE-2) * PI * 2); } else { - xx[i] = 0 + 1.5 * sin((1.0f*i)/(PSIZE) * PI * 2); - yy[i] = 0 - 1.5 * cos((1.0f*i)/(PSIZE) * PI * 2); + xx[i+1] = 0 + 1.5 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 1.5 * cos((1.0f*i)/(PSIZE-2) * PI * 2); } } - // ConcavePolygon * c1 = new ConcavePolygon(11, x, y, color, false); - ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,ColorGLfloat(1,0,0,1)); - // can.add(c1); + ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); + // c2->setColor(color); + // c2->setColor(ColorGLfloat(1,0,0,1)); can.add(c2); + float floatVal = 0.0f; while (can.isOpen()) { // Checks to see if the window has been closed can.sleep(); - // note: when you call drawConcavePolygon, you MUST give it the correct size. - // otherwise, it is always wrong and inconsistent in how it is wrong. - can.pauseDrawing(); - // c1->setCenter(can.getWindowWidth() / 2 + 450 * sin((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2), can.getWindowHeight() / 2 - 450 * cos((1.0f*can.getFrameNumber() / 8)/(PSIZE) * PI * 2) ); - can.resumeDrawing(); + // c2->setCenterX(sin(floatVal/90)); + // c2->setCenterY(sin(floatVal/90)); + // c2->setCenterZ(sin(floatVal/90)); + // c2->setYaw(floatVal); + // c2->setPitch(floatVal); + c2->setRoll(floatVal); + floatVal += 1; } - // delete c1; delete c2; } diff --git a/src/tests/testLines.cpp b/src/tests/testLines.cpp new file mode 100644 index 000000000..c35b61ed5 --- /dev/null +++ b/src/tests/testLines.cpp @@ -0,0 +1,64 @@ +/** + * testLines.cpp tests displaying the Line and Polyline classes. + */ +#include +using namespace tsgl; + +void lineFunction(Canvas& c) { + ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1), + ColorGLfloat(0,0,1,1), ColorGLfloat(1,0,1,1), + ColorGLfloat(1,1,0,1), ColorGLfloat(0,1,1,1), + ColorGLfloat(0,0,1,1) }; + Line * l = new Line(0,0,0,2,0,0,0,ColorGLfloat(1,0,0,1)); + + // l->setColor(ColorGLfloat(1,0,0,1)); + l->setColor(colors); + + float vertices[] = { -1.5,-1,-1, + -1,1,0, + -0.5,-1,1, + 0,-1,-1, + 0.5,1,0, + 1,-1,1, + 1.5,-1,-1 }; + + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,ColorGLfloat(0,0,1,1)); + + // p->setColor(ColorGLfloat(0,0,1,1)); + p->setColor(colors); + c.add(l); + c.add(p); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while( c.isOpen() ) { + c.sleep(); + // l->setCenterX(sin(floatVal/90)); + // l->setCenterY(sin(floatVal/90)); + // l->setCenterZ(sin(floatVal/90)); + // l->setYaw(floatVal); + // l->setPitch(floatVal); + // l->setRoll(floatVal); + // l->setLength(sin(floatVal/90) + 2); + // if (l->getLength() > 3 || l->getLength() < 1) { + // delta *= -1; + // } + // l->changeLengthBy(delta); + // p->setCenterX(sin(floatVal/90)); + // p->setCenterY(sin(floatVal/90)); + // p->setCenterZ(sin(floatVal/90)); + // p->setYaw(floatVal); + // p->setPitch(floatVal); + p->setRoll(floatVal); + floatVal += 1; + } + + delete l; + delete p; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Lines"); + c.run(lineFunction); +} \ No newline at end of file diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 01ebfda3c..0e5f0cf9d 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -5,19 +5,16 @@ #include using namespace tsgl; -int main() { - Canvas c(-1, -1, 1000, 1000, "Stars", FRAME * 13); - c.start(); - - ColorGLfloat * colors = new ColorGLfloat[16]; +void starFunction(Canvas& c) { + ColorGLfloat * colors = new ColorGLfloat[400]; colors[0] = ColorGLfloat(1,0,0,1); - for(int i = 1; i < 16; i ++) { - colors[i] = ColorGLfloat(0,1,0,1); + for(int i = 1; i < 10; i ++) { + // colors[i] = ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); + colors[i] = ColorGLfloat(0,0,1,1); } Star * s1 = new Star(0, 0, 0, 1, 5, 0,0,0, colors, true); - s1->displayOutlineEdges(false); - // s1->setColor(ColorGLfloat(1,0,0,1)); + // s1->setColor(ColorGLfloat(1,0,0,1)); c.add(s1); float floatVal = 0.0f; @@ -44,9 +41,14 @@ int main() { floatVal += 1; } - c.wait(); - delete[] colors; // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. return 0; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Stars"); + c.run(starFunction); } \ No newline at end of file From 6b0c7c0ec8c5a124a1e8e0a162a969fb1118a886 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 4 May 2020 16:46:09 -0400 Subject: [PATCH 022/105] testSolarSystem --- Makefile | 1 + src/TSGL/Drawable.h | 3 ++ src/TSGL/Sphere.cpp | 7 +-- src/tests/testConcavePolygon.cpp | 12 ++++- src/tests/testSolarSystem.cpp | 79 ++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/tests/testSolarSystem.cpp diff --git a/Makefile b/Makefile index e207df789..d5ce555f2 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ BINARIES= \ bin/testPyramid \ bin/testRectangle \ bin/testRegularPolygon \ + bin/testSolarSystem \ bin/testSphere \ bin/testSquare \ bin/testStar \ diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 6fa34fd31..54f7fedb6 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -26,6 +26,7 @@ namespace tsgl { class Drawable { protected: std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed + bool isTextured = false; bool edgesOutlined = true; int numberOfVertices; int numberOfOutlineVertices; @@ -147,6 +148,8 @@ class Drawable { * \details This function returns true only if all vertices have been inserted into an array. */ virtual bool isProcessed() { return init; } + + virtual bool getIsTextured() { return isTextured; } }; } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index bb2c88148..d85ddb010 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -17,6 +17,7 @@ namespace tsgl { * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { + // FIXME alpha param works kinda weirdly if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } @@ -38,11 +39,11 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch { for(float a=0;asetColor(color); // c2->setColor(ColorGLfloat(1,0,0,1)); @@ -60,7 +70,7 @@ void concavePolygonFunction(Canvas& can) { // c2->setCenterZ(sin(floatVal/90)); // c2->setYaw(floatVal); // c2->setPitch(floatVal); - c2->setRoll(floatVal); + // c2->setRoll(floatVal); floatVal += 1; } diff --git a/src/tests/testSolarSystem.cpp b/src/tests/testSolarSystem.cpp new file mode 100644 index 000000000..079ac11df --- /dev/null +++ b/src/tests/testSolarSystem.cpp @@ -0,0 +1,79 @@ +/* + * testSolarSystem.cpp + * + * Usage: ./testSolarSystem + */ + +#include +#include + +using namespace tsgl; + +void ssFunction(Canvas& can) { + Sphere * sun = new Sphere(0, 0, 0, 0.75, 15, 0.0, 15.0, ColorGLfloat(1,1,0,1)); + Sphere * mercury = new Sphere(0.95, 0, 0, .15, 15, 0.0, 15.0, ColorGLfloat(.8,.55,0,1)); + Sphere * venus = new Sphere(1.4, 0, 0, .25, 15, 0.0, 15.0, ColorGLfloat(1,.8,.5,1)); + Sphere * earth = new Sphere(2.05, 0, 0, .3, 15, 0.0, 15.0, ColorGLfloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(2.7, 0, 0, .2, 15, 0.0, 15.0, ColorGLfloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(3.45, 0, 0, .5, 15, 0.0, 15.0, ColorGLfloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(4.45, 0, 0, .4, 15, 0.0, 15.0, ColorGLfloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(4.45, 0, 0, .7, 15, 0, 75, ColorGLfloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(5.15, 0, 0, .25, 15, 0.0, 15.0, ColorGLfloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(5.75, 0, 0, .2, 15, 0.0, 15.0, ColorGLfloat(.25,.65,1,1)); + + saturnRings->displayOutlineEdges(false); + + mercury->setRotationPoint(0,0,0); + venus->setRotationPoint(0,0,0); + earth->setRotationPoint(0,0,0); + mars->setRotationPoint(0,0,0); + jupiter->setRotationPoint(0,0,0); + saturn->setRotationPoint(0,0,0); + saturnRings->setRotationPoint(0,0,0); + uranus->setRotationPoint(0,0,0); + neptune->setRotationPoint(0,0,0); + + can.add(sun); + can.add(mercury); + can.add(venus); + can.add(earth); + can.add(mars); + can.add(jupiter); + can.add(saturn); + can.add(saturnRings); + can.add(uranus); + can.add(neptune); + float rotation = 0.0f; + // GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + sun->setPitch(rotation); + mercury->setPitch(rotation * 4); + venus->setPitch(rotation * 3 / 2); + earth->setPitch(rotation); + mars->setPitch(rotation/2); + jupiter->setPitch(rotation/12); + saturn->setPitch(rotation/30); + saturnRings->setPitch(rotation/30); + uranus->setPitch(rotation/90); + neptune->setPitch(rotation/180); + rotation += 1; + } + + delete sun; + delete mercury; + delete venus; + delete earth; + delete mars; + delete jupiter; + delete saturn; + delete saturnRings; + delete uranus; + delete neptune; +} + +int main(int argc, char* argv[]) { + Canvas c(0, -1, 1800, 620, "Solar System"); + c.setBackgroundColor(BLACK); + c.run(ssFunction); +} \ No newline at end of file From 3508865e8a10ce95086d0ca9a24387a12e6db1fd Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 5 May 2020 21:21:08 -0400 Subject: [PATCH 023/105] Arrow update. testClock and testPanorama added. --- Makefile | 3 + src/TSGL/Arrow.cpp | 78 +++++++++++----- src/TSGL/Arrow.h | 12 ++- src/tests/testArrows.cpp | 4 +- src/tests/testClock.cpp | 108 ++++++++++++++++++++++ src/tests/testDice.cpp | 180 +++++++++++++++++++++++++++++++++++++ src/tests/testPanorama.cpp | 95 ++++++++++++++++++++ 7 files changed, 453 insertions(+), 27 deletions(-) create mode 100644 src/tests/testClock.cpp create mode 100644 src/tests/testDice.cpp create mode 100644 src/tests/testPanorama.cpp diff --git a/Makefile b/Makefile index d5ce555f2..946381d20 100644 --- a/Makefile +++ b/Makefile @@ -75,9 +75,11 @@ BINARIES= \ bin/testCuboid \ bin/testCylinder \ bin/testCircle \ + bin/testClock \ bin/testEllipse \ bin/testEllipsoid \ bin/testLines \ + bin/testPanorama \ bin/testPrism \ bin/testPyramid \ bin/testRectangle \ @@ -100,6 +102,7 @@ BINARIES= \ # bin/testConstructors \ # bin/testConway \ # bin/testCosineIntegral \ +# bin/testDice \ # bin/testDumbSort \ # bin/testFireworks \ # bin/testForestFire \ diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index 364552601..e2e148261 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -16,27 +16,33 @@ namespace tsgl { * \return A new Arrow with the specified length and color. * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. */ -Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + if (width <= 0 || length <= 0) { + TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); + return; + } attribMutex.lock(); myXScale = length; myLength = length; + myYScale = width; + myWidth = width; isDoubleArrow = doubleArrow; attribMutex.unlock(); - addVertex(-0.4, 0.02, 0, color); - addVertex(-0.4, 0.05, 0, color); + addVertex(-0.4, 0.4, 0, color); + addVertex(-0.4, 1, 0, color); addVertex(-0.5, 0, 0, color); - addVertex(-0.4, -0.05, 0, color); - addVertex(-0.4, -0.02, 0, color); + addVertex(-0.4, -1, 0, color); + addVertex(-0.4, -0.4, 0, color); if( isDoubleArrow ) { - addVertex(0.4, -0.02, 0, color); - addVertex(0.4, -0.05, 0, color); + addVertex(0.4, -0.4, 0, color); + addVertex(0.4, -1, 0, color); addVertex(0.5, 0, 0, color); - addVertex(0.4, 0.05, 0, color); - addVertex(0.4, 0.02, 0, color); + addVertex(0.4, 1, 0, color); + addVertex(0.4, 0.4, 0, color); } else { - addVertex(0.5, -.02, 0, color); - addVertex(0.5, .02, 0, color); + addVertex(0.5, -.4, 0, color); + addVertex(0.5, .4, 0, color); } } @@ -54,27 +60,33 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, * \return A new Arrow with the specified length and color. * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. */ -Arrow::Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { + if (width <= 0 || length <= 0) { + TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); + return; + } attribMutex.lock(); myXScale = length; myLength = length; + myYScale = width; + myWidth = width; isDoubleArrow = doubleArrow; attribMutex.unlock(); - addVertex(-0.4, 0.02, 0, color[0]); - addVertex(-0.4, 0.05, 0, color[0]); + addVertex(-0.4, 0.4, 0, color[0]); + addVertex(-0.4, 1, 0, color[0]); addVertex(-0.5, 0, 0, color[0]); - addVertex(-0.4, -0.05, 0, color[0]); - addVertex(-0.4, -0.02, 0, color[0]); + addVertex(-0.4, -1, 0, color[0]); + addVertex(-0.4, -0.4, 0, color[0]); if( isDoubleArrow ) { - addVertex(0.4, -0.02, 0, color[1]); - addVertex(0.4, -0.05, 0, color[1]); + addVertex(0.4, -0.4, 0, color[1]); + addVertex(0.4, -1, 0, color[1]); addVertex(0.5, 0, 0, color[1]); - addVertex(0.4, 0.05, 0, color[1]); - addVertex(0.4, 0.02, 0, color[1]); + addVertex(0.4, 1, 0, color[1]); + addVertex(0.4, 0.4, 0, color[1]); } else { - addVertex(0.5, -0.02, 0, color[1]); - addVertex(0.5, 0.02, 0, color[1]); + addVertex(0.5, -0.4, 0, color[1]); + addVertex(0.5, 0.4, 0, color[1]); } } @@ -100,6 +112,28 @@ void Arrow::changeLengthBy(GLfloat delta) { attribMutex.unlock(); } +void Arrow::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have an Arrow with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myYScale = width; + myWidth = width; + attribMutex.unlock(); +} + +void Arrow::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have an Arrow with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myYScale += delta; + myWidth += delta; + attribMutex.unlock(); +} + /** * \brief Sets the Arrow to a new color. * \param c The new array of ColorGLfloats. diff --git a/src/TSGL/Arrow.h b/src/TSGL/Arrow.h index 87d17ea32..62f22a3ab 100644 --- a/src/TSGL/Arrow.h +++ b/src/TSGL/Arrow.h @@ -16,12 +16,12 @@ namespace tsgl { class Arrow : public ConcavePolygon { private: bool isDoubleArrow; - GLfloat myLength; + GLfloat myLength, myWidth; public: - Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow = false); - Arrow(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow = false); void setLength(GLfloat length); @@ -29,6 +29,12 @@ class Arrow : public ConcavePolygon { GLfloat getLength() { return myLength; } + void setWidth(GLfloat width); + + void changeWidthBy(GLfloat delta); + + GLfloat getWidth() { return myWidth; } + void setColor(ColorGLfloat c) { Shape::setColor(c); } void setColor(ColorGLfloat c[]); diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index c81fe66e5..63aba87df 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -6,8 +6,8 @@ using namespace tsgl; void arrowFunction(Canvas& c) { ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1) }; - Arrow* doubleArrow = new Arrow(0, 0, 0, 2,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(0,0,-1,2,90,0,0,ColorGLfloat(0,0,1,0.65), true); + Arrow* doubleArrow = new Arrow(0, 0, 0, 2, 0.05,0,0,0, colors, false); + Arrow* arrow2 = new Arrow(1 ,1 ,-1 ,2 ,0.05,0,0,0,ColorGLfloat(0,0,1,0.65), true); c.add(doubleArrow); c.add(arrow2); // doubleArrow->setCenterX(1); diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp new file mode 100644 index 000000000..e9ec66462 --- /dev/null +++ b/src/tests/testClock.cpp @@ -0,0 +1,108 @@ +/* + * testClock.cpp + * + * Usage: ./testClock + */ + +#include +#include +#include + +using namespace tsgl; + +void clockFunction(Canvas& can) { + Prism * head = new Prism(0,1.33,1.01,12,1,0.59,0,0,90,ColorGLfloat(.6,.3,0,1)); + can.add(head); + + Cuboid * left = new Cuboid(-0.45,-.5,1,0.1,3,1,0,0,0,ColorGLfloat(.6,.3,0,1) ); + can.add(left); + + Cuboid * right = new Cuboid(0.45,-0.5,1,0.1,3,1,0,0,0,ColorGLfloat(.6,.3,0,1)); + can.add(right); + + Cuboid * back = new Cuboid(0,-0.5,0.55,0.8,3,0.1,0,0,0,ColorGLfloat(.6,.3,0,1) ); + can.add(back); + + Cuboid * bottom = new Cuboid(0,-1.95,1.10,0.79,0.1,0.8,0,0,0,ColorGLfloat(.6,.3,0,1) ); + can.add(bottom); + + Circle * face = new Circle(0,1.15,2.01,0.4,0,0,0,ColorGLfloat(1,1,0.8,1)); + can.add(face); + + Arrow * second = new Arrow(-0.19,1.15,2.03,0.38,0.02,0,0,0,ColorGLfloat(1,.8,.2,1),false); + can.add(second); + second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * minute = new Arrow(-0.19,1.15,2.02,0.38,0.02,0,0,0,ColorGLfloat(0,0,0,1),false); + can.add(minute); + minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * hour = new Arrow(-0.1,1.15,2.02,0.2,0.02,0,0,0,ColorGLfloat(0,0,0,1),false); + can.add(hour); + hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Ellipsoid * pendulum = new Ellipsoid(0, -1.5, 1,0.1, 0.1,0.02,0,0,0,ColorGLfloat(0.75,0.6,.19, 1) ); + pendulum->setRotationPoint(0,0.8,1); + can.add(pendulum); + + Rectangle * cord = new Rectangle(-1.1,0.8,1,2.2,0.05,90,0,0,ColorGLfloat(0,0,0,1)); + cord->setRotationPoint(0,0.8,1); + cord->displayOutlineEdges(false); + can.add(cord); + + time_t t = time(NULL); + // printf("local: %s", asctime(localtime(&t))); + // printf("local: %d:%d:%d\n", localtime(&t)->tm_hour, localtime(&t)->tm_min, localtime(&t)->tm_sec); + + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + + float speed = -0.28; + bool accelerationPositive = true; + while (can.isOpen()) { + can.sleep(); + t = time(NULL); + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + if (cord->getYaw() > 97 || cord->getYaw() < 83) { + speed = 0; + } + if (cord->getYaw() > 90 && accelerationPositive == true) { + accelerationPositive = false; + } else if (cord->getYaw() < 90 && accelerationPositive == false) { + accelerationPositive = true; + } + if (accelerationPositive) { + speed += 0.01; + } else { + speed -= 0.01; + } + cord->changeYawBy(speed); + pendulum->changeYawBy(speed); + + } + + delete head; + delete left; + delete right; + delete back; + delete bottom; + delete face; + delete second; + delete minute; + delete hour; + delete pendulum; + delete cord; +} + +int main(int argc, char* argv[]) { + // int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + // int h = (argc > 2) ? atoi(argv[2]) : w; + // if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + // w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 500, 700, "Grandfather Clock"); + c.setBackgroundColor(WHITE); + c.run(clockFunction); +} \ No newline at end of file diff --git a/src/tests/testDice.cpp b/src/tests/testDice.cpp new file mode 100644 index 000000000..673866913 --- /dev/null +++ b/src/tests/testDice.cpp @@ -0,0 +1,180 @@ +/* + * testDice.cpp + * + * Usage: ./testDice + * Note: currently has some interesting rotation issues that mean that the + * API will probably have to be updated. Not compiling since it won't + * really work, alter the Makefile to understand the issue. Has to do with composite + * Euler angles. + */ + +#include +#include + +using namespace tsgl; + +void diceFunction(Canvas& can) { + Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, ColorGLfloat(1,1,1,1)); + can.add(die); + + RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,ColorGLfloat(0,0,0,1)); + can.add(spot1); + spot1->setRotationPoint(0,0,0); + + + RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,ColorGLfloat(0,0,0,1) ); + spot2_1->setRotationPoint(0,0,0); + can.add(spot2_1); + RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,ColorGLfloat(0,0,0,1) ); + spot2_2->setRotationPoint(0,0,0); + can.add(spot2_2); + + RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + spot3_1->setRotationPoint(0,0,0); + can.add(spot3_1); + RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + spot3_2->setRotationPoint(0,0,0); + can.add(spot3_2); + RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + spot3_3->setRotationPoint(0,0,0); + can.add(spot3_3); + + // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // spot4_1->setRotationPoint(0,0,0); + // can.add(spot4_1); + // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // spot4_2->setRotationPoint(0,0,0); + // can.add(spot4_2); + // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // spot4_3->setRotationPoint(0,0,0); + // can.add(spot4_3); + // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // spot4_4->setRotationPoint(0,0,0); + // can.add(spot4_4); + + RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + spot5_1->setRotationPoint(0,0,0); + can.add(spot5_1); + RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + spot5_2->setRotationPoint(0,0,0); + can.add(spot5_2); + RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + spot5_3->setRotationPoint(0,0,0); + can.add(spot5_3); + RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + spot5_4->setRotationPoint(0,0,0); + can.add(spot5_4); + RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + spot5_5->setRotationPoint(0,0,0); + can.add(spot5_5); + + RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_1); + RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_2); + RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_3); + RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_4); + RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_5); + RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + can.add(spot6_6); + spot6_1->setRotationPoint(0,0,0); + spot6_2->setRotationPoint(0,0,0); + spot6_3->setRotationPoint(0,0,0); + spot6_4->setRotationPoint(0,0,0); + spot6_5->setRotationPoint(0,0,0); + spot6_6->setRotationPoint(0,0,0); + + // die->setRoll(45); + // spot1->setRoll(45); + // spot2_1->setRoll(45-90); + // spot2_2->setRoll(45-90); + // spot3_1->setRoll(180); + // spot3_2->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot4_1->setRoll(45); + // spot4_2->setRoll(45); + // spot4_3->setRoll(45); + // spot4_4->setRoll(45); + // spot5_1->setRoll(45+90); + // spot5_2->setRoll(45+90); + // spot5_3->setRoll(45+90); + // spot5_4->setRoll(45+90); + // spot5_5->setRoll(45+90); + // spot6_1->setRoll(45+180); + // spot6_2->setRoll(45+180); + // spot6_3->setRoll(45+180); + // spot6_4->setRoll(45+180); + // spot6_5->setRoll(45+180); + // spot6_6->setRoll(45+180); + + float rotation = 0; + while (can.isOpen()) { + can.sleep(); + // die->setRoll(rotation); + // spot1->setRoll(rotation); + // spot2_1->setRoll(rotation-90); + // spot2_2->setRoll(rotation-90); + // spot3_1->setPitch(rotation); + // spot3_2->setPitch(rotation); + // spot3_3->setPitch(rotation); + // spot4_1->setRoll(rotation); + // spot4_2->setRoll(rotation); + // spot4_3->setRoll(rotation); + // spot4_4->setRoll(rotation); + // spot5_1->setRoll(rotation+90); + // spot5_2->setRoll(rotation+90); + // spot5_3->setRoll(rotation+90); + // spot5_4->setRoll(rotation+90); + // spot5_5->setRoll(rotation+90); + // spot6_1->setRoll(rotation+180); + // spot6_2->setRoll(rotation+180); + // spot6_3->setRoll(rotation+180); + // spot6_4->setRoll(rotation+180); + // spot6_5->setRoll(rotation+180); + // spot6_6->setRoll(rotation+180); + + die->setPitch(rotation); + spot1->setPitch(rotation); + spot2_1->setPitch(rotation); + spot2_2->setPitch(rotation); + spot3_1->setPitch(rotation-90); + spot3_2->setPitch(rotation-90); + spot3_3->setPitch(rotation-90); + // spot4_1->setPitch(rotation+90); + // spot4_2->setPitch(rotation+90); + // spot4_3->setPitch(rotation+90); + // spot4_4->setPitch(rotation+90); + spot5_1->setPitch(rotation); + spot5_2->setPitch(rotation); + spot5_3->setPitch(rotation); + spot5_4->setPitch(rotation); + spot5_5->setPitch(rotation); + spot6_1->setPitch(rotation); + spot6_2->setPitch(rotation); + spot6_3->setPitch(rotation); + spot6_4->setPitch(rotation); + spot6_5->setPitch(rotation); + spot6_6->setPitch(rotation); + rotation += 1; + } + + delete die; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Dice Rolling"); + c.setBackgroundColor(GRAY); + c.run(diceFunction); +} \ No newline at end of file diff --git a/src/tests/testPanorama.cpp b/src/tests/testPanorama.cpp new file mode 100644 index 000000000..2b6c44852 --- /dev/null +++ b/src/tests/testPanorama.cpp @@ -0,0 +1,95 @@ +/* + * testPanorama.cpp + * + * Usage: ./testPanorama + */ + +#include +#include + +using namespace tsgl; + +void panoramaFunction(Canvas& can) { + Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,ColorGLfloat(1,1,1,1)); + blankCanvas->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + can.add(blankCanvas); + + Rectangle * emptyPanoramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); + emptyPanoramaLeft->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + can.add(emptyPanoramaLeft); + Rectangle * emptyPanoramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); + emptyPanoramaRight->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + can.add(emptyPanoramaRight); + Rectangle * emptyPanoramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); + emptyPanoramaTop->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + can.add(emptyPanoramaTop); + Rectangle * emptyPanoramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); + emptyPanoramaBottom->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + can.add(emptyPanoramaBottom); + + Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorGLfloat(.6,.3,0,1)); + trunk->displayOutlineEdges(false); + can.add(trunk); + + Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,ColorGLfloat(0,1,0,1)); + can.add(leaves); + + Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorGLfloat(.6,.3,0,1)); + trunkFlat->displayOutlineEdges(false); + can.add(trunkFlat); + + Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorGLfloat(0,0.8,0,1)); + can.add(leavesFlat); + + float counter = 1; + while (can.isOpen()) { + // can.sleepFor(0.5); + can.sleep(); + if (counter < 10) { + emptyPanoramaLeft->setWidth(2.7/(counter*4)); + emptyPanoramaRight->setWidth(2.7/(counter*4)); + emptyPanoramaTop->setHeight(2.7/(counter*4)); + emptyPanoramaBottom->setHeight(2.7/(counter*4)); + emptyPanoramaTop->setCenterZ(1.35-1.35/counter); + emptyPanoramaBottom->setCenterZ(1.35-1.35/counter); + emptyPanoramaLeft->setCenterZ(1.35-1.35/counter); + emptyPanoramaRight->setCenterZ(1.35-1.35/counter); + trunk->setLength(0.25/counter); + trunk->setCenterZ(1.35-1.35/counter); + leaves->setZRadius(0.4/counter); + leaves->setCenterZ(1.35-1.35/counter); + counter += 0.05; + } else { + emptyPanoramaLeft->setWidth(0.01); + emptyPanoramaRight->setWidth(0.01); + emptyPanoramaTop->setHeight(0.01); + emptyPanoramaBottom->setHeight(0.01); + emptyPanoramaTop->setCenterZ(1.35); + emptyPanoramaBottom->setCenterZ(1.35); + emptyPanoramaLeft->setCenterZ(1.35); + emptyPanoramaRight->setCenterZ(1.35); + trunk->setLength(0.25/counter); + trunk->setCenterZ(1.35-1.35/counter); + leaves->setZRadius(0.4/counter); + leaves->setCenterZ(1.35-1.35/counter); + } + // printf("%f\n", counter); + } + + delete blankCanvas; + delete emptyPanoramaLeft; + delete emptyPanoramaRight; + delete emptyPanoramaTop; + delete emptyPanoramaBottom; + +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Panorama vs. Painting"); + c.setBackgroundColor(WHITE); + c.run(panoramaFunction); +} \ No newline at end of file From 6ec6f1d357eb74fb344984dfc93807c0a68dc841 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 6 May 2020 20:18:46 -0400 Subject: [PATCH 024/105] testPhilosophers fixed + test3DPhilosophers added --- Makefile | 9 +- src/TSGL/Canvas.cpp | 2 +- src/TSGL/Canvas.h | 1 + src/tests/DiningPhilosophers/Fork.h | 24 +- src/tests/DiningPhilosophers/Philosopher.cpp | 22 +- src/tests/DiningPhilosophers/Philosopher.h | 2 +- src/tests/DiningPhilosophers/Table.cpp | 63 +-- src/tests/DiningPhilosophers/Table.h | 7 +- src/tests/DiningPhilosophers3D/Fork3D.h | 53 ++ .../DiningPhilosophers3D/Philosopher3D.cpp | 110 ++++ .../DiningPhilosophers3D/Philosopher3D.h | 81 +++ src/tests/DiningPhilosophers3D/Table3D.cpp | 488 ++++++++++++++++++ src/tests/DiningPhilosophers3D/Table3D.h | 55 ++ src/tests/DiningPhilosophers3D/philEnums.h | 22 + src/tests/test3DPhilosophers.cpp | 107 ++++ 15 files changed, 984 insertions(+), 62 deletions(-) create mode 100644 src/tests/DiningPhilosophers3D/Fork3D.h create mode 100644 src/tests/DiningPhilosophers3D/Philosopher3D.cpp create mode 100644 src/tests/DiningPhilosophers3D/Philosopher3D.h create mode 100644 src/tests/DiningPhilosophers3D/Table3D.cpp create mode 100644 src/tests/DiningPhilosophers3D/Table3D.h create mode 100644 src/tests/DiningPhilosophers3D/philEnums.h create mode 100644 src/tests/test3DPhilosophers.cpp diff --git a/Makefile b/Makefile index 946381d20..ccb4c1e88 100644 --- a/Makefile +++ b/Makefile @@ -68,18 +68,20 @@ BINARIES= \ bin/test3DRotation \ bin/testArrows \ bin/testBallroom \ + bin/testCircle \ + bin/testClock \ bin/testCone \ bin/testConvexPolygon \ bin/testConcavePolygon \ bin/testCube \ bin/testCuboid \ bin/testCylinder \ - bin/testCircle \ - bin/testClock \ bin/testEllipse \ bin/testEllipsoid \ bin/testLines \ bin/testPanorama \ + bin/testPhilosophers \ + bin/test3DPhilosophers \ bin/testPrism \ bin/testPyramid \ bin/testRectangle \ @@ -121,7 +123,6 @@ BINARIES= \ # bin/testMandelbrot \ # bin/testMouse \ # bin/testNewtonPendulum \ -# bin/testPhilosophers \ # bin/testProducerConsumer \ # bin/testPong \ # bin/testProgressBar \ @@ -199,6 +200,8 @@ lib/libtsgl.a: ${OBJS} @touch build/build #List additional dependencies for test binaries +bin/test3DPhilosophers: build/tests/DiningPhilosophers3D/Philosopher3D.o \ + build/tests/DiningPhilosophers3D/Table3D.o bin/testConway: build/tests/Conway/LifeFarm.o bin/testFireworks: build/tests/Fireworks/Arc.o \ build/tests/Fireworks/Dot.o \ diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 9f1408255..388487eb9 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -207,7 +207,7 @@ void Canvas::draw() glfwMakeContextCurrent(window); // Reset the window glfwSetWindowShouldClose(window, GL_FALSE); - while(!glfwWindowShouldClose(window)) + for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { #ifdef __APPLE__ // leftWindowIndex = 0; diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 22d3b2483..089f5230b 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -45,6 +45,7 @@ #include // For string building #include // For window titles #include +#include #ifdef __APPLE__ #include #else diff --git a/src/tests/DiningPhilosophers/Fork.h b/src/tests/DiningPhilosophers/Fork.h index 53e136095..58600178a 100644 --- a/src/tests/DiningPhilosophers/Fork.h +++ b/src/tests/DiningPhilosophers/Fork.h @@ -16,34 +16,34 @@ struct Fork { user = -1; id = 0; const int POINTS = 20; // number of vertices in polygon - const int HEIGHT = 42; // 42 is preferred, but can be changed - const int WIDTH = 12; // 12 is preferred, but can be changed - int xs[POINTS], ys[POINTS]; + const float HEIGHT = .42; // 42 is preferred, but can be changed + const float WIDTH = .12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; // scales (out of 100) for the dimensions of the fork - double xscale[POINTS] = {0, 19, 19, 27, 27, 46, 46, 54, 54, 73, 73, 81, 81, 100, 100, 65, 65, 35, 35, 0}; - double yscale[POINTS] = {0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 30, 30, 100, 100, 30, 30}; + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; // create the fork points from the scale arrays for(int i = 0; i < POINTS; ++i) { // scale the fork xs[i] = WIDTH * xscale[i]; ys[i] = HEIGHT * yscale[i]; - xs[i] = xs[i]/100; - ys[i] = ys[i]/100; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; } //Add vertices - myShape = new ConcavePolygon(POINTS, xs, ys, BLACK, BLACK); + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorGLfloat(1,1,1,1)); } void setCanvas( Canvas* can) { can->add(myShape); } - void draw(int x, int y, double angle, ColorFloat c) { + void draw(float x, float y, double angle, ColorGLfloat c) { angle -= PI/2; - myShape->setColor(c, (c.asString() != "0R,0G,0B,1A")? BLACK : DARKGRAY); - myShape->setCenter(x, y); - myShape->setRotation(angle); + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); } ~Fork() { delete myShape; diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp index 5d58f8812..f57b73108 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/tests/DiningPhilosophers/Philosopher.cpp @@ -19,10 +19,10 @@ Philosopher::~Philosopher() { /** * Adds Philosopher to Canvas or refreshes its color. */ -void Philosopher::draw(Canvas& can, int x, int y) { - const int SIZE = 32; +void Philosopher::draw(Canvas& can, float x, float y) { + const float SIZE = .5; if( !myCircle) { - myCircle = new Circle(x,y,SIZE,RED,BLACK); + myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorGLfloat(1,0,0,1)); can.add(myCircle); } } @@ -31,16 +31,16 @@ void Philosopher::draw(Canvas& can, int x, int y) { * Updates the Philosopher's color based on its state */ void Philosopher::refreshColor() { - ColorFloat c; + ColorGLfloat c; switch(myState) { - case hasNone: c=RED; break; - case hasRight: c=ORANGE; break; - case hasLeft: c=PURPLE; break; - case hasBoth: c=GREEN; break; - case isFull: c=BLUE; break; - case thinking: c=BLUE; break; + case hasNone: c=ColorGLfloat(1,0,0,1); break; + case hasRight: c=ColorGLfloat(1,0.65,0,1); break; + case hasLeft: c=ColorGLfloat(0.75, 0.0, 0.75, 1.0); break; + case hasBoth: c=ColorGLfloat(0, 1.0, 0, 1.0); break; + case isFull: c=ColorGLfloat(0,0,1, 1.0); break; + case thinking: c=ColorGLfloat(0,0,1, 1.0); break; } - myCircle->setColor(c, BLACK); + myCircle->setColor(c); } /** diff --git a/src/tests/DiningPhilosophers/Philosopher.h b/src/tests/DiningPhilosophers/Philosopher.h index 2e1df70ed..bf27a1b59 100644 --- a/src/tests/DiningPhilosophers/Philosopher.h +++ b/src/tests/DiningPhilosophers/Philosopher.h @@ -25,7 +25,7 @@ class Philosopher { public: Philosopher(); ~Philosopher(); - void draw(Canvas& can, int x, int y); + void draw(Canvas& can, float x, float y); void refreshColor(); void addMeal(); bool acquire(Fork& f); diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 6ce0bee2f..bd49b2212 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -10,9 +10,9 @@ Table::Table(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - tabX = can.getWindowWidth()/2; - tabY = can.getWindowHeight()/2; - can.drawCircle(tabX,tabY,252,DARKGRAY); + myTable = new Circle(0,0,-1,2.2,0,0,0,ColorGLfloat(0.5,0.5,0.5,1)); + can.add(myTable); + // can.drawCircle(0,0,1,ColorGLfloat(0.5,0.5,0.5,1)); phils = new Philosopher[numPhils]; forks = new Fork[numPhils]; for (int i = 0; i < numPhils; ++i) { @@ -20,10 +20,10 @@ Table::Table(Canvas& can, int p, PhilMethod m) { forks[i].id = i; forks[i].setCanvas(myCan); } - float delta = 2.0f / numPhils * PI; - for(int i = 0; i < numPhils; i++) { - myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); - } + // float delta = 2.0f / numPhils * PI; + // for(int i = 0; i < numPhils; i++) { + // myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); + // } myMethod = m; switch(myMethod) { case forfeitWhenBlocked: @@ -45,27 +45,28 @@ Table::Table(Canvas& can, int p, PhilMethod m) { break; } - myCan2 = new Canvas(0,0,300,300,"Legend"); - myCan2->start(); - myCan2->drawText("Method:",16,32,32,BLACK); - myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); - myCan2->drawText("Legend:",16,96,24,BLACK); - myCan2->drawText("Red: Hungry",32,128,24,RED); - myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); - myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); - myCan2->drawText("Green: Eating",32,224,24,GREEN); - myCan2->drawText("Blue: Thinking",32,256,24,BLUE); - myCan2->drawText("Meals eaten: ",32,288,24,BROWN); - myCan2->drawCircle(165,281,3,BROWN); + // myCan2 = new Canvas(0,0,300,300,"Legend"); + // myCan2->start(); + // myCan2->drawText("Method:",16,32,32,BLACK); + // myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); + // myCan2->drawText("Legend:",16,96,24,BLACK); + // myCan2->drawText("Red: Hungry",32,128,24,RED); + // myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); + // myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); + // myCan2->drawText("Green: Eating",32,224,24,GREEN); + // myCan2->drawText("Blue: Thinking",32,256,24,BLUE); + // myCan2->drawText("Meals eaten: ",32,288,24,BROWN); + // myCan2->drawCircle(165,281,3,BROWN); } /*! * \brief Destructor for Table. */ Table::~Table() { - if (myCan2->isOpen()) - myCan2->stop(); - delete myCan2; + // if (myCan2->isOpen()) + // myCan2->stop(); + // delete myCan2; + delete myTable; delete [] phils; delete [] forks; } @@ -451,38 +452,38 @@ void Table::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table::drawStep() { - const int RAD = 300; - int FORK_RAD = 250; + const float RAD = 2.4; + float FORK_RAD = 2; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; const float BASEDIST = RAD+64; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; - ColorFloat fcolor = BLACK; + ColorGLfloat fcolor = ColorGLfloat(1,1,1,1); float fangle = (i+0.5f)*ARC; if( !phils[i].hasCircle() ) { - phils[i].draw(*myCan,tabX+RAD*cos(pangle),tabY+RAD*sin(pangle)); + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); } phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); float angle = pangle+(meals/10)*2*PI/RAD, dist = BASEDIST+8*(meals%10); - myCan->drawRegularPolygon(tabX+dist*cos(angle), tabY+dist*sin(angle), 3, 10 ,BROWN, BLACK); + // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); phils[i].addMeal(); } if (forks[i].user == i) { fangle = i*ARC + CLOSE; - fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; + fcolor = (phils[i].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(0.75,0,0.75,1); } else if((forks[i].user == (i+1)%numPhils)) { fangle = ((i+1)*ARC) - CLOSE; - fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); } else { - FORK_RAD = 220; + FORK_RAD = 1.8; fangle = pangle + PI / numPhils; } - forks[i].draw(tabX+FORK_RAD*cos(fangle),tabY+FORK_RAD*sin(fangle),fangle,fcolor); + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); } \ No newline at end of file diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h index 417492154..e4429afd5 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/tests/DiningPhilosophers/Table.h @@ -22,13 +22,14 @@ using namespace tsgl; class Table { private: - int tabX, tabY, numPhils; + int numPhils; PhilMethod myMethod; std::string methodString; - Canvas *myCan, *myCan2; + Canvas *myCan/* , *myCan2 */; Philosopher *phils; Fork *forks; - TextureHandler loader; + Circle * myTable; + // TextureHandler loader; public: Table(Canvas& can, int p, PhilMethod m); diff --git a/src/tests/DiningPhilosophers3D/Fork3D.h b/src/tests/DiningPhilosophers3D/Fork3D.h new file mode 100644 index 000000000..37ee24529 --- /dev/null +++ b/src/tests/DiningPhilosophers3D/Fork3D.h @@ -0,0 +1,53 @@ +/*! + * \struct Fork3D + * \brief Struct for the forks in the 3D visualization of the Dining Philosophers' problem + */ + +#ifndef FORK3D_H_ +#define FORK3D_H_ + +#include +using namespace tsgl; + +struct Fork3D { + int user, id; + ConcavePolygon * myShape; + Fork3D() { + user = -1; id = 0; + + const int POINTS = 20; // number of vertices in polygon + const float HEIGHT = .42; // 42 is preferred, but can be changed + const float WIDTH = .12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; + + // scales (out of 100) for the dimensions of the 3D fork + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; + + // create the 3D fork points from the scale arrays + for(int i = 0; i < POINTS; ++i) { + // scale the 3D fork + xs[i] = WIDTH * xscale[i]; + ys[i] = HEIGHT * yscale[i]; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; + } + + //Add vertices + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorGLfloat(1,1,1,1)); + } + void setCanvas( Canvas* can) { + can->add(myShape); + } + void draw(float x, float y, double angle, ColorGLfloat c) { + angle -= PI/2; + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); + } + ~Fork3D() { + delete myShape; + } +}; + +#endif /* FORK3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp new file mode 100644 index 000000000..f749d7245 --- /dev/null +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp @@ -0,0 +1,110 @@ +#include "Philosopher3D.h" + +/*! + * \brief Explicitly constructs a new Philosopher3D. + * \details Explicit constructor for a new Philosopher3D object. + */ +Philosopher3D::Philosopher3D() { + setId(0,1); + myState = hasNone; + myAction = doNothing; + myCylinder = NULL; + myCone = NULL; + numMeals = 0; +} + +Philosopher3D::~Philosopher3D() { + delete myCylinder; + delete myCone; +} + +/** + * Adds Philosopher3D to Canvas or refreshes its color. + */ +void Philosopher3D::draw(Canvas& can, float x, float y) { + const float SIZE = .5; + if( !myCylinder) { + myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,ColorGLfloat(1,0,0,1)); + can.add(myCylinder); + } + if( !myCone && myCylinder) { + myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorGLfloat(0.7,0,0,1)); + myCone->setRotationPoint(myCylinder->getCenterX(), myCylinder->getCenterY(), myCylinder->getCenterZ()); + can.add(myCone); + } +} + +/** + * Updates the Philosopher3D's color based on its state + */ +void Philosopher3D::refreshColor() { + ColorGLfloat c; + switch(myState) { + case hasNone: c=ColorGLfloat(1,0,0,1); break; + case hasRight: c=ColorGLfloat(1,0.65,0,1); break; + case hasLeft: c=ColorGLfloat(0.75, 0.0, 0.75, 1.0); break; + case hasBoth: c=ColorGLfloat(0, 1.0, 0, 1.0); break; + case isFull: c=ColorGLfloat(0,0,1, 1.0); break; + case thinking: c=ColorGLfloat(0,0,1, 1.0); break; + } + myCylinder->setColor(c); + myCone->setColor(ColorGLfloat(c.R*.7,c.G*.7,c.B*.7,c.A)); +} + +/** + * Adds a meal representation to meals and the Canvas + */ +void Philosopher3D::addMeal() { + numMeals++; +} + +/** + * Picks up a fork specified by its reference + */ +bool Philosopher3D::acquire(Fork3D& f) { + if (f.user >= 0) + return false; + if (f.id == myLeft) { + if (myState == hasNone) + myState = hasLeft; + else if (myState == hasRight) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + if (f.id == myRight) { + if (myState == hasNone) + myState = hasRight; + else if (myState == hasLeft) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + return false; +} + +/** + * Releases a fork specified by its reference + */ +bool Philosopher3D::release(Fork3D& f) { + if (f.user != id) + return false; + if (myState != isFull) + myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; + f.user = -1; + return true; +} + +/** + * Thinks and switches to hungry state if a random number is a multiple of 3. + */ +void Philosopher3D::think() { + if(rand()%3 == 0) { // 1/3 probability to go to hungry state + setState(hasNone); + setAction(doNothing); + } +} diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.h b/src/tests/DiningPhilosophers3D/Philosopher3D.h new file mode 100644 index 000000000..3de439e57 --- /dev/null +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.h @@ -0,0 +1,81 @@ +/*! + * \class Philosopher3D + * \brief Object representing a 3D philosopher in the Dining Philosophers' problem + * \details The Philosopher3D class contains variables and methods necessary for + * representing a philosopher at a table. Each Philosopher3D may acquire or release + * the fork to his left or to his right (or both), with his state changing + * accordingly. + */ + +#ifndef PHILOSOPHER3D_H_ +#define PHILOSOPHER3D_H_ + +#include +#include +#include "Fork3D.h" +#include "philEnums.h" + +class Philosopher3D { +private: + PhilState myState; + PhilAction myAction; + int id, myLeft, myRight; + unsigned int numMeals; + Cylinder *myCylinder; + Cone * myCone; +public: + Philosopher3D(); + ~Philosopher3D(); + void draw(Canvas& can, float x, float y); + void refreshColor(); + void addMeal(); + bool acquire(Fork3D& f); + bool release(Fork3D& f); + void think(); + + // Mutators + /*! + * \brief Resets the Philosopher3D to thinking after he eats. + */ + void eat() { myState = thinking; myAction = doNothing;} + /*! + * \brief Mutator for myState + * \param s PhilState to set myState to. + */ + void setState(PhilState s) { myState = s; } + /*! + * \brief Mutator for myAction + * \param s PhilAction to set myAction to. + */ + void setAction(PhilAction a) { myAction = a; } + /*! + * \brief Mutator for id + * \param i Which philosopher id to mutate + * \param nphil Total number of philosophers. + */ + void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } + + //Accessors + /** + * Accessor for number of meals Philosopher3D has consumed. + */ + int getMeals() { return numMeals; } + /** + * Accessor for Philosopher3D's state. + */ + PhilState state() { return myState; } + /** + * Accessor for Philosopher3D's action. + */ + PhilAction action() { return myAction; } + /** + * Accessor for Philosopher3D's id. + */ + int getId() { return id; } + /** + * Accessor for Philosopher3D's cylinder. + */ + bool hasCylinder() { return myCylinder; } +}; + +#endif /* PHILOSOPHER3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Table3D.cpp b/src/tests/DiningPhilosophers3D/Table3D.cpp new file mode 100644 index 000000000..c0f082de7 --- /dev/null +++ b/src/tests/DiningPhilosophers3D/Table3D.cpp @@ -0,0 +1,488 @@ +#include "Table3D.h" + +/*! + * \brief Creates a new 3D Table of dining Philosopher3Ds. + * \details Explicit constructor for a new Table3D object. + * \param can The Canvas on which the Table3D is to be drawn. + * \param p Integer denoting the number of Philosopher3Ds at the Table3D + * \param m PhilMethod denoting how the Philosopher3Ds should interact. + */ +Table3D::Table3D(Canvas& can, int p, PhilMethod m) { + numPhils = p; + myCan = &can; + myTable = new Cylinder(0,0,-2,1,2,0,0,90,ColorGLfloat(0.5,0.5,0.5,1)); + can.add(myTable); + phils = new Philosopher3D[numPhils]; + forks = new Fork3D[numPhils]; + for (int i = 0; i < numPhils; ++i) { + phils[i].setId(i,numPhils); + forks[i].id = i; + forks[i].setCanvas(myCan); + } + // float delta = 2.0f / numPhils * PI; + // for(int i = 0; i < numPhils; i++) { + // myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); + // } + myMethod = m; + switch(myMethod) { + case forfeitWhenBlocked: + methodString = "forfeit when blocked"; + break; + case waitWhenBlocked: + methodString = "wait when blocked"; + break; + case nFrameRelease: + methodString = "release on nth frame"; + break; + case resourceHierarchy: + methodString = "hierarchical resources"; + break; + case oddEven: + methodString = "odd-even check"; + break; + default: + break; + } + + // myCan2 = new Canvas(0,0,300,300,"Legend"); + // myCan2->start(); + // myCan2->drawText("Method:",16,32,32,BLACK); + // myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); + // myCan2->drawText("Legend:",16,96,24,BLACK); + // myCan2->drawText("Red: Hungry",32,128,24,RED); + // myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); + // myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); + // myCan2->drawText("Green: Eating",32,224,24,GREEN); + // myCan2->drawText("Blue: Thinking",32,256,24,BLUE); + // myCan2->drawText("Meals eaten: ",32,288,24,BROWN); + // myCan2->drawCircle(165,281,3,BROWN); +} + +/*! + * \brief Destructor for Table3D. + */ +Table3D::~Table3D() { + // if (myCan2->isOpen()) + // myCan2->stop(); + // delete myCan2; + delete myTable; + delete [] phils; + delete [] forks; +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the id numbers for the left and the right Philsopher's state. + * - Switch for the state of a Philosopher3D: + * - Philosopher3D has no fork: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Deadlock amongst threads. + */ +void Table3D::forfeitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(releaseRight); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].setState(hasNone); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch for the state of the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Livelock amongst threads. + */ +void Table3D::waitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the right fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the left fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::nFrameReleaseMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseRight); + else + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states for the left and right Philosopher3Ds. + * - Switch statement for the state of the current Philosopher3D. + * - Philosopher3D has no forks: + * - If the right Philosopher3D's id is less than the left Philsopher's id: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Else, if the left fork is free then try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the right fork: + * - If the left fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::hierarchyMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (right < left) { + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + } else { + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the Philosopher3D's id is even + * - Philosopher3D has right fork (odd id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the left fork. + * - Else, release the right fork. + * . + * - Philosopher3D has left fork (even id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the right fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This method is the one that works best. + */ +void Table3D::oddEvenMethod(int id) { + switch(phils[id].state()) { + case hasNone: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryBoth); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(releaseRight); + } + break; + case hasLeft: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + +/*! + * \brief Method for determining which method of resolution the philosopher is using. + */ +void Table3D::checkStep() { + int i = omp_get_thread_num(); + if (phils[i].state() == isFull) { + phils[i].eat(); + return; + } + switch(myMethod) { + case forfeitWhenBlocked: + forfeitWhenBlockedMethod(i); + break; + case waitWhenBlocked: + waitWhenBlockedMethod(i); + break; + case nFrameRelease: + nFrameReleaseMethod(i); + break; + case resourceHierarchy: + hierarchyMethod(i); + break; + case oddEven: + oddEvenMethod(i); + break; + default: + break; + } +} + +/*! + * \brief Method for philosopher to act based on myAction. + */ +void Table3D::actStep() { + // myCan2->sleep(); + int i = omp_get_thread_num(); + int left = i, right = (i+numPhils-1)%numPhils; + switch(phils[i].action()) { + case tryLeft: + phils[i].acquire(forks[left]); + break; + case tryRight: + phils[i].acquire(forks[right]); + break; + case tryBoth: + phils[i].acquire(forks[left]); + phils[i].acquire(forks[right]); + break; + case releaseLeft: + phils[i].release(forks[left]); + break; + case releaseRight: + phils[i].release(forks[right]); + break; + case releaseBoth: + phils[i].release(forks[left]); + phils[i].release(forks[right]); + break; + default: + break; + } +} + +/*! + * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. + */ +void Table3D::drawStep() { + const float RAD = 2.5; + float FORK_RAD = 1.4; + const float ARC =2*PI/numPhils; + const float CLOSE = 0.15f; + const float BASEDIST = RAD+64; + + int i = omp_get_thread_num(); + float pangle = (i*2*PI)/numPhils; + ColorGLfloat fcolor = ColorGLfloat(1,1,1,1); + float fangle = (i+0.5f)*ARC; + + if( !phils[i].hasCylinder() ) { + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); + } + + phils[i].refreshColor(); + if( phils[i].state() == isFull ) { + int meals = phils[i].getMeals(); + float angle = pangle+(meals/10)*2*PI/RAD, dist = BASEDIST+8*(meals%10); + // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); + phils[i].addMeal(); + } + if (forks[i].user == i) { + fangle = i*ARC + CLOSE; + fcolor = (phils[i].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(0.75,0,0.75,1); + } + else if((forks[i].user == (i+1)%numPhils)) { + fangle = ((i+1)*ARC) - CLOSE; + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); + } else { + FORK_RAD = 1.2; + fangle = pangle + PI / numPhils; + } + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); +} \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Table3D.h b/src/tests/DiningPhilosophers3D/Table3D.h new file mode 100644 index 000000000..daf857b5c --- /dev/null +++ b/src/tests/DiningPhilosophers3D/Table3D.h @@ -0,0 +1,55 @@ +/*! + * \class Table3D + * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. + * \details The Table3D class keeps track of the forks and philosophers in the Dining + * Philosophers' problem; it additionally manages the actions of the philosophers. + * \details Each step of the problem is broken up into two phases. In the checking phase, + * the philosophers look at the 3D table around them and, without communicating with the + * other philosophers, determine an action to take based on their state and the states + * of their adjacent forks. + * \details In the action phase, each philosopher attempts to execute the action previously + * determined in the checking phase. If unsuccessful, the philosopher does nothing; + * otherwise, the philosopher's state changes depending on the action taken. + */ + +#ifndef TABLE3D_H_ +#define TABLE3D_H_ + +#include +#include "Philosopher3D.h" + +using namespace tsgl; + +class Table3D { +private: + int numPhils; + PhilMethod myMethod; + std::string methodString; + Canvas *myCan/* , *myCan2 */; + Philosopher3D *phils; + Fork3D *forks; + Cylinder * myTable; + // TextureHandler loader; +public: + Table3D(Canvas& can, int p, PhilMethod m); + + ~Table3D(); + + void forfeitWhenBlockedMethod(int id); + + void waitWhenBlockedMethod(int id); + + void nFrameReleaseMethod(int id); + + void hierarchyMethod(int id); + + void oddEvenMethod(int id); + + void checkStep(); + + void actStep(); + + void drawStep(); +}; + +#endif /* TABLE3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/philEnums.h b/src/tests/DiningPhilosophers3D/philEnums.h new file mode 100644 index 000000000..17390208e --- /dev/null +++ b/src/tests/DiningPhilosophers3D/philEnums.h @@ -0,0 +1,22 @@ +#ifndef PHIL_ENUM_H_ +#define PHIL_ENUM_H_ + +/*! \brief Enum for valid states for the Dining Philosophers + */ +enum PhilState { + hasNone, hasRight, hasLeft, hasBoth, isFull, thinking +}; + +/*! \brief Enum for valid actions for the Dining Philosophers + */ +enum PhilAction { + doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth +}; + +/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem + */ +enum PhilMethod { + forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven +}; + +#endif /* PHIL_ENUM_H_ */ \ No newline at end of file diff --git a/src/tests/test3DPhilosophers.cpp b/src/tests/test3DPhilosophers.cpp new file mode 100644 index 000000000..583f33eff --- /dev/null +++ b/src/tests/test3DPhilosophers.cpp @@ -0,0 +1,107 @@ +/* + * test3DPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. + * This file includes a main method, Philospher3D class, Fork3D class, and Table3D class. + * + * The program provides a 3D visualization of the Dining Philosophers Problem + * in which philosophers sit around a table, think for a random amount of time, and then want to eat. + * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. + * This visualization includes six different ways of resolving the conflicts. + * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. + * + * Usage: ./test3DPhilosophers + * for enter: + * 'w' for waitWhenBlocked, which results in Deadlock + * 'f' for forfeitWhenBlocked, which results in Livelock + * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 + * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 + * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) + * + * for enter: + * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). + * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. + * + * If step-through is turned off, the spacebar pauses the visualization. + */ + +#include +#include +#include +#include "DiningPhilosophers3D/Table3D.h" +#include "DiningPhilosophers3D/Philosopher3D.h" + +using namespace tsgl; + +void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { + + PhilMethod method; + //switch statement to create table with resolution method + char resolutionMethod = RM[0]; + switch(resolutionMethod) { + case 'w': + method = waitWhenBlocked; //Deadlock + break; + case 'f': + method = forfeitWhenBlocked; //Livelock (when synchronized) + break; + case 'n': + method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 + break; + case 'r': + method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 + break; + case 'o': + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + default: + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + } + + Table3D t(can,philosophers,method); + + srand(time(NULL)); // seed the random number generator for thinking steps + + bool stepThrough = step; // Flag that determines whether the animation pauses between steps + bool paused = false; // Flag that determines whether the animation is paused + bool philPauses[philosophers]; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed + paused = !paused; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + }); + + #pragma omp parallel num_threads(philosophers) + { + while(can.isOpen()) { + can.sleep(); + if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { + if(stepThrough) { philPauses[omp_get_thread_num()] = true; } + t.checkStep(); + can.pauseDrawing(); + if(method == forfeitWhenBlocked || method == waitWhenBlocked) { //Synchronize to see Livelock and Deadlock + #pragma omp barrier //Barrier for optional synchronization + } + t.actStep(); + t.drawStep(); + can.resumeDrawing(); + } + } + } +} + +int main(int argc, char* argv[]) { + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./test3DPhilosophers " + << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in tests/test3DPhilosophers.cpp" << std::endl; + } + int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 + int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 + bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); + std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven + Canvas c(-1, -1, 1300, 1000, "3D Dining Philosophers",1.0f/speed); + c.run(philosopherFunction,nphil,resM,stepThrough); +} From e79f9568e0ee4694d42115c41b84ff96ea34f5a3 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 7 May 2020 00:18:45 -0400 Subject: [PATCH 025/105] Meals added to both types of philosophers --- src/tests/DiningPhilosophers/Philosopher.cpp | 15 +++++++++++++-- src/tests/DiningPhilosophers/Philosopher.h | 4 +++- src/tests/DiningPhilosophers/Table.cpp | 15 ++++++++------- src/tests/DiningPhilosophers3D/Philosopher3D.cpp | 15 +++++++++++++-- src/tests/DiningPhilosophers3D/Philosopher3D.h | 4 +++- src/tests/DiningPhilosophers3D/Table3D.cpp | 15 ++++++++------- 6 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp index f57b73108..e2009a44c 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/tests/DiningPhilosophers/Philosopher.cpp @@ -14,13 +14,18 @@ Philosopher::Philosopher() { Philosopher::~Philosopher() { delete myCircle; + for (RegularPolygon * meal : meals) + { + delete meal; + } + meals.clear(); } /** * Adds Philosopher to Canvas or refreshes its color. */ void Philosopher::draw(Canvas& can, float x, float y) { - const float SIZE = .5; + const float SIZE = .45; if( !myCircle) { myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorGLfloat(1,0,0,1)); can.add(myCircle); @@ -46,8 +51,14 @@ void Philosopher::refreshColor() { /** * Adds a meal representation to meals and the Canvas */ -void Philosopher::addMeal() { +void Philosopher::addMeal(float x, float y, float z) { numMeals++; + meals.push_back(new RegularPolygon(x,y,z,.03,3,0,0,0,ColorGLfloat(0.5,0.3,0,1))); + meals.back()->displayOutlineEdges(false); +} + +RegularPolygon * Philosopher::getLastMeal() { + return meals.back(); } /** diff --git a/src/tests/DiningPhilosophers/Philosopher.h b/src/tests/DiningPhilosophers/Philosopher.h index bf27a1b59..222a4b97e 100644 --- a/src/tests/DiningPhilosophers/Philosopher.h +++ b/src/tests/DiningPhilosophers/Philosopher.h @@ -22,12 +22,14 @@ class Philosopher { int id, myLeft, myRight; unsigned int numMeals; Circle *myCircle; + std::vector meals; public: Philosopher(); ~Philosopher(); void draw(Canvas& can, float x, float y); void refreshColor(); - void addMeal(); + void addMeal(float x, float y, float z); + RegularPolygon * getLastMeal(); bool acquire(Fork& f); bool release(Fork& f); void think(); diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index bd49b2212..33efd32b4 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -10,7 +10,7 @@ Table::Table(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Circle(0,0,-1,2.2,0,0,0,ColorGLfloat(0.5,0.5,0.5,1)); + myTable = new Circle(0,0,-1,1.5,0,0,0,ColorGLfloat(0.5,0.5,0.5,1)); can.add(myTable); // can.drawCircle(0,0,1,ColorGLfloat(0.5,0.5,0.5,1)); phils = new Philosopher[numPhils]; @@ -452,11 +452,11 @@ void Table::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table::drawStep() { - const float RAD = 2.4; - float FORK_RAD = 2; + const float RAD = 1.8; + float FORK_RAD = 1.3; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; - const float BASEDIST = RAD+64; + const float BASEDIST = RAD+.54; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; @@ -470,9 +470,10 @@ void Table::drawStep() { phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/RAD, dist = BASEDIST+8*(meals%10); + float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+.08*(meals%10); // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); - phils[i].addMeal(); + phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); + myCan->add(phils[i].getLastMeal()); } if (forks[i].user == i) { fangle = i*ARC + CLOSE; @@ -482,7 +483,7 @@ void Table::drawStep() { fangle = ((i+1)*ARC) - CLOSE; fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); } else { - FORK_RAD = 1.8; + FORK_RAD = 1; fangle = pangle + PI / numPhils; } forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp index f749d7245..7e0a58432 100644 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp @@ -16,13 +16,18 @@ Philosopher3D::Philosopher3D() { Philosopher3D::~Philosopher3D() { delete myCylinder; delete myCone; + for (Pyramid * meal : meals) + { + delete meal; + } + meals.clear(); } /** * Adds Philosopher3D to Canvas or refreshes its color. */ void Philosopher3D::draw(Canvas& can, float x, float y) { - const float SIZE = .5; + const float SIZE = .45; if( !myCylinder) { myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,ColorGLfloat(1,0,0,1)); can.add(myCylinder); @@ -54,8 +59,14 @@ void Philosopher3D::refreshColor() { /** * Adds a meal representation to meals and the Canvas */ -void Philosopher3D::addMeal() { +void Philosopher3D::addMeal(float x, float y, float z) { numMeals++; + meals.push_back(new Pyramid(x,y,z,3,.08,.04,0,0,90,ColorGLfloat(0.5,0.3,0,1))); + meals.back()->displayOutlineEdges(false); +} + +Pyramid * Philosopher3D::getLastMeal() { + return meals.back(); } /** diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.h b/src/tests/DiningPhilosophers3D/Philosopher3D.h index 3de439e57..0781393c4 100644 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.h +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.h @@ -23,12 +23,14 @@ class Philosopher3D { unsigned int numMeals; Cylinder *myCylinder; Cone * myCone; + std::vector meals; public: Philosopher3D(); ~Philosopher3D(); void draw(Canvas& can, float x, float y); void refreshColor(); - void addMeal(); + void addMeal(float x, float y, float z); + Pyramid * getLastMeal(); bool acquire(Fork3D& f); bool release(Fork3D& f); void think(); diff --git a/src/tests/DiningPhilosophers3D/Table3D.cpp b/src/tests/DiningPhilosophers3D/Table3D.cpp index c0f082de7..63c09445d 100644 --- a/src/tests/DiningPhilosophers3D/Table3D.cpp +++ b/src/tests/DiningPhilosophers3D/Table3D.cpp @@ -10,7 +10,7 @@ Table3D::Table3D(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Cylinder(0,0,-2,1,2,0,0,90,ColorGLfloat(0.5,0.5,0.5,1)); + myTable = new Cylinder(0,0,-2,1,1.5,0,0,90,ColorGLfloat(0.5,0.5,0.5,1)); can.add(myTable); phils = new Philosopher3D[numPhils]; forks = new Fork3D[numPhils]; @@ -451,11 +451,11 @@ void Table3D::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table3D::drawStep() { - const float RAD = 2.5; - float FORK_RAD = 1.4; + const float RAD = 1.95; + float FORK_RAD = 1; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; - const float BASEDIST = RAD+64; + const float BASEDIST = RAD+.58; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; @@ -469,9 +469,10 @@ void Table3D::drawStep() { phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/RAD, dist = BASEDIST+8*(meals%10); + float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+.08*(meals%10); // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); - phils[i].addMeal(); + phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); + myCan->add(phils[i].getLastMeal()); } if (forks[i].user == i) { fangle = i*ARC + CLOSE; @@ -481,7 +482,7 @@ void Table3D::drawStep() { fangle = ((i+1)*ARC) - CLOSE; fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); } else { - FORK_RAD = 1.2; + FORK_RAD = 0.9; fangle = pangle + PI / numPhils; } forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); From d908817042c83a961bde04690b7bf171f659e5cf Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 7 May 2020 02:38:12 -0400 Subject: [PATCH 026/105] Pyramid advantages example + Triangle improved --- Makefile | 1 + src/TSGL/Triangle.cpp | 18 +++++--- src/tests/test2Dvs3D.cpp | 98 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 src/tests/test2Dvs3D.cpp diff --git a/Makefile b/Makefile index ccb4c1e88..6818acd97 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ LFLAGS=-Llib/ \ DEPFLAGS=-MMD -MP BINARIES= \ + bin/test2Dvs3D \ bin/test3DRotation \ bin/testArrows \ bin/testBallroom \ diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index a00cca242..2f8bf90c2 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -21,9 +21,12 @@ namespace tsgl { * \return A new Triangle with the specified vertices and color. */ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { - addVertex(x1, y1, z1, color); - addVertex(x2, y2, z2, color); - addVertex(x3, y3, z3, color); + float xAverage = (x1 + x2 + x3) / 3; + float yAverage = (y1 + y2 + y3) / 3; + float zAverage = (z1 + z2 + z3) / 3; + addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color); + addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color); + addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color); } /*! @@ -45,8 +48,11 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f * \return A new Triangle with the specified vertices and color. */ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3, (z1 + z2 + z3) / 3, 3,yaw,pitch,roll) { - addVertex(x1, y1, z1, color[0]); - addVertex(x2, y2, z2, color[1]); - addVertex(x3, y3, z3, color[2]); + float xAverage = (x1 + x2 + x3) / 3; + float yAverage = (y1 + y2 + y3) / 3; + float zAverage = (z1 + z2 + z3) / 3; + addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color[0]); + addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color[1]); + addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color[2]); } } diff --git a/src/tests/test2Dvs3D.cpp b/src/tests/test2Dvs3D.cpp new file mode 100644 index 000000000..51b244edc --- /dev/null +++ b/src/tests/test2Dvs3D.cpp @@ -0,0 +1,98 @@ +/* + * test2Dvs3D.cpp + * + * Usage: ./test2Dvs3D + */ + +#include +#include + +using namespace tsgl; + +void contrastFunction(Canvas& can) { + ColorGLfloat pyramidcolors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), + ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), + ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), + ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), + ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; + ColorGLfloat triangle2Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,1,1,1), ColorGLfloat(0,1,0,1) }; + ColorGLfloat triangle3Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(1,0,1,1), ColorGLfloat(1,0,0,1) }; + ColorGLfloat triangle6Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1) }; + Pyramid * testPyramid = new Pyramid(-2.0, 0.0, -1.0, 4, 2, 2, 0.0, 0.0, 45.0, pyramidcolors); + // can.add(testPyramid); + Triangle * triangle1 = new Triangle(1.39,0.66,0,3.5,-0.52,0,1.62,-2,0,0,0,0,pyramidcolors); + // can.add(triangle1); + Triangle * triangle2 = new Triangle(1.39,0.66,0,0.49,-0.52,0,1.62,-2,0,0,0,0,triangle2Colors); + // can.add(triangle2); + Triangle * triangle3 = new Triangle(1.39,0.66,0,3.5,-0.52,0,2.27,0.40,0,0,0,0,triangle3Colors); + // can.add(triangle3); + Triangle * triangle4 = new Triangle(2.65,0.64,0,3.31,-0.44,0,2.63,-1.94,0,0,0,0,pyramidcolors); + // can.add(triangle4); + Triangle * triangle5 = new Triangle(2.65,0.64,0,0.16,-0.7,0,2.63,-1.94,0,0,0,0,triangle2Colors); + // can.add(triangle5); + Triangle * triangle6 = new Triangle(2.65,0.64,0,0.16,-0.7,0,1.66,0.47,0,0,0,0,triangle6Colors); + // can.add(triangle6); + // testPyramid->setPitch(45); + int stepsTaken = 0; + while (can.isOpen()) { + can.sleep(); + if (can.getFrameNumber() >= 1000 && stepsTaken < 1) { + can.add(triangle1); + stepsTaken++; + } + if (can.getFrameNumber() >= 1200 && stepsTaken < 2) { + can.add(triangle2); + stepsTaken++; + } + if (can.getFrameNumber() >= 1400 && stepsTaken < 3) { + can.add(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 2000 && stepsTaken < 4) { + can.add(testPyramid); + stepsTaken++; + } + if (can.getFrameNumber() >= 3000 && stepsTaken < 5) { + can.remove(triangle1); + can.remove(triangle2); + can.remove(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 3400 && stepsTaken < 6) { + can.add(triangle4); + stepsTaken++; + } + if (can.getFrameNumber() >= 3600 && stepsTaken < 7) { + can.add(triangle5); + stepsTaken++; + } + if (can.getFrameNumber() >= 3800 && stepsTaken < 8) { + can.add(triangle6); + stepsTaken++; + } + if (can.getFrameNumber() >= 5000 && stepsTaken < 9) { + if (testPyramid->getPitch() < 45) { + testPyramid->changePitchBy(0.5); + } else { + testPyramid->setPitch(45); + stepsTaken++; + } + } + printf("%d\n", can.getFrameNumber()); + } + + delete testPyramid; + delete triangle1; + delete triangle2; + delete triangle3; + delete triangle4; + delete triangle5; + delete triangle6; + +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing"); + c.setBackgroundColor(BLACK); + c.run(contrastFunction); +} \ No newline at end of file From e3e0c602a93745b4867b0af9fd17e93bc8be9639 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 1 Jun 2020 10:19:12 -0400 Subject: [PATCH 027/105] Final project presentation examples Just updating timing to fit the presentation, more or less --- Makefile | 2 +- src/tests/test2Dvs3D.cpp | 19 +++--- src/tests/testDiorama.cpp | 126 +++++++++++++++++++++++++++++++++++++ src/tests/testPanorama.cpp | 95 ---------------------------- 4 files changed, 136 insertions(+), 106 deletions(-) create mode 100644 src/tests/testDiorama.cpp delete mode 100644 src/tests/testPanorama.cpp diff --git a/Makefile b/Makefile index 6818acd97..fdba3f0b4 100644 --- a/Makefile +++ b/Makefile @@ -77,10 +77,10 @@ BINARIES= \ bin/testCube \ bin/testCuboid \ bin/testCylinder \ + bin/testDiorama \ bin/testEllipse \ bin/testEllipsoid \ bin/testLines \ - bin/testPanorama \ bin/testPhilosophers \ bin/test3DPhilosophers \ bin/testPrism \ diff --git a/src/tests/test2Dvs3D.cpp b/src/tests/test2Dvs3D.cpp index 51b244edc..668880755 100644 --- a/src/tests/test2Dvs3D.cpp +++ b/src/tests/test2Dvs3D.cpp @@ -36,41 +36,41 @@ void contrastFunction(Canvas& can) { int stepsTaken = 0; while (can.isOpen()) { can.sleep(); - if (can.getFrameNumber() >= 1000 && stepsTaken < 1) { + if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { can.add(triangle1); stepsTaken++; } - if (can.getFrameNumber() >= 1200 && stepsTaken < 2) { + if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { can.add(triangle2); stepsTaken++; } - if (can.getFrameNumber() >= 1400 && stepsTaken < 3) { + if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { can.add(triangle3); stepsTaken++; } - if (can.getFrameNumber() >= 2000 && stepsTaken < 4) { + if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { can.add(testPyramid); stepsTaken++; } - if (can.getFrameNumber() >= 3000 && stepsTaken < 5) { + if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { can.remove(triangle1); can.remove(triangle2); can.remove(triangle3); stepsTaken++; } - if (can.getFrameNumber() >= 3400 && stepsTaken < 6) { + if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { can.add(triangle4); stepsTaken++; } - if (can.getFrameNumber() >= 3600 && stepsTaken < 7) { + if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { can.add(triangle5); stepsTaken++; } - if (can.getFrameNumber() >= 3800 && stepsTaken < 8) { + if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { can.add(triangle6); stepsTaken++; } - if (can.getFrameNumber() >= 5000 && stepsTaken < 9) { + if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { if (testPyramid->getPitch() < 45) { testPyramid->changePitchBy(0.5); } else { @@ -78,7 +78,6 @@ void contrastFunction(Canvas& can) { stepsTaken++; } } - printf("%d\n", can.getFrameNumber()); } delete testPyramid; diff --git a/src/tests/testDiorama.cpp b/src/tests/testDiorama.cpp new file mode 100644 index 000000000..45e0179c9 --- /dev/null +++ b/src/tests/testDiorama.cpp @@ -0,0 +1,126 @@ +/* + * testDiorama.cpp + * + * Usage: ./testDiorama + */ + +#include +#include + +using namespace tsgl; + +void dioramaFunction(Canvas& can) { + Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,ColorGLfloat(1,1,1,1)); + blankCanvas->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + // can.add(blankCanvas); + + Rectangle * emptyDioramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); + emptyDioramaLeft->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + // can.add(emptyDioramaLeft); + Rectangle * emptyDioramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); + emptyDioramaRight->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + // can.add(emptyDioramaRight); + Rectangle * emptyDioramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); + emptyDioramaTop->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + // can.add(emptyDioramaTop); + Rectangle * emptyDioramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); + emptyDioramaBottom->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + // can.add(emptyDioramaBottom); + + Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorGLfloat(.6,.3,0,1)); + trunk->displayOutlineEdges(false); + // can.add(trunk); + + Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,ColorGLfloat(0,1,0,1)); + // can.add(leaves); + + Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorGLfloat(.6,.3,0,1)); + trunkFlat->displayOutlineEdges(false); + // can.add(trunkFlat); + + Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorGLfloat(0,0.8,0,1)); + // can.add(leavesFlat); + + float counter = 0; + while (can.isOpen()) { + // can.sleepFor(0.5); + can.sleep(); + if (can.getFrameNumber() > 700 && counter < 1) { + can.add(blankCanvas); + counter++; + } + if(can.getFrameNumber() > 1700 && counter < 2) { + can.add(trunkFlat); + counter++; + } + if(can.getFrameNumber() > 1800 && counter < 3) { + can.add(leavesFlat); + counter++; + } + if(can.getFrameNumber() > 2300 && counter < 4) { + can.add(emptyDioramaLeft); + can.add(emptyDioramaRight); + can.add(emptyDioramaTop); + can.add(emptyDioramaBottom); + counter++; + } + if(can.getFrameNumber() > 3500 && counter < 5) { + can.add(trunk); + counter++; + } + if(can.getFrameNumber() > 3600 && counter < 6) { + can.add(leaves); + counter++; + } + if(can.getFrameNumber() > 4000 && counter < 7) { + if(emptyDioramaLeft->getWidth() > .15) { + emptyDioramaLeft->changeWidthBy(-2.7/20); + emptyDioramaRight->changeWidthBy(-2.7/20); + emptyDioramaTop->changeHeightBy(-2.7/20); + emptyDioramaBottom->changeHeightBy(-2.7/20); + emptyDioramaTop->changeZBy(1.35/20); + emptyDioramaBottom->changeZBy(1.35/20); + emptyDioramaLeft->changeZBy(1.35/20); + emptyDioramaRight->changeZBy(1.35/20); + trunk->changeLengthBy(-0.25/20); + trunk->changeZBy(1.35/20); + leaves->changeZRadiusBy(-0.4/20); + leaves->changeZBy(1.35/20); + } else { + emptyDioramaLeft->setWidth(0.01); + emptyDioramaRight->setWidth(0.01); + emptyDioramaTop->setHeight(0.01); + emptyDioramaBottom->setHeight(0.01); + emptyDioramaTop->setCenterZ(1.35); + emptyDioramaBottom->setCenterZ(1.35); + emptyDioramaLeft->setCenterZ(1.35); + emptyDioramaRight->setCenterZ(1.35); + trunk->setLength(0.01); + trunk->setCenterZ(1.35); + leaves->setZRadius(0.01); + leaves->setCenterZ(1.35); + counter++; + } + } + } + + delete blankCanvas; + delete emptyDioramaLeft; + delete emptyDioramaRight; + delete emptyDioramaTop; + delete emptyDioramaBottom; + delete leaves; + delete trunkFlat; + delete leavesFlat; + +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting"); + c.setBackgroundColor(WHITE); + c.run(dioramaFunction); +} \ No newline at end of file diff --git a/src/tests/testPanorama.cpp b/src/tests/testPanorama.cpp deleted file mode 100644 index 2b6c44852..000000000 --- a/src/tests/testPanorama.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * testPanorama.cpp - * - * Usage: ./testPanorama - */ - -#include -#include - -using namespace tsgl; - -void panoramaFunction(Canvas& can) { - Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,ColorGLfloat(1,1,1,1)); - blankCanvas->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); - can.add(blankCanvas); - - Rectangle * emptyPanoramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); - emptyPanoramaLeft->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); - can.add(emptyPanoramaLeft); - Rectangle * emptyPanoramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); - emptyPanoramaRight->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); - can.add(emptyPanoramaRight); - Rectangle * emptyPanoramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); - emptyPanoramaTop->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); - can.add(emptyPanoramaTop); - Rectangle * emptyPanoramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); - emptyPanoramaBottom->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); - can.add(emptyPanoramaBottom); - - Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorGLfloat(.6,.3,0,1)); - trunk->displayOutlineEdges(false); - can.add(trunk); - - Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,ColorGLfloat(0,1,0,1)); - can.add(leaves); - - Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorGLfloat(.6,.3,0,1)); - trunkFlat->displayOutlineEdges(false); - can.add(trunkFlat); - - Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorGLfloat(0,0.8,0,1)); - can.add(leavesFlat); - - float counter = 1; - while (can.isOpen()) { - // can.sleepFor(0.5); - can.sleep(); - if (counter < 10) { - emptyPanoramaLeft->setWidth(2.7/(counter*4)); - emptyPanoramaRight->setWidth(2.7/(counter*4)); - emptyPanoramaTop->setHeight(2.7/(counter*4)); - emptyPanoramaBottom->setHeight(2.7/(counter*4)); - emptyPanoramaTop->setCenterZ(1.35-1.35/counter); - emptyPanoramaBottom->setCenterZ(1.35-1.35/counter); - emptyPanoramaLeft->setCenterZ(1.35-1.35/counter); - emptyPanoramaRight->setCenterZ(1.35-1.35/counter); - trunk->setLength(0.25/counter); - trunk->setCenterZ(1.35-1.35/counter); - leaves->setZRadius(0.4/counter); - leaves->setCenterZ(1.35-1.35/counter); - counter += 0.05; - } else { - emptyPanoramaLeft->setWidth(0.01); - emptyPanoramaRight->setWidth(0.01); - emptyPanoramaTop->setHeight(0.01); - emptyPanoramaBottom->setHeight(0.01); - emptyPanoramaTop->setCenterZ(1.35); - emptyPanoramaBottom->setCenterZ(1.35); - emptyPanoramaLeft->setCenterZ(1.35); - emptyPanoramaRight->setCenterZ(1.35); - trunk->setLength(0.25/counter); - trunk->setCenterZ(1.35-1.35/counter); - leaves->setZRadius(0.4/counter); - leaves->setCenterZ(1.35-1.35/counter); - } - // printf("%f\n", counter); - } - - delete blankCanvas; - delete emptyPanoramaLeft; - delete emptyPanoramaRight; - delete emptyPanoramaTop; - delete emptyPanoramaBottom; - -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Panorama vs. Painting"); - c.setBackgroundColor(WHITE); - c.run(panoramaFunction); -} \ No newline at end of file From fd01ac91533fa19f2bfd098946f6d13494a5aad3 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 2 Jun 2020 10:51:05 -0400 Subject: [PATCH 028/105] Philosophers, Sorting, ColorGLfloat Implemented Rani Hod's fix for testPhilosophers. More or less fixed both shaker (dumb) and merge (smart) sort. Swapped ColorGLfloat for ColorFloat to fix when I unnecessarily added ColorGLfloat months ago. --- Makefile | 6 +- src/TSGL/Arrow.cpp | 14 +- src/TSGL/Arrow.h | 8 +- src/TSGL/Canvas.cpp | 52 ++--- src/TSGL/Circle.cpp | 4 +- src/TSGL/Circle.h | 4 +- src/TSGL/Color.cpp | 169 +------------- src/TSGL/Color.h | 39 +--- src/TSGL/ConcavePolygon.cpp | 6 +- src/TSGL/ConcavePolygon.h | 8 +- src/TSGL/Cone.cpp | 4 +- src/TSGL/Cone.h | 4 +- src/TSGL/ConvexPolygon.cpp | 4 +- src/TSGL/ConvexPolygon.h | 4 +- src/TSGL/Cube.cpp | 14 +- src/TSGL/Cube.h | 8 +- src/TSGL/Cuboid.cpp | 14 +- src/TSGL/Cuboid.h | 8 +- src/TSGL/Cylinder.cpp | 8 +- src/TSGL/Cylinder.h | 4 +- src/TSGL/Drawable.cpp | 10 +- src/TSGL/Drawable.h | 10 +- src/TSGL/Ellipse.cpp | 4 +- src/TSGL/Ellipse.h | 4 +- src/TSGL/Ellipsoid.cpp | 22 +- src/TSGL/Ellipsoid.h | 8 +- src/TSGL/Line.cpp | 4 +- src/TSGL/Line.h | 4 +- src/TSGL/Polyline.cpp | 8 +- src/TSGL/Polyline.h | 4 +- src/TSGL/Prism.cpp | 14 +- src/TSGL/Prism.h | 8 +- src/TSGL/Pyramid.cpp | 14 +- src/TSGL/Pyramid.h | 8 +- src/TSGL/Rectangle.cpp | 12 +- src/TSGL/Rectangle.h | 4 +- src/TSGL/RegularPolygon.cpp | 4 +- src/TSGL/RegularPolygon.h | 4 +- src/TSGL/Shape.cpp | 8 +- src/TSGL/Shape.h | 4 +- src/TSGL/Sphere.cpp | 24 +- src/TSGL/Sphere.h | 8 +- src/TSGL/Square.cpp | 4 +- src/TSGL/Square.h | 4 +- src/TSGL/Star.cpp | 4 +- src/TSGL/Star.h | 4 +- src/TSGL/Triangle.cpp | 4 +- src/TSGL/Triangle.h | 4 +- src/TSGL/TriangleStrip.cpp | 4 +- src/TSGL/TriangleStrip.h | 4 +- src/TSGL/Util.h | 26 +++ src/tests/DiningPhilosophers/Fork.h | 4 +- src/tests/DiningPhilosophers/Philosopher.cpp | 22 +- src/tests/DiningPhilosophers/Table.cpp | 10 +- src/tests/DiningPhilosophers3D/Fork3D.h | 4 +- .../DiningPhilosophers3D/Philosopher3D.cpp | 26 +-- src/tests/DiningPhilosophers3D/Table3D.cpp | 8 +- src/tests/test2Dvs3D.cpp | 16 +- src/tests/test3DPhilosophers.cpp | 2 +- src/tests/test3DRotation.cpp | 16 +- src/tests/testArrows.cpp | 4 +- src/tests/testBallroom.cpp | 19 +- src/tests/testCircle.cpp | 28 +-- src/tests/testClock.cpp | 22 +- src/tests/testConcavePolygon.cpp | 6 +- src/tests/testCone.cpp | 26 +-- src/tests/testConvexPolygon.cpp | 22 +- src/tests/testCube.cpp | 10 +- src/tests/testCuboid.cpp | 10 +- src/tests/testCylinder.cpp | 14 +- src/tests/testDice.cpp | 44 ++-- src/tests/testDiorama.cpp | 28 +-- src/tests/testDumbSort.cpp | 103 --------- src/tests/testEllipse.cpp | 30 +-- src/tests/testEllipsoid.cpp | 20 +- src/tests/testLines.cpp | 16 +- src/tests/testMergeSort.cpp | 209 ++++++++++++++++++ src/tests/testPhilosophers.cpp | 2 +- src/tests/testPrism.cpp | 16 +- src/tests/testPyramid.cpp | 14 +- src/tests/testRectangle.cpp | 24 +- src/tests/testRegularPolygon.cpp | 22 +- src/tests/testShakerSort.cpp | 120 ++++++++++ src/tests/testSmartSort.cpp | 195 ---------------- src/tests/testSolarSystem.cpp | 20 +- src/tests/testSphere.cpp | 18 +- src/tests/testSquare.cpp | 22 +- src/tests/testStar.cpp | 14 +- src/tests/testTriangle.cpp | 22 +- src/tests/testTriangleStrip.cpp | 22 +- 90 files changed, 862 insertions(+), 998 deletions(-) delete mode 100644 src/tests/testDumbSort.cpp create mode 100644 src/tests/testMergeSort.cpp create mode 100644 src/tests/testShakerSort.cpp delete mode 100644 src/tests/testSmartSort.cpp diff --git a/Makefile b/Makefile index fdba3f0b4..9480c60b1 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ DEPFLAGS=-MMD -MP BINARIES= \ bin/test2Dvs3D \ bin/test3DRotation \ + bin/test3DPhilosophers \ bin/testArrows \ bin/testBallroom \ bin/testCircle \ @@ -81,12 +82,13 @@ BINARIES= \ bin/testEllipse \ bin/testEllipsoid \ bin/testLines \ + bin/testMergeSort \ bin/testPhilosophers \ - bin/test3DPhilosophers \ bin/testPrism \ bin/testPyramid \ bin/testRectangle \ bin/testRegularPolygon \ + bin/testShakerSort \ bin/testSolarSystem \ bin/testSphere \ bin/testSquare \ @@ -106,7 +108,6 @@ BINARIES= \ # bin/testConway \ # bin/testCosineIntegral \ # bin/testDice \ -# bin/testDumbSort \ # bin/testFireworks \ # bin/testForestFire \ # bin/testFunction \ @@ -132,7 +133,6 @@ BINARIES= \ # bin/testRotation \ # bin/testScreenshot \ # bin/testSeaUrchin \ -# bin/testSmartSort \ # bin/testSpectrogram \ # bin/testSpectrum \ # bin/testStar \ diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index e2e148261..d9ad02688 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -12,11 +12,11 @@ namespace tsgl { * \param yaw The yaw of the arrow. * \param pitch The pitch of the arrow. * \param roll The roll of the arrow. - * \param color A ColorGLfloats for the color of the Arrow. + * \param color A ColorFloat for the color of the Arrow. * \return A new Arrow with the specified length and color. * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. */ -Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { if (width <= 0 || length <= 0) { TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); return; @@ -56,11 +56,11 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw * \param yaw The yaw of the arrow. * \param pitch The pitch of the arrow. * \param roll The roll of the arrow. - * \param color An array of ColorGLfloats for the colors of the Arrow. + * \param color An array of ColorFloats for the colors of the Arrow. * \return A new Arrow with the specified length and color. * \note At 0,0,0 yaw,pitch,roll, the arrow will be drawn directly parallel to the x-axis as a plane perpindicular to the z-axis. */ -Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { +Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow) : ConcavePolygon(x, y, z, (doubleArrow)? 10 : 7, yaw, pitch, roll) { if (width <= 0 || length <= 0) { TsglDebug("Cannot have an Arrow with length or width less than or equal to 0."); return; @@ -136,10 +136,10 @@ void Arrow::changeWidthBy(GLfloat delta) { /** * \brief Sets the Arrow to a new color. - * \param c The new array of ColorGLfloats. - * \note Overrides Shape::setColor(ColorGLfloat c[]). + * \param c The new array of ColorFloats. + * \note Overrides Shape::setColor(ColorFloat c[]). */ -void Arrow::setColor(ColorGLfloat c[]) { +void Arrow::setColor(ColorFloat c[]) { for(int i = 0; i < 7; i++) { colors[i*4] = c[i/5].R; colors[i*4 + 1] = c[i/5].G; diff --git a/src/TSGL/Arrow.h b/src/TSGL/Arrow.h index 62f22a3ab..a8081ce74 100644 --- a/src/TSGL/Arrow.h +++ b/src/TSGL/Arrow.h @@ -19,9 +19,9 @@ class Arrow : public ConcavePolygon { GLfloat myLength, myWidth; public: - Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color, bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false); - Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorGLfloat color[], bool doubleArrow = false); + Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false); void setLength(GLfloat length); @@ -35,9 +35,9 @@ class Arrow : public ConcavePolygon { GLfloat getWidth() { return myWidth; } - void setColor(ColorGLfloat c) { Shape::setColor(c); } + void setColor(ColorFloat c) { Shape::setColor(c); } - void setColor(ColorGLfloat c[]); + void setColor(ColorFloat c[]); }; } diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 388487eb9..cde9f4e37 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2328,17 +2328,17 @@ void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, * \see resumeDrawing() */ void Canvas::pauseDrawing() { - // #pragma omp critical (pauseResume) - // { - // if (syncMutexLocked == 0 && syncMutexOwner == -1) { - // syncMutex.lock(); - // syncMutexOwner = omp_get_thread_num(); - // } - // #pragma omp critical (syncMutLock) - // { - // ++syncMutexLocked; - // } - // } + #pragma omp critical (pauseResume) + { + if (syncMutexLocked == 0 && syncMutexOwner == -1) { + syncMutex.lock(); + syncMutexOwner = omp_get_thread_num(); + } + #pragma omp critical (syncMutLock) + { + ++syncMutexLocked; + } + } } /*! @@ -2373,21 +2373,21 @@ void Canvas::reset() { * \see pauseDrawing() */ void Canvas::resumeDrawing() { - // #pragma omp critical (syncMutLock) - // { - // --syncMutexLocked; - // } - // #pragma omp critical (pauseResume) - // { - // if (syncMutexOwner == omp_get_thread_num()) { - // while (syncMutexLocked > 0) - // sleepFor(FRAME/2); - // syncMutex.unlock(); - // syncMutexOwner = -1; - // } - // } - // while (syncMutexOwner != -1) - // sleepFor(FRAME/2); + #pragma omp critical (syncMutLock) + { + --syncMutexLocked; + } + #pragma omp critical (pauseResume) + { + if (syncMutexOwner == omp_get_thread_num()) { + while (syncMutexLocked > 0) + sleepFor(FRAME/2); + syncMutex.unlock(); + syncMutexOwner = -1; + } + } + while (syncMutexOwner != -1) + sleepFor(FRAME/2); } /*! diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 19070a64f..1c4772567 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -12,7 +12,7 @@ namespace tsgl { * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; @@ -33,7 +33,7 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index 98a809267..ec9548f54 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -17,9 +17,9 @@ class Circle : public ConvexPolygon { protected: GLfloat myRadius; public: - Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color); + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color); - Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat color[]); + Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]); void setRadius(GLfloat radius); diff --git a/src/TSGL/Color.cpp b/src/TSGL/Color.cpp index edd21d3aa..8f281f492 100644 --- a/src/TSGL/Color.cpp +++ b/src/TSGL/Color.cpp @@ -102,7 +102,7 @@ ColorFloat::ColorFloat() { * \return A ColorFloat struct with equal R, G, and B values set to v, * and the specified A value. */ -ColorFloat::ColorFloat(float v, float a) { +ColorFloat::ColorFloat(GLfloat v, GLfloat a) { if (clamp(v,0,1)) TsglDebug("Out of range parameter specified for ColorFloat"); R = v; G = v; B = v; A = a; @@ -119,7 +119,7 @@ ColorFloat::ColorFloat(float v, float a) { * is out of the range 0 - 1 inclusive then an error message is given. * \return A ColorFloat struct with the specified R, G, B, and A values. */ -ColorFloat::ColorFloat(float r, float g, float b, float a) { +ColorFloat::ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { bool oor = false; oor |= clamp(r,0,1); oor |= clamp(g,0,1); @@ -475,171 +475,6 @@ ColorHSV::operator ColorInt() { return (ColorInt)((ColorFloat)(*this)); } - -/*! - * \brief Default ColorFloat constructor method. - * \details This is the default constructor for the ColorFloat struct. - * \note R, G, B, and A are all set to 1.0f by default. - * \return A ColorFloat struct with default R, G, B, and A values. - */ -ColorGLfloat::ColorGLfloat() { - R = G = B = A = 1; -} - -/*! - * \brief Basic explicit ColorFloat constructor method. - * \details This is the basic explicit constructor for the ColorFloat struct. - * \param v The value component of the color. - * \param a The alpha component of the struct (set to 1.0f by default). - * \warning An invariant is set where if any of the specified R, G, B, or A values - * is out of the range 0 - 1 inclusive then an error message is given. - * \return A ColorFloat struct with equal R, G, and B values set to v, - * and the specified A value. - */ -ColorGLfloat::ColorGLfloat(GLfloat v, GLfloat a) { - if (clamp(v,0,1)) - TsglDebug("Out of range parameter specified for ColorFloat"); - R = v; G = v; B = v; A = a; -} - -/*! - * \brief Full explicit ColorFloat constructor method. - * \details This is the full explicit constructor for the ColorFloat struct. - * \param r The red component of the struct. - * \param g The green component of the struct. - * \param b The blue component of the struct. - * \param a The alpha component of the struct (set to 1.0f by default). - * \warning An invariant is set where if any of the specified R, G, B, or A values - * is out of the range 0 - 1 inclusive then an error message is given. - * \return A ColorFloat struct with the specified R, G, B, and A values. - */ -ColorGLfloat::ColorGLfloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - bool oor = false; - oor |= clamp(r,0,1); - oor |= clamp(g,0,1); - oor |= clamp(b,0,1); - oor |= clamp(a,0,1); - if (oor) - TsglDebug("Out of range parameter specified for ColorFloat"); - R = r; G = g; B = b; A = a; -} - -/*! - * \brief Returns a string representation of the ColorFloat. - * \details This function returns a std::string representation of the ColorFloat. - * \return A string representation of the ColorFloat. - */ -std::string ColorGLfloat::asString() { - std::stringstream ss; - ss << R << "R," << G << "G," << B << "B," << A << "A"; - return ss.str(); -} - -//From http://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both -/*! - * \brief Implicit conversion from ColorFloat to ColorHSV. - * \details This defines the implicit conversion operator from a floating point color type (ColorFloat) to an - * HSV color type (ColorHSV). - */ -ColorGLfloat::operator ColorHSV() { - ColorHSV out; - double min, max, delta; - - min = R < G ? R : G; - min = min < B ? min : B; - - max = R > G ? R : G; - max = max > B ? max : B; - - out.V = max; // v - delta = max - min; - if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash - out.S = (delta / max); // s - } else { - // if max is 0, then r = g = b = 0 - // s = 0, v is undefined - out.S = 0.0; - out.H = NAN; // its now undefined - return out; - } - if( R >= max ) // > is bogus, just keeps compilor happy - out.H = ( G - B ) / delta; // between yellow & magenta - else - if( G >= max ) - out.H = 2.0 + ( B - R ) / delta; // between cyan & yellow - else - out.H = 4.0 + ( R - G ) / delta; // between magenta & cyan - - if( out.H < 0.0 ) - out.H += 6.0; - - return out; -} - -/*! - * \brief Implicit conversion from ColorFloat to ColorInt. - * \details This defines the implicit conversion operator from a floating point color type (ColorFloat) to an - * integer color type (ColorInt). - */ -ColorGLfloat::operator ColorInt() { - return ColorInt(R*MAX_COLOR,G*MAX_COLOR,B*MAX_COLOR,A*MAX_COLOR); -} - -/*! - * \brief Determines if two ColorFloats are equivalent. - * \details Equality operator for two ColorFloats. Determines if they are equivalent. - * \param c2 Reference to the ColorFloat struct that is the second one in the equivalence comparison. - * \note This function relies on (*this), which is a dereferenced pointer to the first ColorFloat struct in the comparison. - * (its the one on the left side of the == sign). - * \returns true if the two ColorFloats are equivalent, false if otherwise. - */ -bool ColorGLfloat::operator==(ColorGLfloat& c2) { - if((*this).R == c2.R && (*this).G == c2.G && (*this).B == c2.B) { - return true; - } else { - return false; - } -} - -/*! - * \brief Determines if two ColorFloats are *NOT* equivalent. - * \details Inequality operator for two ColorFloats. Determines if they are *NOT* equivalent. - * \param c2 Reference to the ColorFloat struct that is the second one in the inequality comparison. - * \note This function relies on (*this), which is a dereferenced pointer to the first ColorFloat struct in the inequality comparison. - * (its the one on the left side of the != sign). - * \returns true if the two ColorFloats are not equivalent, false if otherwise. - */ -bool ColorGLfloat::operator!=(ColorGLfloat& c2) { - if((*this).R == c2.R && (*this).G == c2.G && (*this).B == c2.B) { - return false; - } else { - return true; - } -} - -/*! - * \brief Multiplies the values of a ColorFloat by a float - * \details This operator multiplies each of the components of a ColorFloat - * by amount f. - * \param f Amount to multiply each component by - * \returns A new ColorFloat constructed as ColorFloat(orig.R*f, orig.G*f, orig.b*f, orig.A*f) - * \note Individual channels are clamped between 0 and 1. - */ -ColorGLfloat ColorGLfloat::operator*(GLfloat f) { - GLfloat newR = (*this).R*f; clamp(newR,0,1); - GLfloat newG = (*this).G*f; clamp(newG,0,1); - GLfloat newB = (*this).B*f; clamp(newB,0,1); - GLfloat newA = (*this).A; - return ColorGLfloat(newR,newG,newB,newA); -} - -ColorGLfloat ColorGLfloat::getContrast() { - GLfloat color = (R + G + B > 1.5) ? 0.0 : 1.0; - return ColorGLfloat(color, color, color, A); -} - - - /*! * \brief Returns an HSVA color with a hue dependent on the number of sections. * \details This function returns a ColorFloat whose hue is calculated from the provided section number and diff --git a/src/TSGL/Color.h b/src/TSGL/Color.h index 30e4ff422..3aa7eba32 100755 --- a/src/TSGL/Color.h +++ b/src/TSGL/Color.h @@ -19,7 +19,7 @@ namespace tsgl { struct ColorFloat; //Forward declarations struct ColorInt; struct ColorHSV; -struct ColorGLfloat; +struct ColorFloat; /*! * \brief Floating point RGBA color struct. @@ -35,9 +35,9 @@ struct ColorFloat { ColorFloat(); - ColorFloat(float v, float a = 1.0f); + ColorFloat(GLfloat v, GLfloat a = 1.0f); - ColorFloat(float r, float g, float b, float a = 1.0f); + ColorFloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0f); std::string asString(); @@ -108,39 +108,6 @@ struct ColorHSV { std::string asString(); }; -/*! - * \brief Floating point RGBA color struct. - * \details ColorFloat defines a color with floating point red, green, blue, and alpha components. - * \param R Red component, between 0 and 1 inclusive. - * \param G Green component, between 0 and 1 inclusive. - * \param B Blue component, between 0 and 1 inclusive. - * \param A Alpha component, between 0 and 1 inclusive. - */ -struct ColorGLfloat { - public: - float R, G, B, A; - - ColorGLfloat(); - - ColorGLfloat(GLfloat v, GLfloat a = 1.0f); - - ColorGLfloat(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1); - - std::string asString(); - - operator ColorHSV(); - - operator ColorInt(); - - ColorGLfloat operator*(GLfloat f); - - bool operator==(ColorGLfloat& c2); - - bool operator!=(ColorGLfloat& c2); - - ColorGLfloat getContrast(); -}; - /*! * \brief The various ColorFloat constants used throughout TSGL. */ diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index 3978b6878..602f99e76 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -32,7 +32,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); edgesOutlined = false; geometryType = GL_TRIANGLE_FAN; @@ -59,7 +59,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * (set to true by default). * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ -ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); edgesOutlined = false; geometryType = GL_TRIANGLE_FAN; @@ -84,7 +84,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * \note This function does nothing if the vertex buffer is already full. * \note A message is given indicating that the vertex buffer is full. */ -void ConcavePolygon::addVertex(float x, float y, float z, ColorGLfloat &color) { +void ConcavePolygon::addVertex(float x, float y, float z, ColorFloat &color) { if (init) { TsglDebug("Cannot add anymore vertices."); return; diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index c7f12617a..fd5344cc8 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -1,7 +1,5 @@ /* * ConcavePolygon.h extends Shape and provides a class for drawing a Concave polygon to a Canvas. - * #FIXME setColor(ColorGLfloat c[]) needs to be overrided. Looks awful with the default. - * #FIXME Performance is horrific. This is going to need to be fixed. */ #ifndef CONCAVEPOLYGON_H_ @@ -28,11 +26,11 @@ class ConcavePolygon : public Shape { protected: ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); - void addVertex(float x, float y, float z, ColorGLfloat &color); + void addVertex(float x, float y, float z, ColorFloat &color); public: - ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color); - ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorGLfloat color[]); + ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]); virtual void draw(); }; diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 8357be50d..74e72ff1a 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -17,7 +17,7 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Cone with a buffer for storing the specified numbered of vertices. */ -Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c) +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) : Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; @@ -39,7 +39,7 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Cone with a buffer for storing the specified numbered of vertices. */ -Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) +Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) : Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; diff --git a/src/TSGL/Cone.h b/src/TSGL/Cone.h index 2f2f77fd6..41bc3410a 100644 --- a/src/TSGL/Cone.h +++ b/src/TSGL/Cone.h @@ -17,9 +17,9 @@ namespace tsgl { */ class Cone : public Pyramid { public: - Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c); + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c); - Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]); + Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]); virtual ~Cone(); }; diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 5701db5b5..72b570dbc 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -32,7 +32,7 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n * (set to true by default). * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_POLYGON; numberOfVertices = numberOfOutlineVertices = numVertices; @@ -57,7 +57,7 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n * (set to true by default). * \return A new ConvexPolygon with the specified vertices and color. */ -ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { +ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_POLYGON; numberOfVertices = numberOfOutlineVertices = numVertices; diff --git a/src/TSGL/ConvexPolygon.h b/src/TSGL/ConvexPolygon.h index 1e4f5fb87..0bab85d15 100755 --- a/src/TSGL/ConvexPolygon.h +++ b/src/TSGL/ConvexPolygon.h @@ -24,9 +24,9 @@ class ConvexPolygon : public Shape { protected: ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); public: - ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color); - ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorGLfloat color[]); + ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]); }; } diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 72102fee1..87ef174fe 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -12,11 +12,11 @@ namespace tsgl { * \param yaw The Cube's yaw, in degrees. * \param pitch The Cube's pitch, in degrees. * \param roll The Cube's roll, in degrees. - * \param c A ColorGLfloat for the Cube's vertex colors. + * \param c A ColorFloat for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. */ -Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c) +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); @@ -73,11 +73,11 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \param yaw The Cube's yaw, in degrees. * \param pitch The Cube's pitch, in degrees. * \param roll The Cube's roll, in degrees. - * \param c An array of ColorGLfloats for the Cube's vertex colors. + * \param c An array of ColorFloats for the Cube's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cube with a buffer for storing the specified numbered of vertices. */ -Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]) +Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); @@ -160,10 +160,10 @@ void Cube::changeSideLengthBy(GLfloat delta) { /** * \brief Sets the Cube to an array of new colors. - * \param c An array of new ColorGLfloats. - * \details The array should have 8 ColorGLfloats minimum, one for each corner. + * \param c An array of new ColorFloats. + * \details The array should have 8 ColorFloats minimum, one for each corner. */ -void Cube::setColor(ColorGLfloat c[]) { +void Cube::setColor(ColorFloat c[]) { attribMutex.lock(); colors[0] = colors[36] = colors[64] = c[0].R; colors[1] = colors[37] = colors[65] = c[0].G; diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 8740341bf..8c9558de1 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -19,9 +19,9 @@ class Cube : public Drawable { protected: GLfloat mySideLength; public: - Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c); + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c); - Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorGLfloat c[]); + Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c[]); virtual void setSideLength(float length); @@ -33,9 +33,9 @@ class Cube : public Drawable { */ virtual GLfloat getSideLength() { return mySideLength; } - virtual void setColor(ColorGLfloat c) { Drawable::setColor(c); } + virtual void setColor(ColorFloat c) { Drawable::setColor(c); } - virtual void setColor(ColorGLfloat c[]); + virtual void setColor(ColorFloat c[]); virtual ~Cube(); }; diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 39443cfea..fb88d2822 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -14,11 +14,11 @@ namespace tsgl { * \param yaw The Cuboid's yaw. * \param pitch The Cuboid's pitch. * \param roll The Cuboid's roll. - * \param c A ColorGLfloat for the Cuboid's vertex colors. + * \param c A ColorFloat for the Cuboid's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ -Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c) +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); @@ -79,11 +79,11 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat * \param yaw The Cuboid's yaw. * \param pitch The Cuboid's pitch. * \param roll The Cuboid's roll. - * \param c An array of ColorGLfloats for the Cuboid's vertex colors. + * \param c An array of ColorFloats for the Cuboid's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ -Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]) +Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); @@ -224,10 +224,10 @@ void Cuboid::changeHeightBy(GLfloat delta) { /** * \brief Sets the Cuboid to an array of new colors. - * \param c An array of new ColorGLfloats. - * \details The array should have 8 ColorGLfloats minimum, one for each corner. + * \param c An array of new ColorFloats. + * \details The array should have 8 ColorFloats minimum, one for each corner. */ -void Cuboid::setColor(ColorGLfloat c[]) { +void Cuboid::setColor(ColorFloat c[]) { attribMutex.lock(); colors[0] = colors[36] = colors[64] = c[0].R; colors[1] = colors[37] = colors[65] = c[0].G; diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index 447a927f0..5ad1b2956 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -19,9 +19,9 @@ class Cuboid : public Drawable { protected: GLfloat myLength, myWidth, myHeight; public: - Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c); + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c); - Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorGLfloat c[]); + Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c[]); virtual void setLength(GLfloat length); @@ -53,9 +53,9 @@ class Cuboid : public Drawable { */ virtual GLfloat getWidth() { return myWidth; } - virtual void setColor(ColorGLfloat c) { Drawable::setColor(c); } + virtual void setColor(ColorFloat c) { Drawable::setColor(c); } - virtual void setColor(ColorGLfloat c[]); + virtual void setColor(ColorFloat c[]); virtual ~Cuboid(); }; diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index d7880c651..66a9f5962 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -13,11 +13,11 @@ namespace tsgl { * \param yaw The Cylinder's yaw. * \param pitch The Cylinder's pitch. * \param roll The Cylinder's roll. - * \param c A ColorGLfloat for the Cylinder's vertex colors. + * \param c A ColorFloat for the Cylinder's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ -Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c) +Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; @@ -35,11 +35,11 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl * \param yaw The Cylinder's yaw. * \param pitch The Cylinder's pitch. * \param roll The Cylinder's roll. - * \param c An array of ColorGLfloats for the Cylinder's vertex colors. + * \param c An array of ColorFloats for the Cylinder's vertex colors. * \warning An invariant is held where if length, width, or height isn't positive then an error message is given. * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ -Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorGLfloat c[]) +Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) : Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; diff --git a/src/TSGL/Cylinder.h b/src/TSGL/Cylinder.h index c288f7e9a..1c37903ef 100644 --- a/src/TSGL/Cylinder.h +++ b/src/TSGL/Cylinder.h @@ -17,9 +17,9 @@ namespace tsgl { */ class Cylinder : public Prism { public: - Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c); + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c); - Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorGLfloat c[]); + Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]); virtual ~Cylinder(); }; diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index 8a50a1dc9..005b8f513 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -75,7 +75,7 @@ void Drawable::draw() { * \note This function does nothing if the vertex buffer is already full. * \note A message is given indicating that the vertex buffer is full. */ -void Drawable::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &color) { +void Drawable::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { if (init) { TsglDebug("Cannot add anymore vertices."); return; @@ -107,9 +107,9 @@ void Drawable::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorGLfloat &co /** * \brief Sets the Drawable to a new color. - * \param c The new ColorGLfloat. + * \param c The new ColorFloat. */ -void Drawable::setColor(ColorGLfloat c) { +void Drawable::setColor(ColorFloat c) { attribMutex.lock(); for(int i = 0; i < numberOfVertices; i++) { colors[i*4] = c.R; @@ -122,9 +122,9 @@ void Drawable::setColor(ColorGLfloat c) { /** * \brief Sets the Drawable's outline/edges to a new color - * \param c The new ColorGLfloat. + * \param c The new ColorFloat. */ -void Drawable::setEdgeColor(ColorGLfloat c) { +void Drawable::setEdgeColor(ColorFloat c) { for (int i = 0; i < numberOfOutlineVertices; i++) { outlineArray[4*i] = c.R; outlineArray[4*i+1] = c.G; diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 54f7fedb6..54380a500 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -43,7 +43,7 @@ class Drawable { GLenum geometryType; GLenum outlineGeometryType; bool init = false; - virtual void addVertex(float x, float y, float z, const ColorGLfloat &color = ColorGLfloat(1,1,1,1)); + virtual void addVertex(float x, float y, float z, const ColorFloat &color = WHITE); /*! * \brief Protected helper method that determines if the Drawable's center matches its rotation point. @@ -60,14 +60,14 @@ class Drawable { virtual void draw(); - virtual void setColor(ColorGLfloat c); + virtual void setColor(ColorFloat c); /** * \brief Pure virtual mutator. Sets the Drawable to a new array of colors. - * \param c An array of the new ColorGLfloats. + * \param c An array of the new ColorFloats. * \warning Inheriting subclasses MUST define an override method for this method. */ - virtual void setColor(ColorGLfloat c[]) = 0; - virtual void setEdgeColor(ColorGLfloat c); + virtual void setColor(ColorFloat c[]) = 0; + virtual void setEdgeColor(ColorFloat c); virtual void changeXBy(float deltaX); virtual void changeYBy(float deltaY); diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index 0c5beca47..f6225dd33 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -13,7 +13,7 @@ namespace tsgl { * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; @@ -36,7 +36,7 @@ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, fl * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index fc6e6a70c..fde618e76 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -17,9 +17,9 @@ class Ellipse : public ConvexPolygon { private: GLfloat myXRadius, myYRadius; public: - Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color); + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color); - Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorGLfloat color[]); + Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]); void setXRadius(GLfloat xRadius); diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 4b12ec25b..38e3e09f5 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -14,11 +14,11 @@ namespace tsgl { * \param yaw The Ellipsoid's yaw. * \param pitch The Ellipsoid's pitch. * \param roll The Ellipsoid's roll. - * \param c A ColorGLfloat for the Ellipsoid's vertex colors. + * \param c A ColorFloat for the Ellipsoid's vertex colors. * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorGLfloat c) : Drawable(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } @@ -42,8 +42,8 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius { for(float a=0;a //To determine M_PI and is also used for math operations +#include //Used for multithreaded capabilities of saferand() +#include //Used to generate random numbers in saferand() namespace tsgl { @@ -130,6 +132,30 @@ inline bool fileExists (const std::string& name) { #endif } +// thanks to Rani Hod of Tel Aviv University for this function. +// slightly modified by Ian Adams of Calvin University to add min, max +/*! + * \brief Thread-safe random integer generator + * \details Calling this method returns a randomly generated number between min, max params. + * Repeated calls will result in uniformly distributed random variables. + * \param min Minimum integer value that can be generated by the method, inclusive. + * \param max Maximum integer value that can be generated by the method, inclusive. + * \note Thanks to Rani Hod of Tel Aviv University for this function. Modified by Ian Adams of Calvin University to add min, max. + */ +inline int saferand(int min, int max) +{ + static std::mt19937* generator = nullptr; + #pragma omp threadprivate(generator) + std::uniform_int_distribution dis(min, max); + if (!generator) { + unsigned seed = clock() + omp_get_thread_num(); + generator = new std::mt19937(seed); + } + int val = dis(*generator); + return val; + // return (*generator)(); +} + } #endif /* SRC_TSGL_UTIL_H_ */ diff --git a/src/tests/DiningPhilosophers/Fork.h b/src/tests/DiningPhilosophers/Fork.h index 58600178a..3d254c176 100644 --- a/src/tests/DiningPhilosophers/Fork.h +++ b/src/tests/DiningPhilosophers/Fork.h @@ -34,12 +34,12 @@ struct Fork { } //Add vertices - myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorGLfloat(1,1,1,1)); + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorFloat(1,1,1,1)); } void setCanvas( Canvas* can) { can->add(myShape); } - void draw(float x, float y, double angle, ColorGLfloat c) { + void draw(float x, float y, double angle, ColorFloat c) { angle -= PI/2; myShape->setColor(c); myShape->setCenter(x, y, 0); diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp index e2009a44c..e0db89609 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/tests/DiningPhilosophers/Philosopher.cpp @@ -6,7 +6,7 @@ */ Philosopher::Philosopher() { setId(0,1); - myState = hasNone; + myState = thinking; myAction = doNothing; myCircle = NULL; numMeals = 0; @@ -27,7 +27,7 @@ Philosopher::~Philosopher() { void Philosopher::draw(Canvas& can, float x, float y) { const float SIZE = .45; if( !myCircle) { - myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorGLfloat(1,0,0,1)); + myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorFloat(1,0,0,1)); can.add(myCircle); } } @@ -36,14 +36,14 @@ void Philosopher::draw(Canvas& can, float x, float y) { * Updates the Philosopher's color based on its state */ void Philosopher::refreshColor() { - ColorGLfloat c; + ColorFloat c; switch(myState) { - case hasNone: c=ColorGLfloat(1,0,0,1); break; - case hasRight: c=ColorGLfloat(1,0.65,0,1); break; - case hasLeft: c=ColorGLfloat(0.75, 0.0, 0.75, 1.0); break; - case hasBoth: c=ColorGLfloat(0, 1.0, 0, 1.0); break; - case isFull: c=ColorGLfloat(0,0,1, 1.0); break; - case thinking: c=ColorGLfloat(0,0,1, 1.0); break; + case hasNone: c=RED; break; + case hasRight: c=ORANGE; break; + case hasLeft: c=PURPLE; break; + case hasBoth: c=GREEN; break; + case isFull: c=BLUE; break; + case thinking: c=BLUE; break; } myCircle->setColor(c); } @@ -53,7 +53,7 @@ void Philosopher::refreshColor() { */ void Philosopher::addMeal(float x, float y, float z) { numMeals++; - meals.push_back(new RegularPolygon(x,y,z,.03,3,0,0,0,ColorGLfloat(0.5,0.3,0,1))); + meals.push_back(new RegularPolygon(x,y,z,.03,3,0,0,0,ColorFloat(0.5,0.3,0,1))); meals.back()->displayOutlineEdges(false); } @@ -106,7 +106,7 @@ bool Philosopher::release(Fork& f) { * Thinks and switches to hungry state if a random number is a multiple of 3. */ void Philosopher::think() { - if(rand()%3 == 0) { // 1/3 probability to go to hungry state + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state setState(hasNone); setAction(doNothing); } diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 33efd32b4..c3c5da8da 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -10,9 +10,9 @@ Table::Table(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Circle(0,0,-1,1.5,0,0,0,ColorGLfloat(0.5,0.5,0.5,1)); + myTable = new Circle(0,0,-1,1.5,0,0,0,ColorFloat(0.5,0.5,0.5,1)); can.add(myTable); - // can.drawCircle(0,0,1,ColorGLfloat(0.5,0.5,0.5,1)); + // can.drawCircle(0,0,1,ColorFloat(0.5,0.5,0.5,1)); phils = new Philosopher[numPhils]; forks = new Fork[numPhils]; for (int i = 0; i < numPhils; ++i) { @@ -460,7 +460,7 @@ void Table::drawStep() { int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; - ColorGLfloat fcolor = ColorGLfloat(1,1,1,1); + ColorFloat fcolor = ColorFloat(1,1,1,1); float fangle = (i+0.5f)*ARC; if( !phils[i].hasCircle() ) { @@ -477,11 +477,11 @@ void Table::drawStep() { } if (forks[i].user == i) { fangle = i*ARC + CLOSE; - fcolor = (phils[i].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(0.75,0,0.75,1); + fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; } else if((forks[i].user == (i+1)%numPhils)) { fangle = ((i+1)*ARC) - CLOSE; - fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; } else { FORK_RAD = 1; fangle = pangle + PI / numPhils; diff --git a/src/tests/DiningPhilosophers3D/Fork3D.h b/src/tests/DiningPhilosophers3D/Fork3D.h index 37ee24529..12dfc920d 100644 --- a/src/tests/DiningPhilosophers3D/Fork3D.h +++ b/src/tests/DiningPhilosophers3D/Fork3D.h @@ -34,12 +34,12 @@ struct Fork3D { } //Add vertices - myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorGLfloat(1,1,1,1)); + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,WHITE); } void setCanvas( Canvas* can) { can->add(myShape); } - void draw(float x, float y, double angle, ColorGLfloat c) { + void draw(float x, float y, double angle, ColorFloat c) { angle -= PI/2; myShape->setColor(c); myShape->setCenter(x, y, 0); diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp index 7e0a58432..d686313eb 100644 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp @@ -6,7 +6,7 @@ */ Philosopher3D::Philosopher3D() { setId(0,1); - myState = hasNone; + myState = thinking; myAction = doNothing; myCylinder = NULL; myCone = NULL; @@ -29,11 +29,11 @@ Philosopher3D::~Philosopher3D() { void Philosopher3D::draw(Canvas& can, float x, float y) { const float SIZE = .45; if( !myCylinder) { - myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,ColorGLfloat(1,0,0,1)); + myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,RED); can.add(myCylinder); } if( !myCone && myCylinder) { - myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorGLfloat(0.7,0,0,1)); + myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorFloat(0.7,0,0,1)); myCone->setRotationPoint(myCylinder->getCenterX(), myCylinder->getCenterY(), myCylinder->getCenterZ()); can.add(myCone); } @@ -43,17 +43,17 @@ void Philosopher3D::draw(Canvas& can, float x, float y) { * Updates the Philosopher3D's color based on its state */ void Philosopher3D::refreshColor() { - ColorGLfloat c; + ColorFloat c; switch(myState) { - case hasNone: c=ColorGLfloat(1,0,0,1); break; - case hasRight: c=ColorGLfloat(1,0.65,0,1); break; - case hasLeft: c=ColorGLfloat(0.75, 0.0, 0.75, 1.0); break; - case hasBoth: c=ColorGLfloat(0, 1.0, 0, 1.0); break; - case isFull: c=ColorGLfloat(0,0,1, 1.0); break; - case thinking: c=ColorGLfloat(0,0,1, 1.0); break; + case hasNone: c=RED; break; + case hasRight: c=ORANGE; break; + case hasLeft: c=PURPLE; break; + case hasBoth: c=GREEN; break; + case isFull: c=BLUE; break; + case thinking: c=BLUE; break; } myCylinder->setColor(c); - myCone->setColor(ColorGLfloat(c.R*.7,c.G*.7,c.B*.7,c.A)); + myCone->setColor(ColorFloat(c.R*.7,c.G*.7,c.B*.7,c.A)); } /** @@ -61,7 +61,7 @@ void Philosopher3D::refreshColor() { */ void Philosopher3D::addMeal(float x, float y, float z) { numMeals++; - meals.push_back(new Pyramid(x,y,z,3,.08,.04,0,0,90,ColorGLfloat(0.5,0.3,0,1))); + meals.push_back(new Pyramid(x,y,z,3,.08,.04,0,0,90,ColorFloat(0.5,0.3,0,1))); meals.back()->displayOutlineEdges(false); } @@ -114,7 +114,7 @@ bool Philosopher3D::release(Fork3D& f) { * Thinks and switches to hungry state if a random number is a multiple of 3. */ void Philosopher3D::think() { - if(rand()%3 == 0) { // 1/3 probability to go to hungry state + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state setState(hasNone); setAction(doNothing); } diff --git a/src/tests/DiningPhilosophers3D/Table3D.cpp b/src/tests/DiningPhilosophers3D/Table3D.cpp index 63c09445d..a4519c43b 100644 --- a/src/tests/DiningPhilosophers3D/Table3D.cpp +++ b/src/tests/DiningPhilosophers3D/Table3D.cpp @@ -10,7 +10,7 @@ Table3D::Table3D(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Cylinder(0,0,-2,1,1.5,0,0,90,ColorGLfloat(0.5,0.5,0.5,1)); + myTable = new Cylinder(0,0,-2,1,1.5,0,0,90,ColorFloat(0.5,0.5,0.5,1)); can.add(myTable); phils = new Philosopher3D[numPhils]; forks = new Fork3D[numPhils]; @@ -459,7 +459,7 @@ void Table3D::drawStep() { int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; - ColorGLfloat fcolor = ColorGLfloat(1,1,1,1); + ColorFloat fcolor = WHITE; float fangle = (i+0.5f)*ARC; if( !phils[i].hasCylinder() ) { @@ -476,11 +476,11 @@ void Table3D::drawStep() { } if (forks[i].user == i) { fangle = i*ARC + CLOSE; - fcolor = (phils[i].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(0.75,0,0.75,1); + fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; } else if((forks[i].user == (i+1)%numPhils)) { fangle = ((i+1)*ARC) - CLOSE; - fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? ColorGLfloat(0,1,0,1) : ColorGLfloat(1,0.65,0,1); + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; } else { FORK_RAD = 0.9; fangle = pangle + PI / numPhils; diff --git a/src/tests/test2Dvs3D.cpp b/src/tests/test2Dvs3D.cpp index 668880755..53fe9f65a 100644 --- a/src/tests/test2Dvs3D.cpp +++ b/src/tests/test2Dvs3D.cpp @@ -10,14 +10,14 @@ using namespace tsgl; void contrastFunction(Canvas& can) { - ColorGLfloat pyramidcolors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - ColorGLfloat triangle2Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,1,1,1), ColorGLfloat(0,1,0,1) }; - ColorGLfloat triangle3Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(1,0,1,1), ColorGLfloat(1,0,0,1) }; - ColorGLfloat triangle6Colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1) }; + ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; + ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; + ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; Pyramid * testPyramid = new Pyramid(-2.0, 0.0, -1.0, 4, 2, 2, 0.0, 0.0, 45.0, pyramidcolors); // can.add(testPyramid); Triangle * triangle1 = new Triangle(1.39,0.66,0,3.5,-0.52,0,1.62,-2,0,0,0,0,pyramidcolors); diff --git a/src/tests/test3DPhilosophers.cpp b/src/tests/test3DPhilosophers.cpp index 583f33eff..6da76e638 100644 --- a/src/tests/test3DPhilosophers.cpp +++ b/src/tests/test3DPhilosophers.cpp @@ -82,7 +82,7 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step if(stepThrough) { philPauses[omp_get_thread_num()] = true; } t.checkStep(); can.pauseDrawing(); - if(method == forfeitWhenBlocked || method == waitWhenBlocked) { //Synchronize to see Livelock and Deadlock + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock #pragma omp barrier //Barrier for optional synchronization } t.actStep(); diff --git a/src/tests/test3DRotation.cpp b/src/tests/test3DRotation.cpp index 55dfc24ac..61496b283 100644 --- a/src/tests/test3DRotation.cpp +++ b/src/tests/test3DRotation.cpp @@ -10,14 +10,14 @@ using namespace tsgl; void cubeFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; Cube * testCube = new Cube(2.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, colors); testCube->setRotationPoint(0,0,0); Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 90.0, colors); diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 63aba87df..93b8989c8 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -5,9 +5,9 @@ using namespace tsgl; void arrowFunction(Canvas& c) { - ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1) }; + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1) }; Arrow* doubleArrow = new Arrow(0, 0, 0, 2, 0.05,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(1 ,1 ,-1 ,2 ,0.05,0,0,0,ColorGLfloat(0,0,1,0.65), true); + Arrow* arrow2 = new Arrow(1 ,1 ,-1 ,2 ,0.05,0,0,0,ColorFloat(0,0,1,0.65), true); c.add(doubleArrow); c.add(arrow2); // doubleArrow->setCenterX(1); diff --git a/src/tests/testBallroom.cpp b/src/tests/testBallroom.cpp index e9181cba6..c614c3c32 100644 --- a/src/tests/testBallroom.cpp +++ b/src/tests/testBallroom.cpp @@ -76,10 +76,10 @@ class BouncingBall { Canvas * can; public: Vector2 pos, vel, acc; - ColorGLfloat color; + ColorFloat color; int rad; bool bounced; - BouncingBall(int x, int y, int r, int w, int h, ColorGLfloat c, Canvas * can) { + BouncingBall(int x, int y, int r, int w, int h, ColorFloat c, Canvas * can) { pos = Vector2(x,y); vel = Vector2(0,0); acc = Vector2(0,0); @@ -93,7 +93,7 @@ class BouncingBall { // circle->setLayer(1); can->add(circle); } - BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorGLfloat c, Canvas * canvas) { + BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorFloat c, Canvas * canvas) { pos = Vector2(x,y); vel = Vector2(vx,vy); acc = Vector2(0,0.1f); @@ -197,7 +197,7 @@ class BallRoom { gravity = 0.1f; attract = true; can = canvas; - mouseCircle = new Circle(0,0,0,1,0,0,0,ColorGLfloat(1.0,0.5,0.5,0.5)); + mouseCircle = new Circle(0,0,0,1,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); // mouseCircle->setLayer(2); can->add(mouseCircle); } @@ -209,10 +209,10 @@ class BallRoom { } delete mouseCircle; } - void addBall(int x, int y, int r, ColorGLfloat c = ColorGLfloat(1,1,1,1)) { + void addBall(int x, int y, int r, ColorFloat c = WHITE) { addBall(x,y,0,0,r,c); } - void addBall(int x, int y, int vx, int vy, int r, ColorGLfloat c = ColorGLfloat(1,1,1,1)) { + void addBall(int x, int y, int vx, int vy, int r, ColorFloat c = WHITE) { BouncingBall* b = new BouncingBall(x,y,vx,vy,r,width,height,c, can); const int MAXFAIL = 1000; int fails = 0; @@ -232,9 +232,9 @@ class BallRoom { Vector2 mvec(mx,my); mouseCircle->setCenter(mx, my, 0); if (attract) { - mouseCircle->setColor(ColorGLfloat(0.5,1.0,1.0,0.5)); + mouseCircle->setColor(ColorFloat(0.5,1.0,1.0,0.5)); } else { - mouseCircle->setColor(ColorGLfloat(1.0,0.5,0.5,0.5)); + mouseCircle->setColor(ColorFloat(1.0,0.5,0.5,0.5)); } for (it = balls.begin(); it != balls.end(); ++it) { BouncingBall *b = (*it); @@ -294,14 +294,13 @@ void ballroomFunction(Canvas& can) { float speed = 5.0f; float dir = 2 * 3.14159f * (rand() % 100) / 100.0f; b.addBall(25 + rand() % (WW-50),25 + rand() % (WH-50),speed*cos(dir),speed*sin(dir),10, - ColorGLfloat((64 + rand() % 192) / 255,(64 + rand() % 192) / 255,(64 + rand() % 192) / 255,1)); + ColorFloat((64 + rand() % 192) / 255,(64 + rand() % 192) / 255,(64 + rand() % 192) / 255,1)); } can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { b.toggleAttract(); }); -// ColorGLfloat clearcolor = ColorInt(0,0,0,16); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp index ed71498f4..f3e736685 100644 --- a/src/tests/testCircle.cpp +++ b/src/tests/testCircle.cpp @@ -10,18 +10,18 @@ using namespace tsgl; void circleFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Circle * circle = new Circle(0,0,0,1,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Circle * circle = new Circle(0,0,0,1,0,0,0,colors/* ColorFloat(1,0,0,1) */); // circle->setCenterX(2); // circle->setRotationPoint(0,0,0); can.add(circle); @@ -38,13 +38,13 @@ void circleFunction(Canvas& can) { // circle->setRadius(sin(floatVal/90) + 1); // if (circle->getRadius() > 3 || circle->getRadius() < 1) { // delta *= -1; - // circle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // circle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // circle->changeRadiusBy(delta); // if (delta > 0) { // circle->setColor(colors); // } else { - // circle->setColor(ColorGLfloat(1,0,0,1)); + // circle->setColor(ColorFloat(1,0,0,1)); // } floatVal += 1; } diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp index e9ec66462..ade5c8870 100644 --- a/src/tests/testClock.cpp +++ b/src/tests/testClock.cpp @@ -11,41 +11,41 @@ using namespace tsgl; void clockFunction(Canvas& can) { - Prism * head = new Prism(0,1.33,1.01,12,1,0.59,0,0,90,ColorGLfloat(.6,.3,0,1)); + Prism * head = new Prism(0,1.33,1.01,12,1,0.59,0,0,90,ColorFloat(.6,.3,0,1)); can.add(head); - Cuboid * left = new Cuboid(-0.45,-.5,1,0.1,3,1,0,0,0,ColorGLfloat(.6,.3,0,1) ); + Cuboid * left = new Cuboid(-0.45,-.5,1,0.1,3,1,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(left); - Cuboid * right = new Cuboid(0.45,-0.5,1,0.1,3,1,0,0,0,ColorGLfloat(.6,.3,0,1)); + Cuboid * right = new Cuboid(0.45,-0.5,1,0.1,3,1,0,0,0,ColorFloat(.6,.3,0,1)); can.add(right); - Cuboid * back = new Cuboid(0,-0.5,0.55,0.8,3,0.1,0,0,0,ColorGLfloat(.6,.3,0,1) ); + Cuboid * back = new Cuboid(0,-0.5,0.55,0.8,3,0.1,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(back); - Cuboid * bottom = new Cuboid(0,-1.95,1.10,0.79,0.1,0.8,0,0,0,ColorGLfloat(.6,.3,0,1) ); + Cuboid * bottom = new Cuboid(0,-1.95,1.10,0.79,0.1,0.8,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(bottom); - Circle * face = new Circle(0,1.15,2.01,0.4,0,0,0,ColorGLfloat(1,1,0.8,1)); + Circle * face = new Circle(0,1.15,2.01,0.4,0,0,0,ColorFloat(1,1,0.8,1)); can.add(face); - Arrow * second = new Arrow(-0.19,1.15,2.03,0.38,0.02,0,0,0,ColorGLfloat(1,.8,.2,1),false); + Arrow * second = new Arrow(-0.19,1.15,2.03,0.38,0.02,0,0,0,ColorFloat(1,.8,.2,1),false); can.add(second); second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Arrow * minute = new Arrow(-0.19,1.15,2.02,0.38,0.02,0,0,0,ColorGLfloat(0,0,0,1),false); + Arrow * minute = new Arrow(-0.19,1.15,2.02,0.38,0.02,0,0,0,ColorFloat(0,0,0,1),false); can.add(minute); minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Arrow * hour = new Arrow(-0.1,1.15,2.02,0.2,0.02,0,0,0,ColorGLfloat(0,0,0,1),false); + Arrow * hour = new Arrow(-0.1,1.15,2.02,0.2,0.02,0,0,0,ColorFloat(0,0,0,1),false); can.add(hour); hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Ellipsoid * pendulum = new Ellipsoid(0, -1.5, 1,0.1, 0.1,0.02,0,0,0,ColorGLfloat(0.75,0.6,.19, 1) ); + Ellipsoid * pendulum = new Ellipsoid(0, -1.5, 1,0.1, 0.1,0.02,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); pendulum->setRotationPoint(0,0.8,1); can.add(pendulum); - Rectangle * cord = new Rectangle(-1.1,0.8,1,2.2,0.05,90,0,0,ColorGLfloat(0,0,0,1)); + Rectangle * cord = new Rectangle(-1.1,0.8,1,2.2,0.05,90,0,0,ColorFloat(0,0,0,1)); cord->setRotationPoint(0,0.8,1); cord->displayOutlineEdges(false); can.add(cord); diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp index bc293ab59..2662acd7a 100644 --- a/src/tests/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon.cpp @@ -29,9 +29,9 @@ void concavePolygonFunction(Canvas& can) { float xx[PSIZE]; float yy[PSIZE]; - ColorGLfloat color[PSIZE]; + ColorFloat color[PSIZE]; for (unsigned i = 0; i < PSIZE; ++i) - color[i] = ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1); + color[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1); color[1] = color[PSIZE-1]; @@ -59,7 +59,7 @@ void concavePolygonFunction(Canvas& can) { ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); // c2->setColor(color); - // c2->setColor(ColorGLfloat(1,0,0,1)); + // c2->setColor(RED); can.add(c2); float floatVal = 0.0f; diff --git a/src/tests/testCone.cpp b/src/tests/testCone.cpp index 168e8bd67..db1ad3045 100644 --- a/src/tests/testCone.cpp +++ b/src/tests/testCone.cpp @@ -10,18 +10,18 @@ using namespace tsgl; void coneFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1), - ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1), - ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1) }; - Cone * testCone = new Cone(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 0.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; + Cone * testCone = new Cone(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 0.0, ColorFloat(1,0,0,1)); // Cone * testCone2 = new Cone(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCone); // can.add(testCone2); @@ -54,7 +54,7 @@ void coneFunction(Canvas& can) { // testCone->changeRadiusBy(delta); if (rotation*45 >= 360) { if (boolean) { - testCone->setColor(ColorGLfloat(1,0,0,1)); + testCone->setColor(RED); } else { testCone->setColor(colors); } diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp index 4dcf6d883..747f1d947 100644 --- a/src/tests/testConvexPolygon.cpp +++ b/src/tests/testConvexPolygon.cpp @@ -10,17 +10,17 @@ using namespace tsgl; void convexPolygonFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; float x[] = { -0.5,-0.5,0 ,0.25,0.5,0.5,0.25 }; float y[] = { -0.5,0.25,0.5,0.4 ,0.1,-0.1,-0.5 }; - ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors/* ColorFloat(1,0,0,1) */); // cp->setCenterX(2); // cp->setRotationPoint(0,0,0); can.add(cp); @@ -36,10 +36,10 @@ void convexPolygonFunction(Canvas& can) { // if (floatVal < 200) { // cp->setColor(colors); // } else { - // cp->setColor(ColorGLfloat(1,0,0,1)); + // cp->setColor(RED); // if (floatVal > 400) { // floatVal = 0; - // cp->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // cp->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // } floatVal += 1; diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 3cb58374e..03f635abf 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -10,10 +10,10 @@ using namespace tsgl; void cubeFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, ColorFloat(1,0,0,1)); Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCube); can.add(testCube2); @@ -39,7 +39,7 @@ void cubeFunction(Canvas& can) { //testCube2->setRoll(rotation); if (rotation*45 >= 360) { if (boolean) { - testCube->setColor(ColorGLfloat(1,0,0,1)); + testCube->setColor(RED); } else { testCube->setColor(colors); } diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index fead47d0d..330e67e63 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -10,10 +10,10 @@ using namespace tsgl; void cuboidFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8) }; - Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); // Cuboid * testCuboid2 = new Cuboid(-3.0, 0.0, 0.0, 1, 3, 2, 0.0, 0.0, 0.0, colors); can.add(testCuboid); // can.add(testCuboid2); @@ -56,7 +56,7 @@ void cuboidFunction(Canvas& can) { // testCuboid->changeLengthBy(delta); if (rotation*45 >= 360) { if (boolean) { - testCuboid->setColor(ColorGLfloat(1,0,0,1)); + testCuboid->setColor(RED); } else { testCuboid->setColor(colors); } diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index 2de337bde..fa2443f6a 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -10,12 +10,12 @@ using namespace tsgl; void cylinderFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); // Cylinder * testCylinder2 = new Cylinder(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCylinder); // can.add(testCylinder2); @@ -53,7 +53,7 @@ void cylinderFunction(Canvas& can) { // } if (rotation*45 >= 360) { if (boolean) { - testCylinder->setColor(ColorGLfloat(1,0,0,1)); + testCylinder->setColor(RED); } else { testCylinder->setColor(colors); } diff --git a/src/tests/testDice.cpp b/src/tests/testDice.cpp index 673866913..f3fafa2d1 100644 --- a/src/tests/testDice.cpp +++ b/src/tests/testDice.cpp @@ -14,71 +14,71 @@ using namespace tsgl; void diceFunction(Canvas& can) { - Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, ColorGLfloat(1,1,1,1)); + Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); can.add(die); - RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); can.add(spot1); spot1->setRotationPoint(0,0,0); - RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); spot2_1->setRotationPoint(0,0,0); can.add(spot2_1); - RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); spot2_2->setRotationPoint(0,0,0); can.add(spot2_2); - RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); spot3_1->setRotationPoint(0,0,0); can.add(spot3_1); - RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); spot3_2->setRotationPoint(0,0,0); can.add(spot3_2); - RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); spot3_3->setRotationPoint(0,0,0); can.add(spot3_3); - // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); // spot4_1->setRotationPoint(0,0,0); // can.add(spot4_1); - // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); // spot4_2->setRotationPoint(0,0,0); // can.add(spot4_2); - // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); // spot4_3->setRotationPoint(0,0,0); // can.add(spot4_3); - // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,ColorGLfloat(0,0,0,1) ); + // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); // spot4_4->setRotationPoint(0,0,0); // can.add(spot4_4); - RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); spot5_1->setRotationPoint(0,0,0); can.add(spot5_1); - RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); spot5_2->setRotationPoint(0,0,0); can.add(spot5_2); - RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); spot5_3->setRotationPoint(0,0,0); can.add(spot5_3); - RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); spot5_4->setRotationPoint(0,0,0); can.add(spot5_4); - RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,ColorGLfloat(0,0,0,1) ); + RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); spot5_5->setRotationPoint(0,0,0); can.add(spot5_5); - RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_1); - RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_2); - RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_3); - RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_4); - RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_5); - RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,ColorGLfloat(0,0,0,1)); + RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); can.add(spot6_6); spot6_1->setRotationPoint(0,0,0); spot6_2->setRotationPoint(0,0,0); diff --git a/src/tests/testDiorama.cpp b/src/tests/testDiorama.cpp index 45e0179c9..090dfac93 100644 --- a/src/tests/testDiorama.cpp +++ b/src/tests/testDiorama.cpp @@ -10,35 +10,35 @@ using namespace tsgl; void dioramaFunction(Canvas& can) { - Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,ColorGLfloat(1,1,1,1)); - blankCanvas->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,WHITE); + blankCanvas->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(blankCanvas); - Rectangle * emptyDioramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); - emptyDioramaLeft->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + Rectangle * emptyDioramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorFloat(1,1,1,0)); + emptyDioramaLeft->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaLeft); - Rectangle * emptyDioramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorGLfloat(1,1,1,0)); - emptyDioramaRight->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + Rectangle * emptyDioramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorFloat(1,1,1,0)); + emptyDioramaRight->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaRight); - Rectangle * emptyDioramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); - emptyDioramaTop->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + Rectangle * emptyDioramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorFloat(1,1,1,0)); + emptyDioramaTop->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaTop); - Rectangle * emptyDioramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorGLfloat(1,1,1,0)); - emptyDioramaBottom->setEdgeColor(ColorGLfloat(0.1,0.1,0.1,1)); + Rectangle * emptyDioramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorFloat(1,1,1,0)); + emptyDioramaBottom->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaBottom); - Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorGLfloat(.6,.3,0,1)); + Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorFloat(.6,.3,0,1)); trunk->displayOutlineEdges(false); // can.add(trunk); - Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,ColorGLfloat(0,1,0,1)); + Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,GREEN); // can.add(leaves); - Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorGLfloat(.6,.3,0,1)); + Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorFloat(.6,.3,0,1)); trunkFlat->displayOutlineEdges(false); // can.add(trunkFlat); - Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorGLfloat(0,0.8,0,1)); + Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorFloat(0,0.8,0,1)); // can.add(leavesFlat); float counter = 0; diff --git a/src/tests/testDumbSort.cpp b/src/tests/testDumbSort.cpp deleted file mode 100644 index f9eba386d..000000000 --- a/src/tests/testDumbSort.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * testDumbSort.cpp - * - * Usage: ./testDumbSort - */ - -#include - -using namespace tsgl; - -/*! - * \brief Provides a visualization for a basic (and slow) shaker sort. - * \details - * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. - * - An integer array of size \b SIZE is allocated. - * - A flag \b goingUp is set. - * - Our integer array is filled with random integers under the Canvas' height. - * - The background color is set to gray for visibility. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - While the Canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - If the minimum sorted element is greater than or equals the maximum, we're done. - * - At a rate of \b IPF times a second: - * - If we're going up and the element above us is less than us, swap. - * - If we're going down and the element below us is less than us, swap. - * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. - * . - * - Pause the animation. - * - Clear the Canvas. - * - From 0 to \b SIZE: - * - Get the height of each element in the integer array. - * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. - * . - * - Resume the animation. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void dumbSortFunction(Canvas& can) { - const int SIZE = 550, // Size of the data pool (set to 550 by default) - IPF = 50; // Iterations per frame - int numbers[SIZE]; // Array to store the data - int pos = 0, temp, min = 1, max = SIZE - 2, lastSwap = 0; - bool goingUp = true; - for (int i = 0; i < SIZE; i++) - numbers[i] = rand() % (can.getWindowHeight() - 40); - can.setBackgroundColor(GRAY); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - if (min >= max) return; // We are done sorting - for (int i = 0; i < IPF; i++) { - if (goingUp) { - if (numbers[pos] > numbers[pos + 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos + 1]; - numbers[pos + 1] = temp; - lastSwap = pos; - } - if (pos >= max) { - pos = max; - max = (lastSwap < max) ? lastSwap : max - 1; - goingUp = !goingUp; - } else - pos++; - } else { - if (numbers[pos] < numbers[pos - 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos - 1]; - numbers[pos - 1] = temp; - lastSwap = pos; - } - if (pos <= min) { - pos = min; - min = (lastSwap > min) ? lastSwap : min + 1; - goingUp = !goingUp; - } else - pos--; - } - } - int start = 50, width = 1, height; - int cwh = can.getWindowHeight() - 20; - ColorFloat color; - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - can.clearProcedural(); - for (int i = 0; i < SIZE; i++, start += width * 2) { - height = numbers[i]; - color = ColorInt(MAX_COLOR, (i == pos) ? MAX_COLOR : 0, 0); - can.drawRectangle(start, cwh - height, width, height, color); - } - can.resumeDrawing(); //Tell the Canvas it can resume drawing - } -} - -//Takes in command line arguments for the window width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid - w = 1200; h = 900; // If not, set the width and height to a default value - } - Canvas c(-1, -1, w, h, "Shaker Sort"); - c.run(dumbSortFunction); -} diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp index 6d6ccbeed..6afdfaaf3 100644 --- a/src/tests/testEllipse.cpp +++ b/src/tests/testEllipse.cpp @@ -10,18 +10,18 @@ using namespace tsgl; void ellipseFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Ellipse * ellipse = new Ellipse(0,0,0,1,2,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipse * ellipse = new Ellipse(0,0,0,1,2,0,0,0,colors/* ColorFloat(1,0,0,1) */); // ellipse->setCenterX(2); // ellipse->setRotationPoint(0,0,0); can.add(ellipse); @@ -39,18 +39,18 @@ void ellipseFunction(Canvas& can) { // ellipse->setYRadius(sin(floatVal/90) + 2); // if (ellipse->getXRadius() > 3 || ellipse->getXRadius() < 1) { // delta *= -1; - // ellipse->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // ellipse->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // ellipse->changeXRadiusBy(delta); // if (ellipse->getYRadius() > 3 || ellipse->getYRadius() < 1) { // delta *= -1; - // ellipse->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // ellipse->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // ellipse->changeYRadiusBy(delta); // if (delta > 0) { // ellipse->setColor(colors); // } else { - // ellipse->setColor(ColorGLfloat(1,0,0,1)); + // ellipse->setColor(RED); // } floatVal += 1; } diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 65c2fdc98..147cfc02d 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -10,15 +10,15 @@ using namespace tsgl; void ellipsoidFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 2, 2, 2, 0.0, 0.0, 0.0, colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 2, 2, 2, 0.0, 0.0, 0.0, colors/* ColorFloat(1,0,0,1) */); // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); can.add(testEllipsoid); // can.add(testEllipsoid2); @@ -73,7 +73,7 @@ void ellipsoidFunction(Canvas& can) { // } if (rotation*45 >= 360) { if (boolean) { - testEllipsoid->setColor(ColorGLfloat(1,0,0,1)); + testEllipsoid->setColor(RED); } else { testEllipsoid->setColor(colors); } diff --git a/src/tests/testLines.cpp b/src/tests/testLines.cpp index c35b61ed5..79377fa2f 100644 --- a/src/tests/testLines.cpp +++ b/src/tests/testLines.cpp @@ -5,13 +5,13 @@ using namespace tsgl; void lineFunction(Canvas& c) { - ColorGLfloat colors[] = { ColorGLfloat(1,0,0,1), ColorGLfloat(0,1,0,1), - ColorGLfloat(0,0,1,1), ColorGLfloat(1,0,1,1), - ColorGLfloat(1,1,0,1), ColorGLfloat(0,1,1,1), - ColorGLfloat(0,0,1,1) }; - Line * l = new Line(0,0,0,2,0,0,0,ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1), + ColorFloat(0,0,1,1), ColorFloat(1,0,1,1), + ColorFloat(1,1,0,1), ColorFloat(0,1,1,1), + ColorFloat(0,0,1,1) }; + Line * l = new Line(0,0,0,2,0,0,0,ColorFloat(1,0,0,1)); - // l->setColor(ColorGLfloat(1,0,0,1)); + // l->setColor(RED); l->setColor(colors); float vertices[] = { -1.5,-1,-1, @@ -22,9 +22,9 @@ void lineFunction(Canvas& c) { 1,-1,1, 1.5,-1,-1 }; - Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,ColorGLfloat(0,0,1,1)); + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,BLUE); - // p->setColor(ColorGLfloat(0,0,1,1)); + // p->setColor(BLUE); p->setColor(colors); c.add(l); c.add(p); diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp new file mode 100644 index 000000000..c96dd9016 --- /dev/null +++ b/src/tests/testMergeSort.cpp @@ -0,0 +1,209 @@ +/* + * testMergeSort.cpp + * + * Usage: ./testMergeSort + */ + +#include +#include + +using namespace tsgl; + +const int MARGIN = 8; // Border for drawing + +enum MergeState { + S_MERGE = 1, + S_SHIFT = 2, + S_WAIT = 3, + S_DONE = 4, + S_HIDE = 5 +}; + +struct sortData { + ColorFloat color; //Color of the thread + MergeState state; //Current state of the threads + int first, last, //Start and end of our block + left, right, //Indices of two numbers to compare + fi, hi, li, //Indices of first middle and last numbers in a set + depth; //Current depth of the merge + float* a; //Array of numbers to sort + int seg, segs; //Current / total segments + int size; + + sortData(float* arr, int f, int l, ColorFloat c) { + fi = hi = li = 0; //Initialize indices + left = right = 0; //Initialize bounds + color = c; //Set the color + a = arr; //Get a pointer to the array we'll be sorting + first = f; //Set the first element we need to worry about + last = l; //Set the last element we need to worry about + depth = 0; //We start at depth 0 + seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment + while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done + ++depth; //Otherwise, increment the depth... + segs *= 2; //...and double the number of segments + } + state = S_SHIFT; //Start Merging + size = 2; + } + + void restart(int l) { + depth = 0; + hi = last; + right = hi+1; + last = li = l; + fi = left = first; + state = S_MERGE; + size *= 2; + } + + void sortStep() { + float tmp; + int pivot, jump; + switch(state) { + case S_SHIFT: + pivot = jump = segs/2; + fi = first; li = last; + hi = (fi + li) / 2; //Set our half index to the median of our first and last + for (tmp = depth; tmp > 0; --tmp) { + jump /= 2; + if (seg < pivot) { + pivot -= jump; + li = hi; //Set out last index to our old half index + } else { + pivot += jump; + fi = hi+1; //Set out first index to our old half index plus one + } + hi = (fi + li) / 2; //Set our new half index to the median of our first and last + } + left = fi; right = hi+1; + state = S_MERGE; //We're ready to start Merging + break; + case S_MERGE: + if (left > right || right > last) { + seg = 0; //Reset our segment(s) + segs /= 2; //We're now using half as many segments + state = (depth-- == 0) ? S_WAIT : S_SHIFT; + } else if (right > li) { + ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices + } else if (left <= hi && a[left] < a[right]) { + ++left; + } else { + tmp = a[right]; + for (int x = right; x > left; --x) + a[x] = a[x-1]; + a[left] = tmp; + ++left; ++right; ++hi; + } + break; + default: + break; + } + } +}; + +/*! + * \brief Visualization of the bottom-up mergesort algorithm. + * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. + * \details Uses lines to represent the items being sorted. + * \details At the start, the items being sorted are all divided. + * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. + * \details Different colors represent different sections being sorted. + * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. + */ +void mergeSortFunction(Canvas& can, int threads, int size) { + const int IPF = 1; // Iterations per frame + float* numbers = new float[size]; // Array to store the data + Line** lines = new Line*[size]; // Array to store the data + for (int i = 0; i < size; i++) { + numbers[i] = (float) (saferand(1,200000)) / 50000; + printf("%d: %f\n", i, numbers[i]); + lines[i] = new Line(-5.6 + ((float) i * size / 95000), 0, 0, numbers[i], 90, 0, 0, RED); + can.add(lines[i]); + } + + int bs = size / threads; + int ex = size % threads; + sortData** sd = new sortData*[threads]; + int f = 0; + int l = (ex == 0) ? bs-1 : bs; + for (int i = 0; i < threads; ++i) { + sd[i] = new sortData(numbers,f,l,Colors::highContrastColor(i)); + f = l+1; + if (i < ex-1) l += (bs + 1); + else l += bs; + } + while (can.isOpen()) { + #pragma omp parallel num_threads(threads) + { + int tid = omp_get_thread_num(); + can.sleep(); + if (sd[tid]->state == S_WAIT) { //Merge waiting threads + if ((tid % sd[tid]->size) > 0) + sd[tid]->state = S_DONE; + else { + int next = tid+sd[tid]->size/2; + if (next < threads && sd[next]->state == S_DONE) { + sd[next]->state = S_HIDE; + sd[tid]->restart(sd[next]->last); + } + } + } + for (int i = 0; i < IPF; i++) + sd[tid]->sortStep(); + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + int start = MARGIN/2 + sd[tid]->first; + float height; + int cwh = can.getWindowHeight() - MARGIN/2; + ColorFloat color; + if (sd[tid]->state != S_HIDE) { + //Draw a black rectangle over our portion of the screen to cover up the old drawing + // can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); + for (int i = sd[tid]->first; i < sd[tid]->last; ++i, ++start) { + height = numbers[i]; + if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) + color = WHITE; + else { + if (i == sd[tid]->right || i == sd[tid]->left) + color = WHITE; + else if (i < sd[tid]->left) + color = sd[tid]->color; + else if (i >= sd[tid]->fi && i <= sd[tid]->li) + color = Colors::blend(sd[tid]->color, WHITE, 0.5f); + else + color = Colors::blend(sd[tid]->color, BLACK, 0.5f); + } + lines[i]->setLength(height); + lines[i]->setColor(color); + // lines[i]->setCenterX(start); + // can.drawLine(start, cwh - height, start, cwh, color); + } + } + can.resumeDrawing(); //Tell the Canvas it can resume updating + } + } + for (int i = 0; i < threads; ++i) + delete sd[i]; + delete [] sd; + delete [] numbers; + for (int i = 0; i < size; i++) { + delete lines[i]; + } + delete [] lines; +} + +//Takes in command line arguments for the window width and height +//as well as for the number of threads to use +int main(int argc, char* argv[]) { + int s = (argc > 1) ? atoi(argv[1]) : 1024; + if (s < 10) s = 10; + int w = s * 1.3 + MARGIN; + int h = w/2; + + int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); + for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 + + Canvas c(-1, -1, w, h, "Bottom-up Merge Sort"); + c.setBackgroundColor(BLACK); + c.run(mergeSortFunction, threads, s); +} diff --git a/src/tests/testPhilosophers.cpp b/src/tests/testPhilosophers.cpp index d00f4bda6..5b38efbb5 100644 --- a/src/tests/testPhilosophers.cpp +++ b/src/tests/testPhilosophers.cpp @@ -82,7 +82,7 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step if(stepThrough) { philPauses[omp_get_thread_num()] = true; } t.checkStep(); can.pauseDrawing(); - if(method == forfeitWhenBlocked || method == waitWhenBlocked) { //Synchronize to see Livelock and Deadlock + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock #pragma omp barrier //Barrier for optional synchronization } t.actStep(); diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index 94853b8fa..2a96d230d 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -10,12 +10,12 @@ using namespace tsgl; void prismFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); Prism * testPrism2 = new Prism(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); Prism * testPrism3 = new Prism(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); can.add(testPrism); @@ -49,12 +49,12 @@ void prismFunction(Canvas& can) { // } // testPrism->changeRadiusBy(delta); // if (rotation*45 >= 360) { - // testPrism->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // testPrism->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // rotation = 0; // } // if (rotation*45 >= 360) { // if (boolean) { - // testPrism->setColor(ColorGLfloat(1,0,0,1)); + // testPrism->setColor(RED); // } else { // testPrism->setColor(colors); // } diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 68042f775..173f4cced 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -10,12 +10,12 @@ using namespace tsgl; void pyramidFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,1), ColorGLfloat(0,0,1,1), - ColorGLfloat(0,1,0,1), ColorGLfloat(0,1,1,1), ColorGLfloat(1,0,0,1), - ColorGLfloat(1,0,1,1), ColorGLfloat(1,1,0,1), ColorGLfloat(1,1,1,1), - ColorGLfloat(0.5,0,0.5,1), ColorGLfloat(0,0.5,0.5,1), - ColorGLfloat(0.5,0.5,0,1), ColorGLfloat(0,0.5,1,1) }; - Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorGLfloat(1,0,0,1)); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); Pyramid * testPyramid2 = new Pyramid(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); Pyramid * testPyramid3 = new Pyramid(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); can.add(testPyramid); @@ -52,7 +52,7 @@ void pyramidFunction(Canvas& can) { // testPyramid->changeRadiusBy(delta); if (rotation*45 >= 360) { if (boolean) { - testPyramid->setColor(ColorGLfloat(1,0,0,1)); + testPyramid->setColor(RED); } else { testPyramid->setColor(colors); } diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp index fd2e205e5..734b2a7a1 100644 --- a/src/tests/testRectangle.cpp +++ b/src/tests/testRectangle.cpp @@ -10,15 +10,15 @@ using namespace tsgl; void rectangleFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Rectangle * rectangle = new Rectangle(0,0,0,1,2,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Rectangle * rectangle = new Rectangle(0,0,0,1,2,0,0,0,colors/* ColorFloat(1,0,0,1) */); // rectangle->setCenterX(2); // rectangle->setRotationPoint(0,0,0); can.add(rectangle); @@ -36,18 +36,18 @@ void rectangleFunction(Canvas& can) { // rectangle->setHeight(sin(floatVal/90) + 2); // if (rectangle->getWidth() > 2 || rectangle->getWidth() < 1) { // delta *= -1; - // // rectangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // rectangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // rectangle->changeWidthBy(delta); // if (rectangle->getHeight() > 3 || rectangle->getHeight() < 1) { // delta *= -1; - // // rectangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // rectangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // rectangle->changeHeightBy(delta); // if (delta > 0) { // rectangle->setColor(colors); // } else { - // rectangle->setColor(ColorGLfloat(1,0,0,1)); + // rectangle->setColor(RED); // } floatVal += 1; } diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index 6b6373059..08c42fd60 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -10,15 +10,15 @@ using namespace tsgl; void rpFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - RegularPolygon * rp = new RegularPolygon(0,0,0,1,7,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + RegularPolygon * rp = new RegularPolygon(0,0,0,1,7,0,0,0,colors/* ColorFloat(1,0,0,1) */); // rp->setCenterX(2); // rp->setRotationPoint(0,0,0); can.add(rp); @@ -35,13 +35,13 @@ void rpFunction(Canvas& can) { // rp->setRadius(sin(floatVal/90) + 3); // if (rp->getRadius() > 3 || rp->getRadius() < 1) { // delta *= -1; - // rp->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // rp->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // rp->changeRadiusBy(delta); // if (delta > 0) { // rp->setColor(colors); // } else { - // rp->setColor(ColorGLfloat(1,0,0,1)); + // rp->setColor(RED); // } floatVal += 1; } diff --git a/src/tests/testShakerSort.cpp b/src/tests/testShakerSort.cpp new file mode 100644 index 000000000..f239971d5 --- /dev/null +++ b/src/tests/testShakerSort.cpp @@ -0,0 +1,120 @@ +/* + * testShakerSort.cpp + * + * Usage: ./testShakerSort + */ + +#include + +using namespace tsgl; + +/*! + * \brief Provides a visualization for a basic (and slow) shaker sort. + * \details + * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. + * - An integer array of size \b SIZE is allocated. + * - A flag \b goingUp is set. + * - Our integer array is filled with random integers under the Canvas' height. + * - The background color is set to gray for visibility. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - While the Canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - If the minimum sorted element is greater than or equals the maximum, we're done. + * - At a rate of \b IPF times a second: + * - If we're going up and the element above us is less than us, swap. + * - If we're going down and the element below us is less than us, swap. + * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. + * . + * - Pause the animation. + * - Clear the Canvas. + * - From 0 to \b SIZE: + * - Get the height of each element in the integer array. + * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. + * . + * - Resume the animation. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void shakerSortFunction(Canvas& can) { + const int SIZE = 550, // Size of the data pool (set to 550 by default) + IPF = 50; // Iterations per frame + Rectangle* rectangles[SIZE]; // Array to store the data + float numbers[SIZE]; // Array to store the data + int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; + float temp; + bool goingUp = true; + for (int i = 0; i < SIZE; i++) { + rectangles[i] = new Rectangle(-3.75 + ((float) i * SIZE / 40000), 0, 0, 0.0075, (float) (saferand(1,200000)) / 50000/* (float) (saferand() % (can.getWindowHeight()) ) / 200 */, 0, 0, 0, RED); + numbers[i] = rectangles[i]->getHeight(); + rectangles[i]->displayOutlineEdges(false); + can.add(rectangles[i]); + } + can.setBackgroundColor(GRAY); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + if (min >= max) { // We are done sorting. + // If we don't call wait(), we segfault. If we call return instead, rectangles[] doesn't get deallocated. + // return would be fine if we hadn't allocated memory in this method to which Canvas needed access. + can.wait(); + } + for (int i = 0; i < IPF; i++) { + if (goingUp) { + if (numbers[pos] > numbers[pos + 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos + 1];; + numbers[pos + 1] = temp; + lastSwap = pos; + } + if (pos >= max) { + pos = max; + max = (lastSwap < max) ? lastSwap : max - 1; + goingUp = !goingUp; + } else + pos++; + } else { + if (numbers[pos] < numbers[pos - 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos - 1]; + numbers[pos - 1] = temp; + lastSwap = pos; + } + if (pos <= min) { + pos = min; + min = (lastSwap > min) ? lastSwap : min + 1; + goingUp = !goingUp; + } else + pos--; + } + } + // float start = 50, width = 1, height; + // int cwh = can.getWindowHeight() - 20; + ColorFloat color; + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + // can.clearProcedural(); + for (int i = 0; i < SIZE; i++/* , start += width * 2 */) { + color = (i == pos) ? YELLOW : RED; + rectangles[i]->setColor(color); + rectangles[i]->setHeight(numbers[i]); + // rectangles[i]->setHeight(2); + // height = rectangles[i]->getHeight(); + // can.drawRectangle(start, cwh - height, width, height, color); + } + can.resumeDrawing(); //Tell the Canvas it can resume drawing + } + + for (int i = 0; i < SIZE; i++) { + delete rectangles[i]; + } +} + +//Takes in command line arguments for the window width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid + w = 1200; h = 900; // If not, set the width and height to a default value + } + Canvas c(-1, -1, w, h, "Shaker Sort"); + c.run(shakerSortFunction); +} diff --git a/src/tests/testSmartSort.cpp b/src/tests/testSmartSort.cpp deleted file mode 100644 index f38740953..000000000 --- a/src/tests/testSmartSort.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * testSmartSort.cpp - * - * Usage: ./testSmartSort - */ - -#include -#include - -using namespace tsgl; - -const int MARGIN = 8; // Border for drawing - -enum MergeState { - S_MERGE = 1, - S_SHIFT = 2, - S_WAIT = 3, - S_DONE = 4, - S_HIDE = 5 -}; - -struct sortData { - ColorFloat color; //Color of the thread - MergeState state; //Current state of the threads - int first, last, //Start and end of our block - left, right, //Indices of two numbers to compare - fi, hi, li, //Indices of first middle and last numbers in a set - depth; //Current depth of the merge - int* a; //Array of numbers to sort - int seg, segs; //Current / total segments - int size; - - sortData(int* arr, int f, int l, ColorFloat c) { - fi = hi = li = 0; //Initialize indices - left = right = 0; //Initialize bounds - color = c; //Set the color - a = arr; //Get a pointer to the array we'll be sorting - first = f; //Set the first element we need to worry about - last = l; //Set the last element we need to worry about - depth = 0; //We start at depth 0 - seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment - while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done - ++depth; //Otherwise, increment the depth... - segs *= 2; //...and double the number of segments - } - state = S_SHIFT; //Start Merging - size = 2; - } - - void restart(int l) { - depth = 0; - hi = last; - right = hi+1; - last = li = l; - fi = left = first; - state = S_MERGE; - size *= 2; - } - - void sortStep() { - int tmp, pivot, jump; - switch(state) { - case S_SHIFT: - pivot = jump = segs/2; - fi = first; li = last; - hi = (fi + li) / 2; //Set our half index to the median of our first and last - for (tmp = depth; tmp > 0; --tmp) { - jump /= 2; - if (seg < pivot) { - pivot -= jump; - li = hi; //Set out last index to our old half index - } else { - pivot += jump; - fi = hi+1; //Set out first index to our old half index plus one - } - hi = (fi + li) / 2; //Set our new half index to the median of our first and last - } - left = fi; right = hi+1; - state = S_MERGE; //We're ready to start Merging - break; - case S_MERGE: - if (left > right || right > last) { - seg = 0; //Reset our segment(s) - segs /= 2; //We're now using half as many segments - state = (depth-- == 0) ? S_WAIT : S_SHIFT; - } else if (right > li) { - ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices - } else if (left <= hi && a[left] < a[right]) { - ++left; - } else { - tmp = a[right]; - for (int x = right; x > left; --x) - a[x] = a[x-1]; - a[left] = tmp; - ++left; ++right; ++hi; - } - break; - default: - break; - } - } -}; - -/*! - * \brief Visualization of the bottom-up mergesort algorithm. - * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. - * \details Uses lines to represent the items being sorted. - * \details At the start, the items being sorted are all divided. - * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. - * \details Different colors represent different sections being sorted. - * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. - */ -void smartSortFunction(Canvas& can, int threads, int size) { - const int IPF = 1; // Iterations per frame - int* numbers = new int[size]; // Array to store the data - for (int i = 0; i < size; i++) - numbers[i] = rand() % (can.getWindowHeight() - MARGIN); - - int bs = size / threads; - int ex = size % threads; - sortData** sd = new sortData*[threads]; - int f = 0; - int l = (ex == 0) ? bs-1 : bs; - for (int i = 0; i < threads; ++i) { - sd[i] = new sortData(numbers,f,l,Colors::highContrastColor(i)); - f = l+1; - if (i < ex-1) l += (bs + 1); - else l += bs; - } - while (can.isOpen()) { - #pragma omp parallel num_threads(threads) - { - int tid = omp_get_thread_num(); - can.sleep(); - if (sd[tid]->state == S_WAIT) { //Merge waiting threads - if ((tid % sd[tid]->size) > 0) - sd[tid]->state = S_DONE; - else { - int next = tid+sd[tid]->size/2; - if (next < threads && sd[next]->state == S_DONE) { - sd[next]->state = S_HIDE; - sd[tid]->restart(sd[next]->last); - } - } - } - for (int i = 0; i < IPF; i++) - sd[tid]->sortStep(); - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - int start = MARGIN/2 + sd[tid]->first, height; - int cwh = can.getWindowHeight() - MARGIN/2; - ColorFloat color; - if (sd[tid]->state != S_HIDE) { - //Draw a black rectangle over our portion of the screen to cover up the old drawing - can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); - for (int i = sd[tid]->first; i < sd[tid]->last; ++i, ++start) { - height = numbers[i]; - if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) - color = WHITE; - else { - if (i == sd[tid]->right || i == sd[tid]->left) - color = WHITE; - else if (i < sd[tid]->left) - color = sd[tid]->color; - else if (i >= sd[tid]->fi && i <= sd[tid]->li) - color = Colors::blend(sd[tid]->color, WHITE, 0.5f); - else - color = Colors::blend(sd[tid]->color, BLACK, 0.5f); - } - can.drawLine(start, cwh - height, start, cwh, color); - } - } - can.resumeDrawing(); //Tell the Canvas it can resume updating - } - } - for (int i = 0; i < threads; ++i) - delete sd[i]; - delete [] sd; - delete [] numbers; -} - -//Takes in command line arguments for the window width and height -//as well as for the number of threads to use -int main(int argc, char* argv[]) { - int s = (argc > 1) ? atoi(argv[1]) : 1024; - if (s < 10) s = 10; - int w = s + MARGIN; - int h = w/2; - - int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); - for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 - - Canvas c(-1, -1, w, h, "Bottom-up Merge Sort"); - c.setBackgroundColor(BLACK); - c.run(smartSortFunction, threads, s); -} diff --git a/src/tests/testSolarSystem.cpp b/src/tests/testSolarSystem.cpp index 079ac11df..302be0b71 100644 --- a/src/tests/testSolarSystem.cpp +++ b/src/tests/testSolarSystem.cpp @@ -10,16 +10,16 @@ using namespace tsgl; void ssFunction(Canvas& can) { - Sphere * sun = new Sphere(0, 0, 0, 0.75, 15, 0.0, 15.0, ColorGLfloat(1,1,0,1)); - Sphere * mercury = new Sphere(0.95, 0, 0, .15, 15, 0.0, 15.0, ColorGLfloat(.8,.55,0,1)); - Sphere * venus = new Sphere(1.4, 0, 0, .25, 15, 0.0, 15.0, ColorGLfloat(1,.8,.5,1)); - Sphere * earth = new Sphere(2.05, 0, 0, .3, 15, 0.0, 15.0, ColorGLfloat(0,0.8,0.3,1)); - Sphere * mars = new Sphere(2.7, 0, 0, .2, 15, 0.0, 15.0, ColorGLfloat(1,.4,0,1)); - Sphere * jupiter = new Sphere(3.45, 0, 0, .5, 15, 0.0, 15.0, ColorGLfloat(1,0.9,.6,1)); - Sphere * saturn = new Sphere(4.45, 0, 0, .4, 15, 0.0, 15.0, ColorGLfloat(.9,.65,.25,1)); - Circle * saturnRings = new Circle(4.45, 0, 0, .7, 15, 0, 75, ColorGLfloat(.9,.8,.3,0.5)); - Sphere * uranus = new Sphere(5.15, 0, 0, .25, 15, 0.0, 15.0, ColorGLfloat(.2,.6,1,1)); - Sphere * neptune = new Sphere(5.75, 0, 0, .2, 15, 0.0, 15.0, ColorGLfloat(.25,.65,1,1)); + Sphere * sun = new Sphere(0, 0, 0, 0.75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(0.95, 0, 0, .15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(1.4, 0, 0, .25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(2.05, 0, 0, .3, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(2.7, 0, 0, .2, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(3.45, 0, 0, .5, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(4.45, 0, 0, .4, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(4.45, 0, 0, .7, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(5.15, 0, 0, .25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(5.75, 0, 0, .2, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); saturnRings->displayOutlineEdges(false); diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index 10c5a2bb8..b564d125f 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -10,14 +10,14 @@ using namespace tsgl; void sphereFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); can.add(testSphere); float rotation = 0.0f; @@ -47,7 +47,7 @@ void sphereFunction(Canvas& can) { // printf("%f\n", rotation*45); if (rotation*45 >= 360) { if (boolean) { - testSphere->setColor(ColorGLfloat(1,0,0,1)); + testSphere->setColor(RED); } else { testSphere->setColor(colors); } diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index afbf159ae..4cb241c9c 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -10,15 +10,15 @@ using namespace tsgl; void squareFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0,0,0,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,1,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Square * square = new Square(0,0,0,1,0,0,0,colors/* ColorFloat(1,0,0,1) */); // square->setCenterX(2); // square->setRotationPoint(0,0,0); can.add(square); @@ -35,13 +35,13 @@ void squareFunction(Canvas& can) { // square->setSideLength(sin(floatVal/90) + 3); // if (square->getSideLength() > 3 || square->getSideLength() < 1) { // delta *= -1; - // // square->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // square->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // square->changeSideLengthBy(delta); // if (delta > 0) { // square->setColor(colors); // } else { - // square->setColor(ColorGLfloat(1,0,0,1)); + // square->setColor(RED); // } floatVal += 1; } diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 0e5f0cf9d..b9e0c279a 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -6,15 +6,15 @@ using namespace tsgl; void starFunction(Canvas& c) { - ColorGLfloat * colors = new ColorGLfloat[400]; - colors[0] = ColorGLfloat(1,0,0,1); + ColorFloat * colors = new ColorFloat[400]; + colors[0] = ColorFloat(1,0,0,1); for(int i = 1; i < 10; i ++) { - // colors[i] = ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); - colors[i] = ColorGLfloat(0,0,1,1); + // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); + colors[i] = ColorFloat(0,0,1,1); } Star * s1 = new Star(0, 0, 0, 1, 5, 0,0,0, colors, true); - // s1->setColor(ColorGLfloat(1,0,0,1)); + // s1->setColor(ColorFloat(1,0,0,1)); c.add(s1); float floatVal = 0.0f; @@ -30,13 +30,13 @@ void starFunction(Canvas& c) { // s1->setRadius(sin(floatVal/90) + 3); // if (s1->getRadius() > 3 || s1->getRadius() < 1) { // delta *= -1; - // // s1->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // s1->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // s1->changeRadiusBy(delta); // if (delta > 0) { // s1->setColor(colors); // } else { - // s1->setColor(ColorGLfloat(1,0,0,1)); + // s1->setColor(ColorFloat(1,0,0,1)); // } floatVal += 1; } diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp index b1c7a5e20..0f38de60f 100644 --- a/src/tests/testTriangle.cpp +++ b/src/tests/testTriangle.cpp @@ -10,15 +10,15 @@ using namespace tsgl; void triangleFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; - Triangle * triangle = new Triangle(-0.5,-0.5,0,0,0.5,0,0.5,-0.5,0,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Triangle * triangle = new Triangle(-0.5,-0.5,0,0,0.5,0,0.5,-0.5,0,0,0,0,colors/* ColorFloat(1,0,0,1) */); // triangle->setCenterX(2); // triangle->setRotationPoint(0,0,0); can.add(triangle); @@ -35,10 +35,10 @@ void triangleFunction(Canvas& can) { if (floatVal < 200) { triangle->setColor(colors); } else { - triangle->setColor(ColorGLfloat(1,0,0,1)); + triangle->setColor(RED); if (floatVal > 400) { floatVal = 0; - triangle->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + triangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); } } floatVal += 1; diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp index 393403145..23b8a3acd 100644 --- a/src/tests/testTriangleStrip.cpp +++ b/src/tests/testTriangleStrip.cpp @@ -10,18 +10,18 @@ using namespace tsgl; void triangleStripFunction(Canvas& can) { - ColorGLfloat colors[] = { ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0,0,1,0.8), - ColorGLfloat(0,1,0,0.8), ColorGLfloat(0,1,1,0.8), ColorGLfloat(1,0,0,0.8), - ColorGLfloat(1,0,1,0.8), ColorGLfloat(1,1,0,0.8), ColorGLfloat(1,1,1,0.8), - ColorGLfloat(0.5,0.5,0.5,0.8), ColorGLfloat(0.5,0.5,1,0.8), - ColorGLfloat(0.5,1,0.5,0.8), ColorGLfloat(0.5,1,1,0.8), ColorGLfloat(1,0.5,0.5,0.8), - ColorGLfloat(1,0.5,1,0.8), ColorGLfloat(1,1,0.5,0.8), ColorGLfloat(0,0,0.5,0.8), - ColorGLfloat(0,0.5,0,0.8), ColorGLfloat(0,0.5,0.5,0.8), ColorGLfloat(0.5,0,0,0.8), - ColorGLfloat(0.5,0,0.5,0.8), ColorGLfloat(0.5,0.5,0,0.8), ColorGLfloat(0.5,0.5,0.5,0.8)}; + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; float x[] = { 0,-0.5,0.5,-0.5,0.5,0 }; float y[] = { -1,-0.5,-0.5,0.5,0.5,1 }; float z[] = { 0,0.5,0.5,0.5,0.5,0 }; - TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors/* ColorGLfloat(1,0,0,1) */); + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors/* RED */); // ts->setCenterX(2); // ts->setRotationPoint(0,0,0); can.add(ts); @@ -38,10 +38,10 @@ void triangleStripFunction(Canvas& can) { // if (floatVal < 200) { // ts->setColor(colors); // } else { - // ts->setColor(ColorGLfloat(1,0,0,1)); + // ts->setColor(RED); // if (floatVal > 400) { // floatVal = 0; - // ts->setEdgeColor(ColorGLfloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // ts->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // } floatVal += 1; From 9fca832569bec5bcc68b10cd83f587dd3a71a64a Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 2 Jun 2020 12:08:41 -0400 Subject: [PATCH 029/105] Sorting tests visually improved --- src/tests/testMergeSort.cpp | 45 ++++++++++++++++++------------------ src/tests/testShakerSort.cpp | 16 ++++++------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp index c96dd9016..96d855061 100644 --- a/src/tests/testMergeSort.cpp +++ b/src/tests/testMergeSort.cpp @@ -9,7 +9,7 @@ using namespace tsgl; -const int MARGIN = 8; // Border for drawing +// const int MARGIN = 8; // Border for drawing enum MergeState { S_MERGE = 1, @@ -114,24 +114,27 @@ struct sortData { void mergeSortFunction(Canvas& can, int threads, int size) { const int IPF = 1; // Iterations per frame float* numbers = new float[size]; // Array to store the data - Line** lines = new Line*[size]; // Array to store the data + Rectangle** rectangles = new Rectangle*[size]; // Array to store the data + float start = -5; + float width = 0.01 * 1024/size; for (int i = 0; i < size; i++) { numbers[i] = (float) (saferand(1,200000)) / 50000; printf("%d: %f\n", i, numbers[i]); - lines[i] = new Line(-5.6 + ((float) i * size / 95000), 0, 0, numbers[i], 90, 0, 0, RED); - can.add(lines[i]); + rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); + rectangles[i]->displayOutlineEdges(false); + can.add(rectangles[i]); } - int bs = size / threads; - int ex = size % threads; + int baseNumVals = size / threads; + int extraVals = size % threads; sortData** sd = new sortData*[threads]; - int f = 0; - int l = (ex == 0) ? bs-1 : bs; + int firstIndex = 0; + int lastIndex = (extraVals == 0) ? baseNumVals-1 : baseNumVals; for (int i = 0; i < threads; ++i) { - sd[i] = new sortData(numbers,f,l,Colors::highContrastColor(i)); - f = l+1; - if (i < ex-1) l += (bs + 1); - else l += bs; + sd[i] = new sortData(numbers,firstIndex,lastIndex,Colors::highContrastColor(i)); + firstIndex = lastIndex+1; + if (i < extraVals-1) lastIndex += (baseNumVals + 1); + else lastIndex += baseNumVals; } while (can.isOpen()) { #pragma omp parallel num_threads(threads) @@ -152,14 +155,12 @@ void mergeSortFunction(Canvas& can, int threads, int size) { for (int i = 0; i < IPF; i++) sd[tid]->sortStep(); can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - int start = MARGIN/2 + sd[tid]->first; float height; - int cwh = can.getWindowHeight() - MARGIN/2; ColorFloat color; if (sd[tid]->state != S_HIDE) { //Draw a black rectangle over our portion of the screen to cover up the old drawing // can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); - for (int i = sd[tid]->first; i < sd[tid]->last; ++i, ++start) { + for (int i = sd[tid]->first; i <= sd[tid]->last; ++i, ++start) { height = numbers[i]; if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) color = WHITE; @@ -173,10 +174,8 @@ void mergeSortFunction(Canvas& can, int threads, int size) { else color = Colors::blend(sd[tid]->color, BLACK, 0.5f); } - lines[i]->setLength(height); - lines[i]->setColor(color); - // lines[i]->setCenterX(start); - // can.drawLine(start, cwh - height, start, cwh, color); + rectangles[i]->setHeight(height); + rectangles[i]->setColor(color); } } can.resumeDrawing(); //Tell the Canvas it can resume updating @@ -187,9 +186,9 @@ void mergeSortFunction(Canvas& can, int threads, int size) { delete [] sd; delete [] numbers; for (int i = 0; i < size; i++) { - delete lines[i]; + delete rectangles[i]; } - delete [] lines; + delete [] rectangles; } //Takes in command line arguments for the window width and height @@ -197,13 +196,13 @@ void mergeSortFunction(Canvas& can, int threads, int size) { int main(int argc, char* argv[]) { int s = (argc > 1) ? atoi(argv[1]) : 1024; if (s < 10) s = 10; - int w = s * 1.3 + MARGIN; + int w = s * 1.3; int h = w/2; int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 - Canvas c(-1, -1, w, h, "Bottom-up Merge Sort"); + Canvas c(0, 0, w, h, "Bottom-up Merge Sort"); c.setBackgroundColor(BLACK); c.run(mergeSortFunction, threads, s); } diff --git a/src/tests/testShakerSort.cpp b/src/tests/testShakerSort.cpp index f239971d5..d98719cb5 100644 --- a/src/tests/testShakerSort.cpp +++ b/src/tests/testShakerSort.cpp @@ -44,8 +44,12 @@ void shakerSortFunction(Canvas& can) { int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; float temp; bool goingUp = true; + printf("%d, %d\n", can.getWindowWidth(), can.getDisplayWidth()); + int canWidth = (can.getWindowWidth() > can.getDisplayWidth()) ? can.getDisplayWidth() : can.getWindowWidth(); + float start = -3.6 * canWidth / 960; + float rectangleWidth = 0.013 * canWidth / 960; for (int i = 0; i < SIZE; i++) { - rectangles[i] = new Rectangle(-3.75 + ((float) i * SIZE / 40000), 0, 0, 0.0075, (float) (saferand(1,200000)) / 50000/* (float) (saferand() % (can.getWindowHeight()) ) / 200 */, 0, 0, 0, RED); + rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, (float) (saferand(1,200000)) / 50000, 0, 0, 0, RED); numbers[i] = rectangles[i]->getHeight(); rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); @@ -87,18 +91,12 @@ void shakerSortFunction(Canvas& can) { pos--; } } - // float start = 50, width = 1, height; - // int cwh = can.getWindowHeight() - 20; ColorFloat color; can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - // can.clearProcedural(); - for (int i = 0; i < SIZE; i++/* , start += width * 2 */) { + for (int i = 0; i < SIZE; i++) { color = (i == pos) ? YELLOW : RED; rectangles[i]->setColor(color); rectangles[i]->setHeight(numbers[i]); - // rectangles[i]->setHeight(2); - // height = rectangles[i]->getHeight(); - // can.drawRectangle(start, cwh - height, width, height, color); } can.resumeDrawing(); //Tell the Canvas it can resume drawing } @@ -113,7 +111,7 @@ int main(int argc, char* argv[]) { int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid - w = 1200; h = 900; // If not, set the width and height to a default value + w = 1300; h = 900; // If not, set the width and height to a default value } Canvas c(-1, -1, w, h, "Shaker Sort"); c.run(shakerSortFunction); From d57077a04a4fd99fef66aa3afab8fd7c13835f49 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 4 Jun 2020 16:02:24 -0400 Subject: [PATCH 030/105] Basic image working, .bmp format only --- Makefile | 2 +- assets/pics/launch.bmp | Bin 0 -> 786488 bytes src/TSGL/Canvas.cpp | 7 + src/TSGL/Canvas.h | 2 +- src/TSGL/Image.cpp | 307 +++++++++++++++++++----------------- src/TSGL/Image.h | 103 ++++++------ src/TSGL/Star.cpp | 12 +- src/TSGL/getBMP.cpp | 77 +++++++++ src/TSGL/getBMP.h | 13 ++ src/tests/testImage.cpp | 43 ++++- src/tests/testMergeSort.cpp | 3 - 11 files changed, 360 insertions(+), 209 deletions(-) create mode 100644 assets/pics/launch.bmp create mode 100644 src/TSGL/getBMP.cpp create mode 100644 src/TSGL/getBMP.h diff --git a/Makefile b/Makefile index 9480c60b1..32f040da8 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,7 @@ BINARIES= \ bin/testDiorama \ bin/testEllipse \ bin/testEllipsoid \ + bin/testImage \ bin/testLines \ bin/testMergeSort \ bin/testPhilosophers \ @@ -116,7 +117,6 @@ BINARIES= \ # bin/testGraydient \ # bin/testGreyscale \ # bin/testHighData \ -# bin/testImage \ # bin/testImageCart \ # bin/testInverter \ # bin/testLangton \ diff --git a/assets/pics/launch.bmp b/assets/pics/launch.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0e397c41b6a1dba8a67aaffd7d51c6135a6fa0e3 GIT binary patch literal 786488 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
^=I~%+eP_6}Kfw^t-x*J4 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

f3#M;^lwY5}X5$o$^ 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%0DjuM}2?N`Nhwaug+s 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%0ACNO0Q-Yh8a(We;XjXGORKh?#8g6(gO0`TJAC`Q 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 VMQ7NdkEXK2U;TIK;JL}<{{d4Y^T_}J literal 0 HcmV?d00001 diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index cde9f4e37..a4568ea3a 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2106,6 +2106,10 @@ void Canvas::initGl() { glfwSetWindowUserPointer(window, this); #endif + // Specify how texture values combine with current surface color values. + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE + + glEnable(GL_TEXTURE_2D); // Enable and disable necessary stuff glEnable(GL_DEPTH_TEST); // Depth Testing glDepthFunc(GL_LEQUAL); @@ -2310,6 +2314,9 @@ void Canvas::initWindow() { glfwSetMouseButtonCallback(window, buttonCallback); glfwSetKeyCallback(window, keyCallback); glfwSetScrollCallback(window, scrollCallback); + // Get info of GPU and supported OpenGL version + printf("Renderer: %s\n", glGetString(GL_RENDERER)); + printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); printf("Exiting initWindow.\n"); } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 089f5230b..36b3aa0f4 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -23,7 +23,7 @@ #include "Circle.h" // Our own class for drawing circles #include "ConcavePolygon.h" // Our own class for concave polygons with colored vertices #include "ConvexPolygon.h" // Our own class for convex polygons with colored vertices -// #include "Image.h" // Our own class for drawing images / textured quads +#include "Image.h" // Our own class for drawing images / textured quads #include "Keynums.h" // Our enums for key presses #include "Line.h" // Our own class for drawing straight lines #include "Polyline.h" // Our own class for drawing polylines diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index a1638ad3a..bd30722a3 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -1,149 +1,170 @@ -// #include "Image.h" - -// namespace tsgl { - -// /*! -// * \brief Explicitly constructs a new Image. -// * \details This is the explicit constructor for the Image class. -// * \param filename The filename of the image to load. -// * \param loader A reference pointer to the TextureHandler with which to load the image. -// * \param x The x coordinate of the left of the Image. -// * \param y The y coordinate of the top of the Image. -// * \param width The width of the Image. -// * \param height The height of the Image. -// * \param alhpa The alpha of the Image. -// * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. -// * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. -// */ -// Image::Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha) { -// isTextured = true; // Let the Canvas know we're a textured object -// myTexture = 0; // Fix no texture initialization warning -// myWidth = width; myHeight = height; -// if (myWidth <= 0 || myHeight <= 0) { -// TextureHandler::getDimensions(filename,myWidth,myHeight); -// } -// myCenterX = x + myWidth / 2; -// myCenterY = y + myHeight / 2; -// setRotationPoint(myCenterX, myCenterY); -// currentRotation = 0; -// myFile = filename; -// myLoader = &loader; -// vertices = new float[32]; -// vertices[0] = x; -// vertices[1] = y; -// vertices[8] = x + myWidth; -// vertices[9] = y; -// vertices[16] = x; -// vertices[17] = y + myHeight; -// vertices[24] = x + myWidth; -// vertices[25] = y + myHeight; -// vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords -// vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; -// vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; -// vertices[5] = vertices[13] = vertices[21] = vertices[29] = alpha; -// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left -// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right -// vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left -// vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right -// } +#include "Image.h" -// /*! -// * \brief Draw the Image. -// * \details This function actually draws the Image to the Canvas. -// */ -// void Image::draw() { -// unsigned int w, h; -// myLoader->loadPicture(myFile, w, h, myTexture); - -// glBindTexture(GL_TEXTURE_2D, myTexture); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); -// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -// } +namespace tsgl { -// /*! -// * \brief Mutator for the center coordinates of the Image. -// * \details Alters the values of the myCenterX and myCenterY private variables. -// * \param x Float value for the new center x-coordinate. -// * \param y Float value for the new center y-coordinate. -// * \warning This will also alter the Image's rotation point if and only if the -// * old rotation point was at the Image's old center. -// */ -// void Image::setCenter(float x, float y) { -// attribMutex.lock(); -// if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { -// setRotationPoint(x, y); -// } -// if(myCenterX != x || myCenterY != y) { -// float deltaX = x - myCenterX; -// float deltaY = y - myCenterY; -// for(int i = 0; i < 4; i++) { -// vertices[8*i] += deltaX; -// vertices[8*i+1] += deltaY; -// } -// myCenterX = x; -// myCenterY = y; -// } -// attribMutex.unlock(); -// } + /*! + * \brief Explicitly constructs a new Image. + * \details This is the explicit constructor for the Image class. + * \param filename The filename of the image to load. + * \param loader A reference pointer to the TextureHandler with which to load the image. + * \param x The x coordinate of the left of the Image. + * \param y The y coordinate of the top of the Image. + * \param width The width of the Image. + * \param height The height of the Image. + * \param alhpa The alpha of the Image. + * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. + * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. + */ +Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll/* , float alpha */) : Drawable(x,y,z,yaw,pitch,roll) { + if (width <= 0 || height <= 0) { + TsglDebug("Cannot have an Image with width or height less than or equal to 0."); + return; + } + myWidth = width; myHeight = height; + myXScale = width; myYScale = height; + numberOfVertices = numberOfOutlineVertices = 4; + myFile = filename; -// /*! -// * \brief Mutator for the coordinates of the Image. -// * \details Alters all coordinate variables for the Image. -// * \param deltaX Float value of how much to alter the y-coordinates. -// * \param deltaY Float value of how much to alter the y-coordinates. -// * \warning This will also alter the Image's rotation point if and only if the -// * old rotation point was at the Image's old center. -// */ -// void Image::moveImageBy(float deltaX, float deltaY) { -// attribMutex.lock(); -// if(myRotationPointX == myCenterX && myRotationPointY == myCenterY) { -// myRotationPointX += deltaX; -// myRotationPointY += deltaY; -// } -// if(deltaX != 0 || deltaY != 0) { -// for(int i = 0; i < 4; i++) { -// vertices[8*i] += deltaX; -// vertices[8*i+1] += deltaY; -// } -// myCenterX += deltaX; -// myCenterY += deltaY; -// } -// attribMutex.unlock(); -// } + // Load the image. + image = getBMP(filename); -// /*! -// * \brief Mutator for the rotation of the Image. -// * \details Rotates the Image corners around myRotationPointX, myRotationPointY. -// * \param radians Float value denoting how many radians to rotate the Image. -// */ -// void Image::setRotation(float radians) { -// if(radians != currentRotation) { -// attribMutex.lock(); -// float pivotX = myRotationPointX; -// float pivotY = myRotationPointY; -// float s = sin(radians - currentRotation); -// float c = cos(radians - currentRotation); -// currentRotation = radians; -// for(int i = 0; i < 4; i++) { -// float x = vertices[8*i]; -// float y = vertices[8*i+1]; -// x -= pivotX; -// y -= pivotY; -// float xnew = x * c - y * s; -// float ynew = x * s + y * c; - -// x = xnew + pivotX; -// y = ynew + pivotY; -// vertices[8*i] = x; -// vertices[8*i+1] = y; -// } -// attribMutex.unlock(); -// } -// } + // create the Image's texture id + glGenTextures(1, &myTexture); + + // vertex allocation and assignment + vertices = new GLfloat[numberOfVertices * 3]; + colors = new GLfloat[numberOfVertices * 4]; + + addVertex(-0.5,-0.5,0,RED); + addVertex(-0.5,0.5,0,BLUE); + addVertex(0.5,0.5,0,CYAN); + addVertex(0.5,-0.5,0,GREEN); +} + + /*! + * \brief Draw the Image. + * \details This function actually draws the Image to the Canvas. + */ +void Image::draw() { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + // enable textures and bind the texture id + glBindTexture(GL_TEXTURE_2D, myTexture); + + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // actually generate the texture + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image->data); + + // transformation matrix + glPushMatrix(); + glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); + glRotatef(myCurrentYaw, 0, 0, 1); + glRotatef(myCurrentPitch, 0, 1, 0); + glRotatef(myCurrentRoll, 1, 0, 0); + glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); + glScalef(myXScale, myYScale, myZScale); + + // enable necessary states (vertex, color, and texture) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + // link arrays to their respective opengl pointers + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(4, GL_FLOAT, 0, colors); + glTexCoordPointer(2, GL_FLOAT, 0, texcoords); + + // draw the image + glDrawArrays(GL_QUADS, 0, numberOfVertices); + + // pop transformation matrix + glPopMatrix(); + + /* Cleanup states */ + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +} + +void Image::setColor(ColorFloat c[]) { + for (int i = 0; i < numberOfVertices; i++) { + colors[i*4] = c[i].R; + colors[i*4+1] = c[i].G; + colors[i*4+2] = c[i].B; + colors[i*4+3] = c[i].A; + } +} + + +/** + * \brief Mutates the distance from the left side of the Image base to its right side. + * \param width The Image's new width. + */ +void Image::setWidth(GLfloat width) { + if (width <= 0) { + TsglDebug("Cannot have an Image with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = width; + myXScale = width; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the left side of the Image base to its right side by the parameter amount. + * \param delta The amount by which to change the width of the Image. + */ +void Image::changeWidthBy(GLfloat delta) { + if (myWidth + delta <= 0) { + TsglDebug("Cannot have an Image with width less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth += delta; + myXScale += delta; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the top side of the Image base to its bottom side. + * \param height The Image's new height. + */ +void Image::setHeight(GLfloat height) { + if (height <= 0) { + TsglDebug("Cannot have an Image with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myWidth = height; + myYScale = height; + attribMutex.unlock(); +} + +/** + * \brief Mutates the distance from the top side of the Image base to its bottom side by the parameter amount. + * \param delta The amount by which to change the height of the Image. + */ +void Image::changeHeightBy(GLfloat delta) { + if (myHeight + delta <= 0) { + TsglDebug("Cannot have an Image with height less than or equal to 0."); + return; + } + attribMutex.lock(); + myHeight += delta; + myYScale += delta; + attribMutex.unlock(); +} // /*! // * \brief Alters the file the Image draws. @@ -170,4 +191,4 @@ // attribMutex.unlock(); // } -// } +} diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index 67b5b3a0d..659ca7075 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -1,67 +1,68 @@ -// /* -// * Image.h extends Shape and provides a class for drawing an image to a Canvas. -// */ +/* + * Image.h extends Drawable and provides a class for drawing an image to a Canvas. + */ -// #ifndef IMAGE_H_ -// #define IMAGE_H_ +#ifndef IMAGE_H_ +#define IMAGE_H_ -// #include +#include -// #include "Drawable.h" // For extending our Shape object -// #include "TextureHandler.h" // For loading images -// #include "TsglAssert.h" // For unit testing purposes +#include "Drawable.h" // For extending our Shape object +#include "getBMP.h" +#include "TsglAssert.h" // For unit testing purposes -// namespace tsgl { +namespace tsgl { -// /*! \class Image -// * \brief Draw an image to the Canvas. -// * \details Image is a class which provides a simple interface for loading and drawing images. -// * The Image class currently supports files in the .png, .bmp, and .jpg formats. -// * \note For the time being, there is no way to measure the size of an image once it's loaded. -// * Therefore, the width and height must be specified manually, and stretching may occur if the -// * input dimensions don't match the images actual dimensions. -// * \note Additionally, an ImageLoader must be passed as an argument. This ImageLoader is automatically -// * constructed with the Canvas as the private *loader* variable. At the moment, there is no way to -// * extend Canvas::drawImage() function due to this privatization. -// * \warning Aside from an error message output to stderr, Image gives no indication if an image failed to load. -// */ -// class Image : public Drawable { -// private: -// int myWidth, myHeight; -// float currentRotation; -// float *vertices; -// std::string myFile; -// GLtexture myTexture; -// TextureHandler* myLoader; -// public: -// Image(std::string filename, TextureHandler &loader, int x, int y, int width, int height, float alpha = 1.0f); +/*! \class Image + * \brief Draw an image to the Canvas. + * \details Image is a class which provides a simple interface for loading and drawing images. + * The Image class currently supports files in the .png, .bmp, and .jpg formats. + * \note For the time being, there is no way to measure the size of an image once it's loaded. + * Therefore, the width and height must be specified manually, and stretching may occur if the + * input dimensions don't match the images actual dimensions. + * \warning Aside from an error message output to stderr, Image gives no indication if an image failed to load. + */ +class Image : public Drawable { + private: + imageFile * image; + GLfloat myWidth, myHeight; + std::string myFile; + GLuint myTexture; + GLfloat texcoords[8] = + { + 0, 0, 0, 1, 1, 1, 1, 0 + }; + public: + Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll/* , float alpha = 1.0f */); -// virtual void draw(); + virtual void draw(); -// /*! -// * \brief Accessor for the image's height. -// * \return The height of the Image. -// */ -// int getHeight() { return myHeight; } + /*! + * \brief Accessor for the image's height. + * \return The height of the Image. + */ + GLfloat getHeight() { return myHeight; } -// /*! -// * \brief Accessor for the image's width. -// * \return The width of the Image. -// */ -// int getWidth() { return myWidth; } + /*! + * \brief Accessor for the image's width. + * \return The width of the Image. + */ + GLfloat getWidth() { return myWidth; } -// void setCenter(float x, float y); + void setWidth(GLfloat width); -// void moveImageBy(float deltaX, float deltaY); + void setHeight(GLfloat height); -// virtual void setRotation(float radians); + void changeWidthBy(GLfloat delta); -// void changeFileName(std::string filename, int width = 0, int height = 0); + void changeHeightBy(GLfloat delta); -// ~Image() { delete[] vertices; } + void setColor(ColorFloat c[]); -// }; + ~Image() { glDeleteTextures(1, &myTexture); delete image; } -// } +}; -// #endif /* IMAGE_H_ */ \ No newline at end of file +} + +#endif /* IMAGE_H_ */ \ No newline at end of file diff --git a/src/TSGL/Star.cpp b/src/TSGL/Star.cpp index 845e4eefd..cd7e1473c 100644 --- a/src/TSGL/Star.cpp +++ b/src/TSGL/Star.cpp @@ -16,7 +16,11 @@ namespace tsgl { * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja = false) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } //TODO: maybe take "ninja" out, decide how we want the stars to be attribMutex.lock(); myRadius = radius; @@ -49,7 +53,11 @@ Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, flo * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ -Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja = false) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { +Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja) : ConcavePolygon(x,y,z,points*2,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Star with radius less than or equal to 0."); + return; + } //TODO: maybe take "ninja" out, decide how we want the stars to be attribMutex.lock(); myRadius = radius; diff --git a/src/TSGL/getBMP.cpp b/src/TSGL/getBMP.cpp new file mode 100644 index 000000000..d662b982d --- /dev/null +++ b/src/TSGL/getBMP.cpp @@ -0,0 +1,77 @@ +// Routine to read an uncompressed 24-bit unindexed color RGB BMP file into a +// 32-bit color RGBA image file (alpha values all being set to 1). + +#include + +#include "getBMP.h" + +imageFile *getBMP(std::string fileName) +{ + int offset, // No. of bytes to start of image data in input BMP file. + w, // Width in pixels of input BMP file. + h; // Height in pixels of input BMP file. + + // Initialize imageFile objects. + imageFile *tempStore = new imageFile; // Temporary storage. + imageFile *outRGB = new imageFile; // RGB output file. + imageFile *outRGBA = new imageFile; // RGBA output file. + + // Initialize input stream. + std::ifstream inFile(fileName.c_str(), std::ios::binary); + + // Get start point of image data in input BMP file. + inFile.seekg(10); + inFile.read((char *)&offset, 4); + + // Get image width and height. + inFile.seekg(18); + inFile.read((char *)&w, 4); + inFile.read((char *)&h, 4); + + // Determine the length of padding of the pixel rows + // (each pixel row of a BMP file is 4-byte aligned by padding with zero bytes). + int padding = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; + + // Allocate storage for temporary input file, read in image data from the BMP file, close input stream. + tempStore->data = new unsigned char[(3 * w + padding) * h]; + inFile.seekg(offset); + inFile.read((char *)tempStore->data, (3 * w + padding) * h); + inFile.close(); + + // Set image width and height and allocate storage for image in output RGB file. + outRGB->width = w; + outRGB->height = h; + outRGB->data = new unsigned char[3 * w * h]; + + // Copy data from temporary input file to output RGB file adjusting for padding and performing BGR to RGB conversion. + int tempStorePos = 0; + int outRGBpos = 0; + for (int j = 0; j < h; j++) + for (int i = 0; i < 3 * w; i += 3) + { + tempStorePos = (3 * w + padding) * j + i; + outRGBpos = 3 * w * j + i; + outRGB->data[outRGBpos] = tempStore->data[tempStorePos + 2]; + outRGB->data[outRGBpos + 1] = tempStore->data[tempStorePos + 1]; + outRGB->data[outRGBpos + 2] = tempStore->data[tempStorePos]; + } + + // Set image width and height and allocate storage for image in output RGBA file. + outRGBA->width = w; + outRGBA->height = h; + outRGBA->data = new unsigned char[4 * w * h]; + + // Copy image data from output RGB file to output RGBA file, setting all A values to 1. + for (int j = 0; j < 4 * w * h; j += 4) + { + outRGBA->data[j] = outRGB->data[(j / 4) * 3]; + outRGBA->data[j + 1] = outRGB->data[(j / 4) * 3 + 1]; + outRGBA->data[j + 2] = outRGB->data[(j / 4) * 3 + 2]; + outRGBA->data[j + 3] = 0xFF; + } + + // Release temporary storage and the output RGB file and return the RGBA version. + delete[] tempStore; + delete[] outRGB; + return outRGBA; +} diff --git a/src/TSGL/getBMP.h b/src/TSGL/getBMP.h new file mode 100644 index 000000000..457c8fc0e --- /dev/null +++ b/src/TSGL/getBMP.h @@ -0,0 +1,13 @@ +#ifndef GETBMP_H +#define GETBMP_H + +struct imageFile +{ + int width; + int height; + unsigned char *data; +}; + +imageFile *getBMP(std::string fileName); + +#endif diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index d9af717aa..2918bf6d4 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -17,15 +17,42 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void imageFunction(Canvas& can) { - int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; - can.drawImage("../assets/pics/test.png", 0, 0, ww, hh); - can.drawImage("../assets/pics/ship.bmp", ww, 0, ww, hh); // possibly lost - can.drawImage("../assets/pics/shiprgb.bmp", ww*2, 0, ww, hh); // definitely lost - can.drawImage("../assets/pics/sky_main.jpg", 0, hh, ww, hh); - can.drawImage("../assets/pics/colorfulKeyboard.jpg", ww, hh, ww, hh); - can.drawImage("../assets/pics/cow.jpg", ww*2, hh, ww, hh); + Image * image = new Image(0,0,0,"./assets/pics/launch.bmp", 4,4, 0,0,0); + can.add(image); - can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // image->setCenterX(sin(floatVal/90)); + // image->setCenterY(sin(floatVal/90)); + // image->setCenterZ(sin(floatVal/90)); + // image->setYaw(floatVal); + // image->setPitch(floatVal); + // image->setRoll(floatVal); + // image->setWidth(sin(floatVal/90) + 4); + // image->setHeight(sin(floatVal/90) + 4); + // if (image->getWidth() > 5 || image->getWidth() < 3) { + // delta *= -1; + // } + // image->changeWidthBy(delta); + if (image->getHeight() > 5 || image->getHeight() < 3) { + delta *= -1; + } + image->changeHeightBy(delta); + floatVal += 1; + } + // int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; + // can.drawImage("../assets/pics/test.png", 0, 0, ww, hh); + // can.drawImage("../assets/pics/ship.bmp", ww, 0, ww, hh); // possibly lost + // can.drawImage("../assets/pics/shiprgb.bmp", ww*2, 0, ww, hh); // definitely lost + // can.drawImage("../assets/pics/sky_main.jpg", 0, hh, ww, hh); + // can.drawImage("../assets/pics/colorfulKeyboard.jpg", ww, hh, ww, hh); + // can.drawImage("../assets/pics/cow.jpg", ww*2, hh, ww, hh); + + // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay + + delete image; } //Takes command-line arguments for the width and height of the screen diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp index 96d855061..9cff52d99 100644 --- a/src/tests/testMergeSort.cpp +++ b/src/tests/testMergeSort.cpp @@ -9,8 +9,6 @@ using namespace tsgl; -// const int MARGIN = 8; // Border for drawing - enum MergeState { S_MERGE = 1, S_SHIFT = 2, @@ -119,7 +117,6 @@ void mergeSortFunction(Canvas& can, int threads, int size) { float width = 0.01 * 1024/size; for (int i = 0; i < size; i++) { numbers[i] = (float) (saferand(1,200000)) / 50000; - printf("%d: %f\n", i, numbers[i]); rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); From 996a17b60d6bf4320735a9c4f857d4b962564982 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 5 Jun 2020 12:08:58 -0400 Subject: [PATCH 031/105] All formats support w/ stb. Inconsistent rendering --- src/TSGL/Image.cpp | 41 +++++++++++++++++++++++++++++++++-------- src/TSGL/Image.h | 15 ++++++++++----- src/tests/testImage.cpp | 13 ++++++++----- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index bd30722a3..69660a1d1 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -1,3 +1,9 @@ +// From stb_image.h: +// Do this: +// #define STB_IMAGE_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the implementation. +#define STB_IMAGE_IMPLEMENTATION +#include "stb/stb_image.h" #include "Image.h" namespace tsgl { @@ -5,13 +11,16 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Image. * \details This is the explicit constructor for the Image class. - * \param filename The filename of the image to load. - * \param loader A reference pointer to the TextureHandler with which to load the image. - * \param x The x coordinate of the left of the Image. - * \param y The y coordinate of the top of the Image. + * \param x The x coordinate of the center of the Image. + * \param y The y coordinate of the center of the Image. + * \param z The z coordinate of the center of the Image. + * \param filename The filename of the image to load, a std::string * \param width The width of the Image. * \param height The height of the Image. - * \param alhpa The alpha of the Image. + * \param yaw The yaw orientation of the Image. + * \param pitch The pitch orientation of the Image. + * \param roll The roll orientation of the Image. + * \param alpha The alpha of the Image. * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. */ @@ -26,7 +35,15 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf myFile = filename; // Load the image. - image = getBMP(filename); + // image = getBMP(filename); + stbi_set_flip_vertically_on_load(true); + data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); + assert(data); + if (!data) + { + TsglDebug("Failed to load texture"); + } + glEnable(GL_TEXTURE_2D); // create the Image's texture id glGenTextures(1, &myTexture); @@ -62,8 +79,9 @@ void Image::draw() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // actually generate the texture - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image->data); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelWidth, pixelHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); // transformation matrix glPushMatrix(); @@ -191,4 +209,11 @@ void Image::changeHeightBy(GLfloat delta) { // attribMutex.unlock(); // } +Image::~Image() { + glDeleteTextures(1, &myTexture); + // delete image; + stbi_image_free(data); +} + + } diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index 659ca7075..b1127c2be 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -7,8 +7,8 @@ #include -#include "Drawable.h" // For extending our Shape object -#include "getBMP.h" +#include "Drawable.h" // For extending our Drawable object +// #include "getBMP.h" #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -24,8 +24,10 @@ namespace tsgl { */ class Image : public Drawable { private: - imageFile * image; + // imageFile * image; + unsigned char * data = 0; GLfloat myWidth, myHeight; + GLint pixelWidth, pixelHeight; std::string myFile; GLuint myTexture; GLfloat texcoords[8] = @@ -57,10 +59,13 @@ class Image : public Drawable { void changeHeightBy(GLfloat delta); - void setColor(ColorFloat c[]); + GLint getPixelHeight() { return pixelHeight; } + + GLint getPixelWidth() { return pixelWidth; } - ~Image() { glDeleteTextures(1, &myTexture); delete image; } + void setColor(ColorFloat c[]); + ~Image(); }; } diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 2918bf6d4..83755b888 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -17,9 +17,12 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void imageFunction(Canvas& can) { - Image * image = new Image(0,0,0,"./assets/pics/launch.bmp", 4,4, 0,0,0); + Image * image = new Image(0,0,0,"./assets/pics/launch.bmp", 4,3, 0,0,0); can.add(image); + // image->setHeight((GLfloat)image->getPixelHeight() / 100); + // image->setWidth((GLfloat)image->getPixelWidth() / 100); + float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { @@ -36,10 +39,10 @@ void imageFunction(Canvas& can) { // delta *= -1; // } // image->changeWidthBy(delta); - if (image->getHeight() > 5 || image->getHeight() < 3) { - delta *= -1; - } - image->changeHeightBy(delta); + // if (image->getHeight() > 5 || image->getHeight() < 3) { + // delta *= -1; + // } + // image->changeHeightBy(delta); floatVal += 1; } // int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; From 9f824a3f19556199d0f2d146356ebcd449e608a4 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 5 Jun 2020 13:34:05 -0400 Subject: [PATCH 032/105] Small change, make non-texture colors work again --- src/TSGL/Canvas.cpp | 2 +- src/TSGL/Image.cpp | 3 +++ src/tests/testImage.cpp | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index a4568ea3a..923ba6227 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2109,7 +2109,7 @@ void Canvas::initGl() { // Specify how texture values combine with current surface color values. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE - glEnable(GL_TEXTURE_2D); + // glEnable(GL_TEXTURE_2D); // Enable and disable necessary stuff glEnable(GL_DEPTH_TEST); // Depth Testing glDepthFunc(GL_LEQUAL); diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index 69660a1d1..e4a9fd473 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -67,6 +67,7 @@ void Image::draw() { TsglDebug("Vertex buffer is not full."); return; } + glEnable(GL_TEXTURE_2D); // enable textures and bind the texture id glBindTexture(GL_TEXTURE_2D, myTexture); @@ -112,6 +113,8 @@ void Image::draw() { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); + + glDisable(GL_TEXTURE_2D); } void Image::setColor(ColorFloat c[]) { diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 83755b888..08187083f 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -17,6 +17,12 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void imageFunction(Canvas& can) { + Square * s = new Square(5,0,0,0.5,0,0,0,RED); + can.add(s); + + Pyramid * p = new Pyramid(-5,0,0,5,1,0.5,0,0,0,BLUE); + can.add(p); + Image * image = new Image(0,0,0,"./assets/pics/launch.bmp", 4,3, 0,0,0); can.add(image); From e92aef9182cb7b80c21aa95cb8935a7ac687c8b4 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 10 Jun 2020 17:30:55 -0400 Subject: [PATCH 033/105] Many fixes. Image yet inconsistent. Shaders unused --- assets/pics/lowDimImage.jpg | Bin 0 -> 8415 bytes install-mac | 8 +- src/TSGL/Canvas.cpp | 558 ++++---- src/TSGL/Canvas.h | 31 +- src/TSGL/ConcavePolygon.cpp | 35 - src/TSGL/ConcavePolygon.h | 2 - src/TSGL/Image.cpp | 44 +- src/TSGL/Image.h | 7 +- src/TSGL/TextureHandler.cpp | 1610 ++++++++++++------------ src/TSGL/TextureHandler.h | 156 +-- src/tests/DiningPhilosophers/Table.cpp | 15 +- src/tests/DiningPhilosophers/Table.h | 1 + src/tests/testConcavePolygon.cpp | 16 +- src/tests/testImage.cpp | 55 +- src/tests/testSphere.cpp | 2 +- src/tests/testSquare.cpp | 2 +- src/tests/testStar.cpp | 2 +- 17 files changed, 1341 insertions(+), 1203 deletions(-) create mode 100644 assets/pics/lowDimImage.jpg diff --git a/assets/pics/lowDimImage.jpg b/assets/pics/lowDimImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34171ba09f65f57d8adc22309fe48d9f0846d15a GIT binary patch literal 8415 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 + + syncMutex.lock(); + #ifdef __APPLE__ // leftWindowIndex = 0; windowMutex.lock(); #endif glfwMakeContextCurrent(window); + + realFPS = round(1 / drawTimer->getTimeBetweenSleeps()); + if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; + std::cout.flush(); + + // set it up so draw calls write into the framebuffer + // if (hasEXTFramebuffer) + // glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); + // else + // glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); + // glDrawBuffer(GL_COLOR_ATTACHMENT0); + // Scale to window size GLint windowWidth, windowHeight; glfwGetWindowSize(window, &windowWidth, &windowHeight); glViewport(0, 0, windowWidth, windowHeight); + winWidth = windowWidth; + winHeight = windowHeight; // Draw stuff glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION_MATRIX); + // glMatrixMode(GL_PROJECTION_MATRIX); // glMatrixMode is deprecated, so it's ignored regardless of whether it's called glLoadIdentity(); - gluPerspective( 60, (double)windowWidth / (double)windowHeight, 0.1, 100 ); + gluPerspective( 60, (double)windowWidth / (double)windowHeight, 0.1, 1000 ); - glMatrixMode(GL_MODELVIEW_MATRIX); - glTranslatef(0,0,-5); + // glMatrixMode(GL_MODELVIEW_MATRIX); // glMatrixMode is deprecated, so it's ignored regardless of whether it's called + // based on a gluPerspective angle of 60 (PI/3) + glTranslatef(0,0,(-windowHeight / 2) / tan(PI/6)); /* commented out stuff really only seems to need to be called once per draw cycle tbh */ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); + // glEnableClientState(GL_VERTEX_ARRAY); + // glEnableClientState(GL_COLOR_ARRAY); if (objectBuffer.size() > 0) { for (unsigned int i = 0; i < objectBuffer.size(); i++) { Drawable* d = objectBuffer[i]; - if(d->isProcessed()) { - d->draw(); - } // if(d->isProcessed()) { - // if (!d->getIsTextured()) { - // d->draw(); - // } else { - // textureShaders(true); - // d->draw(); - // textureShaders(false); - // } + // d->draw(); // } + if(d->isProcessed()) { + if (!d->getIsTextured()) { + d->draw(); + } else { + // should be noted that the texture shader programs do literally nothing right now, and need correction. + // calls to stuff like glEnableClientState() override them, it seems. + // but at least they're not causing compilation errors anymore. + // tried fixing them, for image at least, but I think model, view, and projection matrices need work. + textureShaders(true); + d->draw(); + textureShaders(false); + } + } } } else { objectBufferEmpty = true; } /* Cleanup states */ - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + // glDisableClientState(GL_COLOR_ARRAY); + // glDisableClientState(GL_VERTEX_ARRAY); + + // Update our screenBuffer copy with the screen + // glViewport(0,0,winWidth*scaling,winHeight*scaling); + + // set it up so TSGL reads from the framebuffer + // if (hasEXTFramebuffer) + // glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); + // else + // glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, frameBuffer); + // glReadBuffer(GL_COLOR_ATTACHMENT0); + + // screenshots and testing + // read from the framebuffer into the screenbuffer + glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); + if (toRecord > 0) { + screenShot(); + --toRecord; + } + + // actually render everything in the framebuffer to the screen + // glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); + // glDrawBuffer(drawBuffer); + + // textureShaders(true); + // const float vertices[36] = { + // 0, 0, 0,1,1,1,1,0,1, + // winWidth,0, 0,1,1,1,1,1,1, + // 0, winHeight,0,1,1,1,1,0,0, + // winWidth,winHeight,0,1,1,1,1,1,0 + // }; + // glBindTexture(GL_TEXTURE_2D,renderedTexture); + // /* these 5 lines don't seem to do anything */ + // glPixelStorei(GL_UNPACK_ALIGNMENT,4); + // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + // /* next two lines are very essential */ + // glBufferData(GL_ARRAY_BUFFER,36*sizeof(float),vertices,GL_DYNAMIC_DRAW); + // glDrawArrays(GL_TRIANGLE_STRIP,0,4); + // glFlush(); // Flush buffer data to the actual draw buffer + // glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window + + // textureShaders(false); // Update Screen glfwSwapBuffers(window); @@ -1986,18 +2073,18 @@ int Canvas::getWindowY() { void Canvas::glDestroy() { // Free up our resources - // glDetachShader(shaderProgram, shaderFragment); - // glDetachShader(shaderProgram, shaderVertex); - // glDeleteShader(shaderFragment); - // glDeleteShader(shaderVertex); - // glDeleteProgram(shaderProgram); - // glDetachShader(textureShaderProgram, textureShaderFragment); - // glDetachShader(textureShaderProgram, textureShaderVertex); - // glDeleteShader(textureShaderFragment); - // glDeleteShader(textureShaderVertex); - // glDeleteProgram(textureShaderProgram); - // glDeleteBuffers(1, &vertexBuffer); - // glDeleteVertexArrays(1, &vertexArray); + glDetachShader(shaderProgram, shaderFragment); + glDetachShader(shaderProgram, shaderVertex); + glDeleteShader(shaderFragment); + glDeleteShader(shaderVertex); + glDeleteProgram(shaderProgram); + glDetachShader(textureShaderProgram, textureShaderFragment); + glDetachShader(textureShaderProgram, textureShaderVertex); + glDeleteShader(textureShaderFragment); + glDeleteShader(textureShaderVertex); + glDeleteProgram(textureShaderProgram); + glDeleteBuffers(1, &vertexBuffer); + glDeleteVertexArrays(1, &vertexArray); } /*! @@ -2089,9 +2176,7 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti initGlfw(); #ifndef _WIN32 initWindow(); - printf("initGlew disabled.\n"); - printf("Also check glDestroy.\n"); - // initGlew(); + initGlew(); glfwMakeContextCurrent(NULL); // Reset the context #endif } @@ -2109,7 +2194,7 @@ void Canvas::initGl() { // Specify how texture values combine with current surface color values. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE - // glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_2D); // Enable and disable necessary stuff glEnable(GL_DEPTH_TEST); // Depth Testing glDepthFunc(GL_LEQUAL); @@ -2138,126 +2223,127 @@ void Canvas::initGl() { printf("Exiting initGl.\n"); } -// void Canvas::initGlew() { -// // Enable Experimental GLEW to Render Properly -// glewExperimental = GL_TRUE; -// GLenum err = glewInit(); -// if (GLEW_OK != err) { -// // Problem: glewInit failed, something is seriously wrong. -// fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); -// exit(102); -// } - -// hasEXTFramebuffer = false; +void Canvas::initGlew() { + // Enable Experimental GLEW to Render Properly + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (GLEW_OK != err) { + // Problem: glewInit failed, something is seriously wrong. + fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); + exit(102); + } -// GLint n, i; -// glGetIntegerv(GL_NUM_EXTENSIONS, &n); -// for (i = 0; i < n; i++) { -// std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); -// if (s == "GL_EXT_framebuffer_object") { -// hasEXTFramebuffer = true; -// break; -// } -// } -// const GLubyte* gfxVendor = glGetString(GL_VENDOR); -// std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); -// atiCard = (gfx.find("ATI") != std::string::npos); -// // #define DEBUG -// #ifdef DEBUG -// printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); -// printf("OpenGL version: %s\n", glGetString(GL_VERSION)); -// printf("GLFW version: %s\n", glfwGetVersionString()); -// printf("GL Extension: "); -// for (i = 0; i < n; i++) -// printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); -// if (hasEXTFramebuffer) -// TsglDebug("EXT Framebuffer available"); -// #endif - -// GLint status; - -// // Create and bind our Vertex Array Object -// glGenVertexArrays(1, &vertexArray); -// glBindVertexArray(vertexArray); - -// // Create and bind our Vertex Buffer Object -// glGenBuffers(1, &vertexBuffer); -// glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - -// // Create / compile vertex shader -// shaderVertex = glCreateShader(GL_VERTEX_SHADER); -// glShaderSource(shaderVertex, 1, &vertexSource, NULL); -// glCompileShader(shaderVertex); -// glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); - -// // Create / compile fragment shader -// shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); -// glShaderSource(shaderFragment, 1, &fragmentSource, NULL); -// glCompileShader(shaderFragment); -// glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); - -// // Attach both shaders to a shader program, link the program -// shaderProgram = glCreateProgram(); -// glAttachShader(shaderProgram, shaderVertex); -// glAttachShader(shaderProgram, shaderFragment); -// glBindFragDataLocation(shaderProgram, 0, "outColor"); - -// // Specify the layout of the vertex data in our standard shader -// glLinkProgram(shaderProgram); - -// // Create / compile textured vertex shader -// textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); -// glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); -// glCompileShader(textureShaderVertex); -// glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); - -// // Create / compile textured fragment shader -// textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); -// glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); -// glCompileShader(textureShaderFragment); -// glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); - -// // Attach both shaders to another shader program, link the program -// textureShaderProgram = glCreateProgram(); -// glAttachShader(textureShaderProgram, textureShaderVertex); -// glAttachShader(textureShaderProgram, textureShaderFragment); -// glBindFragDataLocation(textureShaderProgram, 0, "outColor"); - -// // Specify the layout of the vertex data in our textured shader -// glLinkProgram(textureShaderProgram); -// textureShaders(false); - -// /****** NEW ******/ -// // Create a framebuffer -// frameBuffer = 0; -// glGenFramebuffersEXT(1, &frameBuffer); -// if (hasEXTFramebuffer) -// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); -// else -// glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); -// // The texture we're going to render to -// glGenTextures(1, &renderedTexture); -// // "Bind" the newly created texture : all future texture functions will modify this texture -// glBindTexture(GL_TEXTURE_2D, renderedTexture); -// // Give an empty image to OpenGL ( the last "0" ) -// // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems -// glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); -// // Poor filtering. Needed ! -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// // Set "renderedTexture" as our colour attachement #0 -// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); -// // Set the list of draw buffers. -// GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; -// glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers -// // Always check that our framebuffer is ok -// if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) -// TsglErr("FRAMEBUFFER CREATION FAILED"); - -// glBindFramebuffer(GL_FRAMEBUFFER, 0); -// } + // hasEXTFramebuffer = false; + + // GLint n, i; + // glGetIntegerv(GL_NUM_EXTENSIONS, &n); + // for (i = 0; i < n; i++) { + // std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); + // if (s == "GL_EXT_framebuffer_object") { + // hasEXTFramebuffer = true; + // break; + // } + // } + const GLubyte* gfxVendor = glGetString(GL_VENDOR); + std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); + atiCard = (gfx.find("ATI") != std::string::npos); +// #define DEBUG + #ifdef DEBUG + printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + printf("GLFW version: %s\n", glfwGetVersionString()); + printf("GL Extension: "); + for (i = 0; i < n; i++) + printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); + // if (hasEXTFramebuffer) + // TsglDebug("EXT Framebuffer available"); + #endif + + GLint status; + + // Create and bind our Vertex Array Object + glGenVertexArrays(1, &vertexArray); + glBindVertexArray(vertexArray); + + // Create and bind our Vertex Buffer Object + glGenBuffers(1, &vertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); + + // Create / compile vertex shader + shaderVertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(shaderVertex, 1, &vertexSource, NULL); + glCompileShader(shaderVertex); + glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); + + // Create / compile fragment shader + shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(shaderFragment, 1, &fragmentSource, NULL); + glCompileShader(shaderFragment); + glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); + + // Attach both shaders to a shader program, link the program + shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, shaderVertex); + glAttachShader(shaderProgram, shaderFragment); + glBindFragDataLocation(shaderProgram, 0, "outColor"); + + // Specify the layout of the vertex data in our standard shader + glLinkProgram(shaderProgram); + + // Create / compile textured vertex shader + textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); + glCompileShader(textureShaderVertex); + glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); + + // Create / compile textured fragment shader + textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); + glCompileShader(textureShaderFragment); + glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); + + // Attach both shaders to another shader program, link the program + textureShaderProgram = glCreateProgram(); + glAttachShader(textureShaderProgram, textureShaderVertex); + glAttachShader(textureShaderProgram, textureShaderFragment); + glBindFragDataLocation(textureShaderProgram, 0, "outColor"); + + // Specify the layout of the vertex data in our textured shader + glLinkProgram(textureShaderProgram); + textureShaders(false); + + /****** NEW ******/ + // Create a framebuffer + // frameBuffer = 0; + // glGenFramebuffersEXT(1, &frameBuffer); + // if (hasEXTFramebuffer) + // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); + // else + // glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); + // std::cout << glGetError() << std::endl; + // // The texture we're going to render to + // glGenTextures(1, &renderedTexture); + // // "Bind" the newly created texture : all future texture functions will modify this texture + // glBindTexture(GL_TEXTURE_2D, renderedTexture); + // // Give an empty image to OpenGL ( the last "0" ) + // // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems + // glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); + // // Poor filtering. Needed ! + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // // Set "renderedTexture" as our colour attachement #0 + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); + // // Set the list of draw buffers. + // GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + // glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers + // // Always check that our framebuffer is ok + // if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + // TsglErr("FRAMEBUFFER CREATION FAILED"); + + // glBindFramebuffer(GL_FRAMEBUFFER, 0); +} void Canvas::initGlfw() { if (!glfwIsReady) { @@ -2283,9 +2369,9 @@ void Canvas::initWindow() { // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window - // glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer + glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer - // glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); glfwMutex.lock(); // GLFW crashes if you try to make more than once window at once @@ -2308,7 +2394,7 @@ void Canvas::initWindow() { glfwSetWindowPos(window, monitorX, monitorY); glfwMakeContextCurrent(window); - // glfwShowWindow(window); // Show the window + glfwShowWindow(window); // Show the window glfwSetWindowUserPointer(window, this); glfwSetMouseButtonCallback(window, buttonCallback); @@ -2511,7 +2597,7 @@ void Canvas::screenShot() { char filename[25]; sprintf(filename, "Image%06d.png", frameCounter); // TODO: Make this save somewhere not in root - // loader.saveImageToFile(filename, screenBuffer, winWidthPadded, winHeight); + loader.saveImageToFile(filename, screenBuffer, winWidthPadded, winHeight); } void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { @@ -2666,47 +2752,47 @@ void Canvas::takeScreenShot() { if (toRecord == 0) toRecord = 1; } -// void Canvas::textureShaders(bool on) { -// GLint program; -// if (!on) { -// program = shaderProgram; +void Canvas::textureShaders(bool on) { + GLint program; + if (!on) { + program = shaderProgram; -// // Relocate the shader attributes -// GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); -// glEnableVertexAttribArray(posAttrib); -// glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 0); -// GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); -// glEnableVertexAttribArray(colAttrib); -// glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) (2 * sizeof(float))); + // Relocate the shader attributes + GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0); + GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*) (3 * sizeof(float))); -// } else { -// program = textureShaderProgram; - -// // Relocate the shader attributes -// GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); -// glEnableVertexAttribArray(texturePosAttrib); -// glVertexAttribPointer(texturePosAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); -// GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); -// glEnableVertexAttribArray(textureColAttrib); -// glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), -// (void*) (2 * sizeof(float))); -// GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); -// glEnableVertexAttribArray(textureTexAttrib); -// glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), -// (void*) (6 * sizeof(float))); -// } + } else { + program = textureShaderProgram; + + // Relocate the shader attributes + GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); + glEnableVertexAttribArray(texturePosAttrib); + glVertexAttribPointer(texturePosAttrib, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0); + GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); + glEnableVertexAttribArray(textureColAttrib); + glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(float), + (void*) (3 * sizeof(float))); + GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); + glEnableVertexAttribArray(textureTexAttrib); + glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(float), + (void*) (7 * sizeof(float))); + } -// // Reallocate the shader program for use -// glUseProgram(program); + // Reallocate the shader program for use + glUseProgram(program); -// // Recompute the camera matrices -// uniModel = glGetUniformLocation(program, "model"); -// uniView = glGetUniformLocation(program, "view"); -// uniProj = glGetUniformLocation(program, "proj"); + // Recompute the camera matrices + uniModel = glGetUniformLocation(program, "model"); + uniView = glGetUniformLocation(program, "view"); + uniProj = glGetUniformLocation(program, "proj"); -// // Update the camera -// setupCamera(); -// } + // Update the camera + setupCamera(); +} /*! * \brief Waits for the user to close the Canvas. diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 36b3aa0f4..96c28dab4 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -37,6 +37,7 @@ // #include "Text.h" // Our own class for drawing text #include "Timer.h" // Our own timer for steady FPS #include "Triangle.h" // Our own class for drawing triangles +#include "TextureHandler.h" // Currently used for screenshots, might change this #include "Util.h" // Needed constants and has cmath for performing math operations #include // For callback upon key presses @@ -86,14 +87,14 @@ class Canvas { unsigned bufferSize; // Size of the screen buffer std::string defaultFontFileName; Timer* drawTimer; // Timer to regulate drawing frequency - GLuint frameBuffer; // Target buffer for rendering to renderedTexture + // GLuint frameBuffer; // Target buffer for rendering to renderedTexture int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) bool hasBackbuffer; // Whether or not the hardware supports double-buffering - bool hasEXTFramebuffer; // Whether or not the hard supports EXT FBOs + // bool hasEXTFramebuffer; // Whether or not the hard supports EXT FBOs bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice - // TextureHandler loader; // The ImageLoader that holds all our already loaded textures + TextureHandler loader; // The TextureHandler that holds all our already loaded textures bool loopAround; // Whether our point buffer has looped back to the beginning this int monitorX, monitorY; // Monitor position for upper left corner double mouseX, mouseY; // Location of the mouse once HandleIO() has been called @@ -116,33 +117,33 @@ class Canvas { GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window unsigned proceduralBufferSize; doubleFunction scrollFunction; // Single function object for scrolling - // GLtexture shaderFragment, // Address of the fragment shader - // shaderProgram, // Addres of the shader program to send to the GPU - // shaderVertex; // Address of the vertex shader + GLtexture shaderFragment, // Address of the fragment shader + shaderProgram, // Addres of the shader program to send to the GPU + shaderVertex; // Address of the vertex shader std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread int syncMutexLocked; // Whether the syncMutex is currently locked int syncMutexOwner; // Thread ID of the owner of the syncMutex - // GLtexture textureShaderFragment, // Address of the textured fragment shader - // textureShaderProgram, // Addres of the textured shader program to send to the GPU - // textureShaderVertex; // Address of the textured vertex shader + GLtexture textureShaderFragment, // Address of the textured fragment shader + textureShaderProgram, // Addres of the textured shader program to send to the GPU + textureShaderVertex; // Address of the textured vertex shader bool toClose; // If the Canvas has been asked to close unsigned int toRecord; // To record the screen each frame GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - // GLtexture vertexArray, // Address of GL's array buffer object - // vertexBuffer; // Address of GL's vertex buffer object + GLtexture vertexArray, // Address of GL's array buffer object + vertexBuffer; // Address of GL's vertex buffer object float* vertexData; // The allPoints array GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not std::mutex windowMutex; // (OS X) Mutex for handling window contexts int winHeight; // Height of the Canvas' window std::string winTitle; // Title of the window - int winWidth; // Width of the Canvas' window - int winWidthPadded; // Window width padded to a multiple of 4 (necessary for taking screenshots) + GLint winWidth; // Width of the Canvas' window + GLint winWidthPadded; // Window width padded to a multiple of 4 (necessary for taking screenshots) static int drawBuffer; // Buffer to use for drawing (set to GL_LEFT or GL_RIGHT) static bool glfwIsReady; // Whether or not we have info about our monitor @@ -159,7 +160,7 @@ class Canvas { unsigned int b, std::string title, double timerLength); // Method for initializing the canvas void initGl(); // Initializes the GL things specific to the Canvas - // void initGlew(); // Initialized the GLEW things specific to the Canvas + void initGlew(); // Initialized the GLEW things specific to the Canvas static void initGlfw(); // Initalizes GLFW for all future canvases. void initWindow(); // Initalizes the window specific to the Canvas static void keyCallback(GLFWwindow* window, int key, @@ -174,7 +175,7 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - // void textureShaders(bool state); // Turn textures on or off + void textureShaders(bool state); // Turn textures on or off // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works // static bool testLine(Canvas& can); // Unit tester for lines static bool testAccessors(Canvas& can); // Unit tester for accessor methods diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index 602f99e76..099e9629e 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -75,41 +75,6 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int } } - /*! - * \brief Adds another vertex to a ConcavePolygon. - * \details This function initializes the next vertex in the ConcavePolygon and adds it to a ConcavePolygon buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void ConcavePolygon::addVertex(float x, float y, float z, ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - attribMutex.lock(); - vertices[currentVertex] = x; - vertices[currentVertex + 1] = y; - vertices[currentVertex + 2] = z; - colors[currentColor] = color.R; - colors[currentColor + 1] = color.G; - colors[currentColor + 2] = color.B; - colors[currentColor + 3] = color.A; - currentVertex += 3; - currentColor += 4; - attribMutex.unlock(); - - if (currentVertex == numberOfVertices*3) { - attribMutex.lock(); - outlineArray = new GLfloat[numberOfOutlineVertices*4]; - std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); - init = true; - attribMutex.unlock(); - } -} - /*! * \brief Draw the ConcavePolygon. * \details This function actually draws the ConcavePolygon to the Canvas. diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index fd5344cc8..29f53d442 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -25,8 +25,6 @@ namespace tsgl { class ConcavePolygon : public Shape { protected: ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll); - - void addVertex(float x, float y, float z, ColorFloat &color); public: ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color); diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index e4a9fd473..16bb5c230 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -1,9 +1,3 @@ -// From stb_image.h: -// Do this: -// #define STB_IMAGE_IMPLEMENTATION -// before you include this file in *one* C or C++ file to create the implementation. -#define STB_IMAGE_IMPLEMENTATION -#include "stb/stb_image.h" #include "Image.h" namespace tsgl { @@ -24,25 +18,21 @@ namespace tsgl { * \return A new Image is drawn with the specified coordinates, dimensions, and transparency. * \note IMPORTANT: In CartesianCanvas, *y* specifies the bottom, not the top, of the image. */ -Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll/* , float alpha */) : Drawable(x,y,z,yaw,pitch,roll) { +Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll, float alpha) : Drawable(x,y,z,yaw,pitch,roll) { if (width <= 0 || height <= 0) { TsglDebug("Cannot have an Image with width or height less than or equal to 0."); return; } + isTextured = true; // Let the Canvas know we're a textured object myWidth = width; myHeight = height; myXScale = width; myYScale = height; numberOfVertices = numberOfOutlineVertices = 4; myFile = filename; // Load the image. - // image = getBMP(filename); stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); - assert(data); - if (!data) - { - TsglDebug("Failed to load texture"); - } + tsglAssert(data, "stbi_load(filename) failed."); glEnable(GL_TEXTURE_2D); // create the Image's texture id @@ -56,6 +46,27 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf addVertex(-0.5,0.5,0,BLUE); addVertex(0.5,0.5,0,CYAN); addVertex(0.5,-0.5,0,GREEN); + // vertices = new GLfloat[36]; + // colors = nullptr; + // outlineArray = nullptr; + + // // vertices = { + // // // x , y ,z, R,G,B,A, txX,txY + // // -0.5,-0.5,0, 1,1,1,1, 0.0,0.0, + // // -0.5, 0.5,0, 1,1,1,1, 0.0,1.0, + // // 0.5, 0.5,0, 1,1,1,1, 1.0,1.0, + // // 0.5,-0.5,0, 1,1,1,1, 1.0,0.0 + // // } + // vertices[0] = vertices[1] = vertices[9] = vertices[28] = -0.5; // x + y + // vertices[10] = vertices[18] = vertices[19] = vertices[27] = 0.5; // x + y + // vertices[2] = vertices[11] = vertices[20] = vertices[29] = 0; // z + // vertices[3] = vertices[12] = vertices[21] = // R + // vertices[4] = vertices[13] = vertices[22] = // G + // vertices[5] = vertices[14] = vertices[23] = // B + // vertices[6] = vertices[15] = vertices[24] = 1;// A + // vertices[7] = vertices[8] = vertices[16] = vertices[35] = 0.0; // texture coord x + y + // vertices[17] = vertices[25] = vertices[26] = vertices[34] = 1.0; // texture coord x + y + // init = true; } /*! @@ -76,13 +87,14 @@ void Image::draw() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture parameters for filtering. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // actually generate the texture + // actually generate the texture + mipmaps glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelWidth, pixelHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); // transformation matrix glPushMatrix(); @@ -104,6 +116,7 @@ void Image::draw() { glTexCoordPointer(2, GL_FLOAT, 0, texcoords); // draw the image + // glBufferData(GL_ARRAY_BUFFER, 36 * sizeof(GLfloat), vertices, GL_DYNAMIC_DRAW); glDrawArrays(GL_QUADS, 0, numberOfVertices); // pop transformation matrix @@ -214,7 +227,6 @@ void Image::changeHeightBy(GLfloat delta) { Image::~Image() { glDeleteTextures(1, &myTexture); - // delete image; stbi_image_free(data); } diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index b1127c2be..7ea1ca741 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -8,7 +8,8 @@ #include #include "Drawable.h" // For extending our Drawable object -// #include "getBMP.h" +#include +// #include "TextureHandler.h" #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -24,7 +25,7 @@ namespace tsgl { */ class Image : public Drawable { private: - // imageFile * image; + // TextureHandler myTH; unsigned char * data = 0; GLfloat myWidth, myHeight; GLint pixelWidth, pixelHeight; @@ -35,7 +36,7 @@ class Image : public Drawable { 0, 0, 0, 1, 1, 1, 1, 0 }; public: - Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll/* , float alpha = 1.0f */); + Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll, float alpha = 1.0f); virtual void draw(); diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index 990b1bb82..cdadb0bf6 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -1,795 +1,817 @@ -// #include "TextureHandler.h" - -// namespace tsgl { - -// //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) -// #ifndef STB_DEFINE -// #define STB_IMAGE_WRITE_IMPLEMENTATION -// #include "stb/stb_image_write.h" -// #define STB_IMAGE_IMPLEMENTATION -// #include "stb/stb_image.h" -// #define STB_DEFINE -// //It may look truly awful....but its an easy way to turn off warnings -// //solely for stb.h. Sorry :'( -// // #pragma GCC diagnostic push -// // #pragma GCC diagnostic ignored "-fpermissive" +#include "TextureHandler.h" + +namespace tsgl { + + //The instructions for the stb library say to define it exactly once in a .c or .cpp file (NOT a .h file) + #ifndef STB_DEFINE + #define STB_IMAGE_WRITE_IMPLEMENTATION + #include "stb/stb_image_write.h" + #define STB_IMAGE_IMPLEMENTATION + #include "stb/stb_image.h" + #define STB_DEFINE +//It may look truly awful....but its an easy way to turn off warnings +//solely for stb.h. Sorry :'( // #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wmissing-field-initializers" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wsign-compare" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wstrict-aliasing" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wwrite-strings" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wtype-limits" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wunused-but-set-variable" -// #pragma GCC diagnostic push -// #pragma GCC diagnostic ignored "-Wunused-result" -// #include "stb/stb.h" -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #pragma GCC diagnostic pop -// #endif - -// //List of default fonts to check for -// #ifndef DEFAULTFONTS -// #define DEFAULTFONTS -// #ifdef _WIN32 -// const char* DEFAULTFONTPATHS[] = { -// "../assets/freefont/FreeSerif.ttf", -// "./assets/freefont/FreeSerif.ttf", -// "./FreeSerif.ttf", -// "C:\\Windows\\Fonts\\ARIALUNI.ttf", -// "C:\\Windows\\Fonts\\ARIAL.ttf", -// "C:\\Windows\\Fonts\\COUR.ttf", -// "C:\\Windows\\Fonts\\COURI.ttf" -// }; -// #endif -// #ifdef __APPLE__ -// const char* DEFAULTFONTPATHS[] = { -// "../assets/freefont/FreeSerif.ttf", -// "./assets/freefont/FreeSerif.ttf", -// "./FreeSerif.ttf", -// "/Library/Fonts/Arial.ttf", -// "/Library/Fonts/Courier New.ttf", -// "/Library/Fonts/Georgia.ttf", -// "/opt/X11/share/fonts/TTF/VeraSe.ttf", -// }; -// #endif -// #ifdef __linux__ -// const char* DEFAULTFONTPATHS[] = { -// "../assets/freefont/FreeSerif.ttf", -// "./assets/freefont/FreeSerif.ttf", -// "./FreeSerif.ttf", -// "/usr/share/fonts/dejavu/DejaVuSerif.ttf", -// "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", -// "/usr/share/fonts/TTF/DejaVuSerif.ttf", -// "/usr/share/fonts/TTF/arial.ttf", -// "/usr/share/fonts/TTF/cour.ttf", -// "/usr/share/fonts/TTF/couri.ttf" -// }; -// #endif -// #endif - -// #define GL_GLEXT_PROTOTYPES - -// /*! -// * \brief Default TextureHandler constructor method. -// * \details This is the default constructor for theTextureHandler Canvas class. -// * \return A new TextureHandler instance. -// */ -// TextureHandler::TextureHandler() { -// fontLibrary = nullptr; -// fontFace = nullptr; -// } - -// /*! -// * \brief TextureHandler destructor method. -// * \details This is the destructor for the TextureHandler class. -// * \details Frees up memory that was allocated to a TextureHandler instance. -// */ -// TextureHandler::~TextureHandler() { -// for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { -// glDeleteTextures(1, &(it->second)); -// } - -// for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { -// FT_Done_Face(it->second); -// } -// FT_Done_FreeType(fontLibrary); -// } - -// void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, -// const unsigned int &width, const unsigned int &height, -// int glMode) { -// // Generate the OpenGL texture object -// glGenTextures(1, &texture); -// glBindTexture(GL_TEXTURE_2D, texture); - -// if (glMode == GL_ALPHA) { -// unsigned char* newBuffer = new unsigned char[width * height * 4]; -// unsigned maxSize = width * height; -// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { -// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; -// } - -// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); -// delete[] newBuffer; -// } else { -// if (glMode == GL_RED) { -// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -// } else { -// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); -// } -// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); -// } - -// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -// } - -// void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { -// // Generate the OpenGL texture object -// GLtexture texture; - -// glGenTextures(1, &texture); -// glBindTexture(GL_TEXTURE_2D, texture); - -// if (glMode == GL_ALPHA) { -// unsigned char* newBuffer = new unsigned char[width * height * 4]; -// unsigned maxSize = width * height; -// for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { -// newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; -// } - -// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); -// delete[] newBuffer; -// } else { -// if (glMode == GL_RED) { -// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -// } else { -// glPixelStorei(GL_UNPACK_ALIGNMENT, 4); -// } -// glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); -// } - -// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - -// float* vertices = new float[32]; -// vertices[0] = x; -// vertices[1] = y + height; -// vertices[8] = x + width; -// vertices[9] = y + height; -// vertices[16] = x + width; -// vertices[17] = y; -// vertices[24] = x; -// vertices[25] = y; -// vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords -// vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; -// vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; -// vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; -// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left -// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right -// vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left -// vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right - -// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); -// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); -// glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - -// glDeleteTextures(1, &texture); - -// delete[] vertices; -// } - -// /*! -// * \brief Draws text. -// * \details Draws the text specified by its parameters onto a Canvas. -// * \param text The UTF-8 encoded string of text to be drawn. -// * \param font_size The size of the text in pixels. -// * \param vertices An array of vertex data for the bonding box of the text. -// * \note vertices will be partially automatically set by drawText() -// * itself in order to draw / kern the text properly, but the color, starting -// * position, and texture coordinates will be left unchanged. -// * \note If no font is loaded before calling this function, TSGL will attempt to locate a -// * default font at ../assets/freefont/FreeMono.ttf. -// * \return True if successful, false otherwise. -// * \bug If the default font cannot be located, TSGL will crash. -// */ -// bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { -// const wchar_t* string = text.c_str(); -// if(fontFace == nullptr) { //If no font is set, load up a default one -// bool found = false; -// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { -// if (fileExists(DEFAULTFONTPATHS[i])) { -// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW -// loadFont(DEFAULTFONTPATHS[i]); -// found = true; -// break; -// } -// } -// if (!found) { -// TsglErr("No suitable fonts found...exiting"); //NEW -// exit(44); -// } -// } - -// FT_GlyphSlot glyph = fontFace->glyph; -// FT_UInt current_glyph_index, previous_glyph_index = 0; -// int penX = vertices[0], -// penY = vertices[1]; - -// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); -// if (error) { -// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); -// return false; -// } - -// bool use_kerning = FT_HAS_KERNING(fontFace); - -// for (unsigned int i = 0; i < text.size(); i++) { -// current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - -// if (use_kerning && previous_glyph_index && current_glyph_index) { -// FT_Vector delta; -// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); -// penX += delta.x >> 6; -// penY += delta.y >> 6; -// } - -// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); -// if (error) { -// fprintf(stderr, "FT_Load_Char failed\n"); -// return false; -// } - -// previous_glyph_index = current_glyph_index; - -// int glMode = GL_ALPHA; - -// char fontMode = glyph->bitmap.pixel_mode; -// if (fontMode == FT_PIXEL_MODE_MONO) -// glMode = GL_RED; -// else if (fontMode == FT_PIXEL_MODE_GRAY) -// glMode = GL_ALPHA; -// else if (fontMode == FT_PIXEL_MODE_LCD) -// glMode = GL_RGB; -// else if (fontMode == FT_PIXEL_MODE_LCD_V) -// glMode = GL_RGB; -// #ifndef _WIN32 -// else if (fontMode == FT_PIXEL_MODE_BGRA) -// glMode = GL_RGBA; -// #endif - -// GLtexture texture; -// createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); -// glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - -// vertices[0] = vertices[16] = penX + glyph->bitmap_left; -// vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; -// vertices[1] = vertices[9] = penY - glyph->bitmap_top; -// vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; - - -// float s = sin(rotation); -// float c = cos(rotation); -// for(int i = 0; i < 4; i++) { -// float x = vertices[8*i]; -// float y = vertices[8*i+1]; -// x -= centerX; -// y -= centerY; -// float xnew = x * c - y * s; -// float ynew = x * s + y * c; - -// x = xnew + centerX; -// y = ynew + centerY; -// vertices[8*i] = x; -// vertices[8*i+1] = y; -// } - -// penX += glyph->advance.x >> 6; -// penY += glyph->advance.y >> 6; - -// glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer -// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character - -// glDeleteTextures(1, &texture); -// } -// return true; -// } - -// /*! -// * \brief Loads a font. -// * \details Loads a font from the library given by filename. -// * \param filename The file name of the font to be loaded. -// * \warning If the font cannot be found then an error message is printed out. -// * \warning If the font library is not correctly installed then an error message is printed out. -// * \warning If the font is not supported then an error message is printed out. -// * \return True if successful, false otherwise. -// */ -// bool TextureHandler::loadFont(const std::string& filename) { -// if (fontLibrary == nullptr) { -// if (FT_Init_FreeType(&fontLibrary)) { -// fprintf(stderr, "An error occurred during freetype font library initialization\n"); -// return false; -// } -// } - -// if(filename == "") { -// fontFace = nullptr; -// return true; -// } - -// if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already -// FT_Face tmp_face; -// int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); -// if (error == FT_Err_Unknown_File_Format) { -// fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" -// "font format is unsupported\n", filename.c_str()); -// return false; -// } else if (error) { -// fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); -// return false; -// } - -// loadedFonts[filename] = tmp_face; -// fontFace = tmp_face; -// FT_Select_Charmap(fontFace , ft_encoding_unicode); -// } else { -// fontFace = loadedFonts[filename]; -// } - -// return true; -// } - -// void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { -// const wchar_t* string = text.c_str(); -// if(fontFace == nullptr) { //If no font is set, load up a default one -// bool found = false; -// for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { -// if (fileExists(DEFAULTFONTPATHS[i])) { -// TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW -// loadFont(DEFAULTFONTPATHS[i]); -// found = true; -// break; -// } -// } -// if (!found) { -// TsglErr("No suitable fonts found...exiting"); //NEW -// exit(44); -// } -// } -// FT_GlyphSlot glyph = fontFace->glyph; -// FT_UInt current_glyph_index, previous_glyph_index = 0; -// int penX = leftX; -// int penY = bottomY; - -// int minX = leftX; -// int minY = bottomY; -// int maxX = leftX; -// int maxY = bottomY; - -// int currentRightX, currentTopY, currentBottomY; - -// bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); -// if (error) { -// fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); -// return; -// } - -// bool use_kerning = FT_HAS_KERNING(fontFace); - -// for (unsigned int i = 0; i < text.size(); i++) { -// current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); - -// if (use_kerning && previous_glyph_index && current_glyph_index) { -// FT_Vector delta; -// FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); -// penX += delta.x >> 6; -// penY += delta.y >> 6; -// } - -// error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); -// if (error) { -// fprintf(stderr, "FT_Load_Char falied\n"); -// return; -// } - -// previous_glyph_index = current_glyph_index; - -// currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; -// currentTopY = penY - glyph->bitmap_top; -// currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; - -// maxX = currentRightX; -// if(currentBottomY > maxY) { -// maxY = currentBottomY; -// } -// if(currentTopY < minY) { -// minY = currentTopY; -// } - -// penX += glyph->advance.x >> 6; -// penY += glyph->advance.y >> 6; -// } - -// centerX = (minX + maxX) / 2; -// centerY = (minY + maxY) / 2; -// } - -// /*! -// * \brief Loads an image. -// * \details Loads a .png, .jpeg, or .bmp image from a file. -// * \param filename The file name of the picture. -// * \param width A reference variable for holding the width of the picture. -// * \param height A reference variable for holding the height of the picture. -// * \param texture A reference variable for holding the texture of the picture. -// * (same as return value) -// * \return The texture that created from the loaded image. -// */ -// GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { -// if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already -// texture = 0; -// std::string extension = filename.substr(filename.find_last_of('.')); -// if (extension == ".png") -// loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); -// else if (extension == ".jpg" || extension == ".jpeg") -// loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); -// else if (extension == ".bmp") -// loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); -// else { -// fprintf(stderr, "File extension not found\n"); -// return 0; -// } -// } else { -// texture = loadedTextures[filename]; -// } - -// return texture; -// } - -// GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const { -// // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself - -// // Data read from the header of the BMP file -// unsigned char header[54]; // Each BMP file begins by a 54-bytes header -// unsigned int imageSize; // = width*height*3 -// // Actual RGB data -// unsigned char * data; - -// // Open the file -// #ifdef _WIN32 -// FILE* file; -// fopen_s(&file, filename, "rb"); -// #else -// FILE* file = fopen(filename, "rb"); -// #endif - -// if (!file) { -// fprintf(stderr, "Can't open %s: no such file\n", filename); -// return 0; -// } - -// if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem -// fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); -// fclose(file); -// return 0; -// } - -// if (header[0] != 'B' || header[1] != 'M') { -// fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); -// fclose(file); -// return 0; -// } - -// imageSize = width = height = 0; -// // Get info out of header as 4 byte unsigned ints -// for (int i = 3; i >= 0; i--) -// imageSize = (imageSize << 8) | header[0x22 + i]; -// for (int i = 3; i >= 0; i--) -// width = (width << 8) | header[0x12 + i]; -// for (int i = 3; i >= 0; i--) -// height = (height << 8) | header[0x16 + i]; - -// int components = imageSize / width / height; - -// // Some BMP files are misformatted, guess missing information -// if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component - -// // Create a buffer -// data = new unsigned char[imageSize]; - -// // Read the actual data from the file into the buffer -// if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem -// fprintf(stderr, "%s: file ended unexpectedly\n", filename); -// fclose(file); -// return 0; -// } - -// //Everything is in memory now, the file can be closed -// fclose(file); - -// char tmp; -// //Reverse the endian-ness of the colors -// if (components == 4) { -// for (unsigned int i = 0; i < imageSize; i += 4) { -// tmp = data[i]; -// data[i] = data[i + 3]; -// data[i + 3] = tmp; -// tmp = data[i + 1]; -// data[i + 1] = data[i + 2]; -// data[i + 2] = tmp; -// } -// } else if (components == 3) { -// for (unsigned int i = 0; i < imageSize; i += 3) { -// tmp = data[i]; -// data[i] = data[i + 1]; -// data[i + 1] = tmp; -// } -// } - -// // Flip the image vertically, since BMPs are loaded bottom to top -// for (unsigned int j = 0; j < height - (height / 2); j++) { -// for (unsigned int i = 0; i < components * width; i++) { -// int s1 = components * width * j + i; -// int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j -// tmp = data[s1]; -// data[s1] = data[s2]; -// data[s2] = tmp; -// } -// } - -// if (components == 3) -// components = GL_RGB; -// else if (components == 4) -// components = GL_RGBA; - -// createGLtextureFromBuffer(texture, data, width, height, components); - -// delete[] data; - -// return texture; -// } - -// /*! -// * \brief Gets the dimensions of an image -// * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. -// * \param filename The file name of the picture. -// * \param width A reference variable for holding the width of the picture. -// * \param height A reference variable for holding the height of the picture. -// * \return The texture that created from the loaded image. -// */ -// void TextureHandler::getDimensions(std::string filename, int &width, int &height) { -// int w = 0, h = 0; -// stbi_info(filename.c_str(), &w, &h, 0); -// width = w; height = h; -// } - -// GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const { -// unsigned char *data; -// int w = 0, h = 0; -// TsglDebug(std::string("Loading ") + filename); -// data = stbi_load(filename, &w, &h, 0, 4); -// assert(data); -// if (!data) { -// TsglErr(std::string("Loading ") + filename + " failed"); -// return texture; -// } -// TsglDebug(std::string("Loading ") + filename + " succeeded"); -// TsglDebug(to_string(w) + "," + to_string(h)); -// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); -// width = w, height = h; -// free(data); -// return texture; -// } - -// GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const { -// unsigned char *data; -// int w = 0, h = 0; -// TsglDebug(std::string("Loading ") + filename); -// data = stbi_load(filename, &w, &h, 0, 4); -// assert(data); -// if (!data) { -// TsglErr(std::string("Loading ") + filename + " failed"); -// return texture; -// } -// TsglDebug(std::string("Loading ") + filename + " succeeded"); -// TsglDebug(to_string(w) + "," + to_string(h)); -// createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); -// width = w, height = h; -// free(data); -// return texture; -// } - -// /*! -// * \brief Saves an Image. -// * \details Saves an Image to file that was captured from a Canvas object. -// * \param filename The name of the file to save the Image to. -// * \param pixels The pixel data for the Image. -// * \param width The width of the Image. -// * \param height The height of the Image. -// * \return True if successful, false otherwise. -// */ -// bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, -// unsigned int width, unsigned int height) const { -// std::string extension = filename.substr(filename.find_last_of('.')); -// bool success = false; -// if (extension == ".png") -// success = saveToPNG(filename.c_str(), pixels, width, height); -// else if (extension == ".jpg" || extension == ".jpeg") -// fprintf(stderr, "JPG saving not implemented yet\n"); -// else if (extension == ".bmp") -// success = saveToBMP(filename.c_str(), pixels, width, height); -// else -// fprintf(stderr, "File extension not found\n"); -// return success; -// } - -// bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { -// unsigned char header[54]; // Each BMP file begins by a 54-bytes header -// unsigned int imageSize = w * h * 3; // Byte-size of the data for the image -// unsigned int totalSize = imageSize + 54; - -// // Open the file -// #ifdef _WIN32 -// FILE* file; -// fopen_s(&file, filename, "wb"); -// #else -// FILE* file = fopen(filename, "wb"); -// #endif - -// if (!file) { -// fprintf(stderr, "Can't open %s: no such file\n", filename); -// return false; -// } - -// unsigned char padding = 4 - (w * 3) % 4; -// if (padding == 4) padding = 0; -// int rawdatasize = (w * 3 + padding) * h; - -// header[0] = 'B'; -// header[1] = 'M'; -// header[2] = (unsigned char) totalSize; -// header[3] = (unsigned char)(totalSize >> 8); -// header[4] = (unsigned char)(totalSize >> 16); -// header[5] = (unsigned char)(totalSize >> 24); -// for (unsigned i = 6; i <= 9; ++i) -// header[i] = 0; -// header[10] = 54; -// for (unsigned i = 11; i <= 13; ++i) -// header[i] = 0; -// header[14] = 40; -// for (unsigned i = 15; i <= 17; ++i) -// header[i] = 0; -// header[18] = (unsigned char) w; -// header[19] = (unsigned char)(w >> 8); -// header[20] = (unsigned char)(w >> 16); -// header[21] = (unsigned char)(w >> 24); -// header[22] = (unsigned char) h; -// header[23] = (unsigned char)(h >> 8); -// header[24] = (unsigned char)(h >> 16); -// header[25] = (unsigned char)(h >> 24); -// header[26] = 1; -// header[27] = 0; -// header[28] = 24; -// header[29] = 0; -// for (unsigned i = 30; i <= 33; ++i) -// header[i] = 0; -// header[34] = (unsigned char) rawdatasize; -// header[35] = (unsigned char)(rawdatasize >> 8); -// header[36] = (unsigned char)(rawdatasize >> 16); -// header[37] = (unsigned char)(rawdatasize >> 24); -// header[38] = 19; -// header[39] = 11; -// header[40] = 0; -// header[41] = 0; -// header[42] = 19; -// header[43] = 11; -// header[44] = 0; -// header[45] = 0; -// for (unsigned i = 46; i <= 53; ++i) -// header[i] = 0; - -// unsigned char *rawdata = new unsigned char[rawdatasize]; - -// unsigned rawpos = 0, datapos = 0; -// for (unsigned j = 0; j < h; ++j) { -// for (unsigned i = 0; i < w; ++i) { -// rawdata[rawpos] = pixels[datapos+2]; -// rawdata[rawpos+1] = pixels[datapos+1]; -// rawdata[rawpos+2] = pixels[datapos]; -// rawpos += 3; -// datapos += 3; -// } -// for (unsigned i = 0; i < padding; ++i) { -// rawdata[rawpos++] = 0; -// } -// } - -// fwrite(header, 54, 1, file); -// fwrite(rawdata, 1, rawdatasize, file); -// fclose(file); - -// delete[] rawdata; - -// return true; -// } - -// bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { -// // Flip the image, since for some reason the library call -// // flips the image upside down when it saves -// for (unsigned int j = 0; j < h - (h / 2); j++) { -// for (unsigned int i = 0; i < 3 * w; i++) { -// int s1 = 3 * w * j + i; -// int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j -// char tmp = pixels[s1]; -// pixels[s1] = pixels[s2]; -// pixels[s2] = tmp; -// } -// } -// stbi_write_png(filename, w, h, 3, pixels, 0); -// return true; -// } - -// //-------------------------Unit testing--------------------------------------------- -// /*! -// * \brief Runs the Unit tests for TextureHandler. -// */ -// void TextureHandler::runTests() { -// TsglDebug("Testing TextureHandler class..."); -// TextureHandler tester; -// tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); -// TsglDebug("Unit tests for TextureHandler complete."); -// std::cout << std::endl; -// } - -// bool TextureHandler::testLoadFont(TextureHandler& test) { -// int passed = 0; //Passed tests -// int failed = 0; //Failed tests -// //Test 1: Loading in the font at the start -// if(test.fontFace == nullptr) { -// test.loadFont("../assets/freefont/FreeMono.ttf"); -// if(test.fontFace != nullptr) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, Loading font for testLoadFont() failed!"); -// } -// } - -// if(passed == 1 && failed == 0) { -// TsglDebug("Unit test for loading in fonts passed!"); -// return true; -// } else { -// TsglErr("This many tests passed for testLoadFont: "); -// std::cout << " " << passed << std::endl; -// TsglErr("This many tests failed for testLoadFont: "); -// std::cout << " " << failed << std::endl; -// return false; -// } -// } -// //----------------------------End Unit testing--------------------------------------- -// } +// #pragma GCC diagnostic ignored "-fpermissive" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + #include "stb/stb.h" +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop + #endif + + //List of default fonts to check for +#ifndef DEFAULTFONTS +#define DEFAULTFONTS +#ifdef _WIN32 + const char* DEFAULTFONTPATHS[] = { + "../assets/freefont/FreeSerif.ttf", + "./assets/freefont/FreeSerif.ttf", + "./FreeSerif.ttf", + "C:\\Windows\\Fonts\\ARIALUNI.ttf", + "C:\\Windows\\Fonts\\ARIAL.ttf", + "C:\\Windows\\Fonts\\COUR.ttf", + "C:\\Windows\\Fonts\\COURI.ttf" + }; +#endif +#ifdef __APPLE__ + const char* DEFAULTFONTPATHS[] = { + "../assets/freefont/FreeSerif.ttf", + "./assets/freefont/FreeSerif.ttf", + "./FreeSerif.ttf", + "/Library/Fonts/Arial.ttf", + "/Library/Fonts/Courier New.ttf", + "/Library/Fonts/Georgia.ttf", + "/opt/X11/share/fonts/TTF/VeraSe.ttf", + }; +#endif +#ifdef __linux__ + const char* DEFAULTFONTPATHS[] = { + "../assets/freefont/FreeSerif.ttf", + "./assets/freefont/FreeSerif.ttf", + "./FreeSerif.ttf", + "/usr/share/fonts/dejavu/DejaVuSerif.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", + "/usr/share/fonts/TTF/DejaVuSerif.ttf", + "/usr/share/fonts/TTF/arial.ttf", + "/usr/share/fonts/TTF/cour.ttf", + "/usr/share/fonts/TTF/couri.ttf" + }; +#endif +#endif + +#define GL_GLEXT_PROTOTYPES + +/*! + * \brief Default TextureHandler constructor method. + * \details This is the default constructor for theTextureHandler Canvas class. + * \return A new TextureHandler instance. + */ +TextureHandler::TextureHandler() { + fontLibrary = nullptr; + fontFace = nullptr; +} + +/*! + * \brief TextureHandler destructor method. + * \details This is the destructor for the TextureHandler class. + * \details Frees up memory that was allocated to a TextureHandler instance. + */ +TextureHandler::~TextureHandler() { + for (TextureMap::iterator it = loadedTextures.begin(); it != loadedTextures.end(); ++it) { + glDeleteTextures(1, &(it->second)); + } + + for (FontMap::iterator it = loadedFonts.begin(); it != loadedFonts.end(); ++it) { + FT_Done_Face(it->second); + } + FT_Done_FreeType(fontLibrary); +} + +void TextureHandler::createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, + const unsigned int &width, const unsigned int &height, + int glMode) { + // Generate the OpenGL texture object + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + if (glMode == GL_ALPHA) { + unsigned char* newBuffer = new unsigned char[width * height * 4]; + unsigned maxSize = width * height; + for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { + newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); + delete[] newBuffer; + } else { + if (glMode == GL_RED) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + } + glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode) { + // Generate the OpenGL texture object + GLtexture texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + if (glMode == GL_ALPHA) { + unsigned char* newBuffer = new unsigned char[width * height * 4]; + unsigned maxSize = width * height; + for (unsigned int i = 0, x = 0; i < maxSize; i++, x += 4) { + newBuffer[x] = newBuffer[x + 1] = newBuffer[x + 2] = newBuffer[x + 3] = buffer[i]; + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, newBuffer); + delete[] newBuffer; + } else { + if (glMode == GL_RED) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + } + glTexImage2D(GL_TEXTURE_2D, 0, glMode, width, height, 0, glMode, GL_UNSIGNED_BYTE, buffer); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + float* vertices = new float[32]; + vertices[0] = x; + vertices[1] = y + height; + vertices[8] = x + width; + vertices[9] = y + height; + vertices[16] = x + width; + vertices[17] = y; + vertices[24] = x; + vertices[25] = y; + vertices[2] = vertices[10] = vertices[18] = vertices[26] = 1.0f; // Texture color of the coords + vertices[3] = vertices[11] = vertices[19] = vertices[27] = 1.0f; + vertices[4] = vertices[12] = vertices[20] = vertices[28] = 1.0f; + vertices[5] = vertices[13] = vertices[21] = vertices[29] = 1.0f; + vertices[6] = vertices[7] = 0.0f; // Texture coords of top left + vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right + vertices[30] = 0.0f, vertices[31] = 1.0f; // Texture coords of bottom left + vertices[22] = vertices[23] = 1.0f; // Texture coords of bottom right + + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDeleteTextures(1, &texture); + + delete[] vertices; +} + +/*! + * \brief Draws text. + * \details Draws the text specified by its parameters onto a Canvas. + * \param text The UTF-8 encoded string of text to be drawn. + * \param font_size The size of the text in pixels. + * \param vertices An array of vertex data for the bonding box of the text. + * \note vertices will be partially automatically set by drawText() + * itself in order to draw / kern the text properly, but the color, starting + * position, and texture coordinates will be left unchanged. + * \note If no font is loaded before calling this function, TSGL will attempt to locate a + * default font at ../assets/freefont/FreeMono.ttf. + * \return True if successful, false otherwise. + * \bug If the default font cannot be located, TSGL will crash. + */ +bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { + const wchar_t* string = text.c_str(); + if(fontFace == nullptr) { //If no font is set, load up a default one + bool found = false; + for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { + if (fileExists(DEFAULTFONTPATHS[i])) { + TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW + loadFont(DEFAULTFONTPATHS[i]); + found = true; + break; + } + } + if (!found) { + TsglErr("No suitable fonts found...exiting"); //NEW + exit(44); + } + } + + FT_GlyphSlot glyph = fontFace->glyph; + FT_UInt current_glyph_index, previous_glyph_index = 0; + int penX = vertices[0], + penY = vertices[1]; + + bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); + if (error) { + fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); + return false; + } + + bool use_kerning = FT_HAS_KERNING(fontFace); + + for (unsigned int i = 0; i < text.size(); i++) { + current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + + if (use_kerning && previous_glyph_index && current_glyph_index) { + FT_Vector delta; + FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); + penX += delta.x >> 6; + penY += delta.y >> 6; + } + + error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); + if (error) { + fprintf(stderr, "FT_Load_Char failed\n"); + return false; + } + + previous_glyph_index = current_glyph_index; + + int glMode = GL_ALPHA; + + char fontMode = glyph->bitmap.pixel_mode; + if (fontMode == FT_PIXEL_MODE_MONO) + glMode = GL_RED; + else if (fontMode == FT_PIXEL_MODE_GRAY) + glMode = GL_ALPHA; + else if (fontMode == FT_PIXEL_MODE_LCD) + glMode = GL_RGB; + else if (fontMode == FT_PIXEL_MODE_LCD_V) + glMode = GL_RGB; +#ifndef _WIN32 + else if (fontMode == FT_PIXEL_MODE_BGRA) + glMode = GL_RGBA; +#endif + + GLtexture texture; + createGLtextureFromBuffer(texture, glyph->bitmap.buffer, glyph->bitmap.width, glyph->bitmap.rows, glMode); + glBindTexture(GL_TEXTURE_2D, texture); // Set the current texture + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + vertices[0] = vertices[16] = penX + glyph->bitmap_left; + vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; + vertices[1] = vertices[9] = penY - glyph->bitmap_top; + vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; + + + float s = sin(rotation); + float c = cos(rotation); + for(int i = 0; i < 4; i++) { + float x = vertices[8*i]; + float y = vertices[8*i+1]; + x -= centerX; + y -= centerY; + float xnew = x * c - y * s; + float ynew = x * s + y * c; + + x = xnew + centerX; + y = ynew + centerY; + vertices[8*i] = x; + vertices[8*i+1] = y; + } + + penX += glyph->advance.x >> 6; + penY += glyph->advance.y >> 6; + + glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character + + glDeleteTextures(1, &texture); + } + return true; +} + +/*! + * \brief Loads a font. + * \details Loads a font from the library given by filename. + * \param filename The file name of the font to be loaded. + * \warning If the font cannot be found then an error message is printed out. + * \warning If the font library is not correctly installed then an error message is printed out. + * \warning If the font is not supported then an error message is printed out. + * \return True if successful, false otherwise. + */ +bool TextureHandler::loadFont(const std::string& filename) { + if (fontLibrary == nullptr) { + if (FT_Init_FreeType(&fontLibrary)) { + fprintf(stderr, "An error occurred during freetype font library initialization\n"); + return false; + } + } + + if(filename == "") { + fontFace = nullptr; + return true; + } + + if (loadedFonts.find(filename) == loadedFonts.end()) { // Load the image if we haven't already + FT_Face tmp_face; + int error = FT_New_Face(fontLibrary, filename.c_str(), 0, &tmp_face); + if (error == FT_Err_Unknown_File_Format) { + fprintf(stderr, "%s: the font file could be opened and read, but it appears that its" + "font format is unsupported\n", filename.c_str()); + return false; + } else if (error) { + fprintf(stderr, "%s: the font file could not be opened and read\n", filename.c_str()); + return false; + } + + loadedFonts[filename] = tmp_face; + fontFace = tmp_face; + FT_Select_Charmap(fontFace , ft_encoding_unicode); + } else { + fontFace = loadedFonts[filename]; + } + + return true; +} + +void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { + const wchar_t* string = text.c_str(); + if(fontFace == nullptr) { //If no font is set, load up a default one + bool found = false; + for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { + if (fileExists(DEFAULTFONTPATHS[i])) { + TsglDebug("No Font set! Now loading from " + std::string(DEFAULTFONTPATHS[i])); //NEW + loadFont(DEFAULTFONTPATHS[i]); + found = true; + break; + } + } + if (!found) { + TsglErr("No suitable fonts found...exiting"); //NEW + exit(44); + } + } + FT_GlyphSlot glyph = fontFace->glyph; + FT_UInt current_glyph_index, previous_glyph_index = 0; + int penX = leftX; + int penY = bottomY; + + int minX = leftX; + int minY = bottomY; + int maxX = leftX; + int maxY = bottomY; + + int currentRightX, currentTopY, currentBottomY; + + bool error = FT_Set_Pixel_Sizes(fontFace, 0, font_size); + if (error) { + fprintf(stderr, "FT_Set_Pixel_Sizes failed\n"); + return; + } + + bool use_kerning = FT_HAS_KERNING(fontFace); + + for (unsigned int i = 0; i < text.size(); i++) { + current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + + if (use_kerning && previous_glyph_index && current_glyph_index) { + FT_Vector delta; + FT_Get_Kerning(fontFace, previous_glyph_index, current_glyph_index, FT_KERNING_DEFAULT, &delta); + penX += delta.x >> 6; + penY += delta.y >> 6; + } + + error = FT_Load_Glyph(fontFace, current_glyph_index, FT_LOAD_RENDER); + if (error) { + fprintf(stderr, "FT_Load_Char falied\n"); + return; + } + + previous_glyph_index = current_glyph_index; + + currentRightX = penX + glyph->bitmap_left + glyph->bitmap.width; + currentTopY = penY - glyph->bitmap_top; + currentBottomY = penY - glyph->bitmap_top + glyph->bitmap.rows; + + maxX = currentRightX; + if(currentBottomY > maxY) { + maxY = currentBottomY; + } + if(currentTopY < minY) { + minY = currentTopY; + } + + penX += glyph->advance.x >> 6; + penY += glyph->advance.y >> 6; + } + + centerX = (minX + maxX) / 2; + centerY = (minY + maxY) / 2; +} + +/*! + * \brief Loads an image. + * \details Loads a .png, .jpeg, or .bmp image from a file. + * \param filename The file name of the picture. + * \param width A reference variable for holding the width of the picture. + * \param height A reference variable for holding the height of the picture. + * \param texture A reference variable for holding the texture of the picture. + * (same as return value) + * \return The texture that created from the loaded image. + */ +GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture) { + if (loadedTextures.find(filename) == loadedTextures.end()) { // Load the image if we haven't already + texture = 0; + // stbi_set_flip_vertically_on_load(true); + // unsigned char * data = stbi_load(filename.c_str(), width, height, 0, 4); + // tsglAssert(data, "stbi_load(filename) failed."); + // glEnable(GL_TEXTURE_2D); + // // create the Image's texture id + // glGenTextures(1, &texture); + // glBindTexture(GL_TEXTURE_2D, texture); + + // // Set texture parameters for wrapping. + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + // // Set texture parameters for filtering. + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // // actually generate the texture + // glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + // GL_RGBA, GL_UNSIGNED_BYTE, data); + // glGenerateMipmap(GL_TEXTURE_2D); + + std::string extension = filename.substr(filename.find_last_of('.')); + if (extension == ".png") + loadedTextures[filename] = loadTextureFromPNG(filename.c_str(), width, height, texture); + else if (extension == ".jpg" || extension == ".jpeg") + loadedTextures[filename] = loadTextureFromJPG(filename.c_str(), width, height, texture); + else if (extension == ".bmp") + loadedTextures[filename] = loadTextureFromBMP(filename.c_str(), width, height, texture); + else { + fprintf(stderr, "File extension not found\n"); + return 0; + } + } else { + texture = loadedTextures[filename]; + } + + return texture; +} + +GLtexture TextureHandler::loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const { + // Adapted from http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself + + // Data read from the header of the BMP file + unsigned char header[54]; // Each BMP file begins by a 54-bytes header + unsigned int imageSize; // = width*height*3 + // Actual RGB data + unsigned char * data; + + // Open the file +#ifdef _WIN32 + FILE* file; + fopen_s(&file, filename, "rb"); +#else + FILE* file = fopen(filename, "rb"); +#endif + + if (!file) { + fprintf(stderr, "Can't open %s: no such file\n", filename); + return 0; + } + + if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem + fprintf(stderr, "%s: not a correct BMP file: header incorrect size\n", filename); + fclose(file); + return 0; + } + + if (header[0] != 'B' || header[1] != 'M') { + fprintf(stderr, "%s: not a correct BMP file: header did not specify BMP type\n", filename); + fclose(file); + return 0; + } + + imageSize = width = height = 0; + // Get info out of header as 4 byte unsigned ints + for (int i = 3; i >= 0; i--) + imageSize = (imageSize << 8) | header[0x22 + i]; + for (int i = 3; i >= 0; i--) + width = (width << 8) | header[0x12 + i]; + for (int i = 3; i >= 0; i--) + height = (height << 8) | header[0x16 + i]; + + int components = imageSize / width / height; + + // Some BMP files are misformatted, guess missing information + if (imageSize == 0) imageSize = width * height * 4; // 4 : one byte for each Red, Green, Blue, and Alpha component + + // Create a buffer + data = new unsigned char[imageSize]; + + // Read the actual data from the file into the buffer + if (fread(data, 1, imageSize, file) != imageSize) { // If not imageSize bytes read : problem + fprintf(stderr, "%s: file ended unexpectedly\n", filename); + fclose(file); + return 0; + } + + //Everything is in memory now, the file can be closed + fclose(file); + + char tmp; + //Reverse the endian-ness of the colors + if (components == 4) { + for (unsigned int i = 0; i < imageSize; i += 4) { + tmp = data[i]; + data[i] = data[i + 3]; + data[i + 3] = tmp; + tmp = data[i + 1]; + data[i + 1] = data[i + 2]; + data[i + 2] = tmp; + } + } else if (components == 3) { + for (unsigned int i = 0; i < imageSize; i += 3) { + tmp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = tmp; + } + } + + // Flip the image vertically, since BMPs are loaded bottom to top + for (unsigned int j = 0; j < height - (height / 2); j++) { + for (unsigned int i = 0; i < components * width; i++) { + int s1 = components * width * j + i; + int s2 = components * width * (height - 1 - j) + i; // This needs to be height *MINUS ONE* minus j + tmp = data[s1]; + data[s1] = data[s2]; + data[s2] = tmp; + } + } + + if (components == 3) + components = GL_RGB; + else if (components == 4) + components = GL_RGBA; + + createGLtextureFromBuffer(texture, data, width, height, components); + + delete[] data; + + return texture; +} + +/*! + * \brief Gets the dimensions of an image + * \details Loads the header of a .png, .jpeg, or .bmp image to read their dimensions. + * \param filename The file name of the picture. + * \param width A reference variable for holding the width of the picture. + * \param height A reference variable for holding the height of the picture. + * \return The texture that created from the loaded image. + */ +void TextureHandler::getDimensions(std::string filename, int &width, int &height) { + int w = 0, h = 0; + stbi_info(filename.c_str(), &w, &h, 0); + width = w; height = h; +} + +GLtexture TextureHandler::loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const { + unsigned char *data; + int w = 0, h = 0; + TsglDebug(std::string("Loading ") + filename); + data = stbi_load(filename, &w, &h, 0, 4); + assert(data); + if (!data) { + TsglErr(std::string("Loading ") + filename + " failed"); + return texture; + } + TsglDebug(std::string("Loading ") + filename + " succeeded"); + TsglDebug(to_string(w) + "," + to_string(h)); + createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); + width = w, height = h; + free(data); + return texture; +} + +GLtexture TextureHandler::loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const { + unsigned char *data; + int w = 0, h = 0; + TsglDebug(std::string("Loading ") + filename); + data = stbi_load(filename, &w, &h, 0, 4); + assert(data); + if (!data) { + TsglErr(std::string("Loading ") + filename + " failed"); + return texture; + } + TsglDebug(std::string("Loading ") + filename + " succeeded"); + TsglDebug(to_string(w) + "," + to_string(h)); + createGLtextureFromBuffer(texture, data, w, h, GL_RGBA); + width = w, height = h; + free(data); + return texture; +} + +/*! + * \brief Saves an Image. + * \details Saves an Image to file that was captured from a Canvas object. + * \param filename The name of the file to save the Image to. + * \param pixels The pixel data for the Image. + * \param width The width of the Image. + * \param height The height of the Image. + * \return True if successful, false otherwise. + */ +bool TextureHandler::saveImageToFile(std::string filename, GLubyte *pixels, + unsigned int width, unsigned int height) const { + std::string extension = filename.substr(filename.find_last_of('.')); + bool success = false; + if (extension == ".png") + success = saveToPNG(filename.c_str(), pixels, width, height); + else if (extension == ".jpg" || extension == ".jpeg") + fprintf(stderr, "JPG saving not implemented yet\n"); + else if (extension == ".bmp") + success = saveToBMP(filename.c_str(), pixels, width, height); + else + fprintf(stderr, "File extension not found\n"); + return success; +} + +bool TextureHandler::saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { + unsigned char header[54]; // Each BMP file begins by a 54-bytes header + unsigned int imageSize = w * h * 3; // Byte-size of the data for the image + unsigned int totalSize = imageSize + 54; + + // Open the file +#ifdef _WIN32 + FILE* file; + fopen_s(&file, filename, "wb"); +#else + FILE* file = fopen(filename, "wb"); +#endif + + if (!file) { + fprintf(stderr, "Can't open %s: no such file\n", filename); + return false; + } + + unsigned char padding = 4 - (w * 3) % 4; + if (padding == 4) padding = 0; + int rawdatasize = (w * 3 + padding) * h; + + header[0] = 'B'; + header[1] = 'M'; + header[2] = (unsigned char) totalSize; + header[3] = (unsigned char)(totalSize >> 8); + header[4] = (unsigned char)(totalSize >> 16); + header[5] = (unsigned char)(totalSize >> 24); + for (unsigned i = 6; i <= 9; ++i) + header[i] = 0; + header[10] = 54; + for (unsigned i = 11; i <= 13; ++i) + header[i] = 0; + header[14] = 40; + for (unsigned i = 15; i <= 17; ++i) + header[i] = 0; + header[18] = (unsigned char) w; + header[19] = (unsigned char)(w >> 8); + header[20] = (unsigned char)(w >> 16); + header[21] = (unsigned char)(w >> 24); + header[22] = (unsigned char) h; + header[23] = (unsigned char)(h >> 8); + header[24] = (unsigned char)(h >> 16); + header[25] = (unsigned char)(h >> 24); + header[26] = 1; + header[27] = 0; + header[28] = 24; + header[29] = 0; + for (unsigned i = 30; i <= 33; ++i) + header[i] = 0; + header[34] = (unsigned char) rawdatasize; + header[35] = (unsigned char)(rawdatasize >> 8); + header[36] = (unsigned char)(rawdatasize >> 16); + header[37] = (unsigned char)(rawdatasize >> 24); + header[38] = 19; + header[39] = 11; + header[40] = 0; + header[41] = 0; + header[42] = 19; + header[43] = 11; + header[44] = 0; + header[45] = 0; + for (unsigned i = 46; i <= 53; ++i) + header[i] = 0; + + unsigned char *rawdata = new unsigned char[rawdatasize]; + + unsigned rawpos = 0, datapos = 0; + for (unsigned j = 0; j < h; ++j) { + for (unsigned i = 0; i < w; ++i) { + rawdata[rawpos] = pixels[datapos+2]; + rawdata[rawpos+1] = pixels[datapos+1]; + rawdata[rawpos+2] = pixels[datapos]; + rawpos += 3; + datapos += 3; + } + for (unsigned i = 0; i < padding; ++i) { + rawdata[rawpos++] = 0; + } + } + + fwrite(header, 54, 1, file); + fwrite(rawdata, 1, rawdatasize, file); + fclose(file); + + delete[] rawdata; + + return true; +} + +bool TextureHandler::saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const { + // Flip the image, since for some reason the library call + // flips the image upside down when it saves + for (unsigned int j = 0; j < h - (h / 2); j++) { + for (unsigned int i = 0; i < 3 * w; i++) { + int s1 = 3 * w * j + i; + int s2 = 3 * w * (h - 1 - j) + i; // This needs to be height *MINUS ONE* minus j + char tmp = pixels[s1]; + pixels[s1] = pixels[s2]; + pixels[s2] = tmp; + } + } + stbi_write_png(filename, w, h, 3, pixels, 0); + return true; +} + +//-------------------------Unit testing--------------------------------------------- +/*! + * \brief Runs the Unit tests for TextureHandler. + */ +void TextureHandler::runTests() { + TsglDebug("Testing TextureHandler class..."); + TextureHandler tester; + tsglAssert(testLoadFont(tester), "Unit test for loading in fonts failed!"); + TsglDebug("Unit tests for TextureHandler complete."); + std::cout << std::endl; +} + +bool TextureHandler::testLoadFont(TextureHandler& test) { + int passed = 0; //Passed tests + int failed = 0; //Failed tests + //Test 1: Loading in the font at the start + if(test.fontFace == nullptr) { + test.loadFont("../assets/freefont/FreeMono.ttf"); + if(test.fontFace != nullptr) { + passed++; + } else { + failed++; + TsglErr("Test 1, Loading font for testLoadFont() failed!"); + } + } + + if(passed == 1 && failed == 0) { + TsglDebug("Unit test for loading in fonts passed!"); + return true; + } else { + TsglErr("This many tests passed for testLoadFont: "); + std::cout << " " << passed << std::endl; + TsglErr("This many tests failed for testLoadFont: "); + std::cout << " " << failed << std::endl; + return false; + } +} +//----------------------------End Unit testing--------------------------------------- +} diff --git a/src/TSGL/TextureHandler.h b/src/TSGL/TextureHandler.h index 1832ef3a0..2017dbf19 100644 --- a/src/TSGL/TextureHandler.h +++ b/src/TSGL/TextureHandler.h @@ -1,94 +1,94 @@ -// /* -// * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. -// */ - -// #ifndef TEXTURELOADER_H_ -// #define TEXTURELOADER_H_ - -// #include -// #include - -// #include FT_FREETYPE_H -// #include FT_GLYPH_H - -// #include // Needed for GL function calls - -// #ifdef _WIN32 -// #include -// #include -// #include -// //#else -// // #include -// // #include -// #endif - -// #include // For GL functions -// #include -// #include -// #include -// #include - -// #include "Error.h" -// #include "TsglAssert.h" // For unit testing purposes -// #include "Util.h" // For testing for the existence of files - -// typedef GLuint GLtexture; - -// namespace tsgl { - -// /*! \class TextureHandler -// * \brief Handles saving, loading, and rendering of images and textures. -// * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas -// * and CartesianCanvas through the use of GLTextures. -// */ -// class TextureHandler { -// private: -// typedef std::unordered_map TextureMap; -// typedef std::unordered_map FontMap; - -// TextureMap loadedTextures; -// FontMap loadedFonts; -// FT_Library fontLibrary; -// FT_Face fontFace; - -// static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, -// const unsigned int &height, int glMode); +/* + * TextureHandler.h provides an interface for loading a variety of image formats and fonts into GL textures. + */ + +#ifndef TEXTURELOADER_H_ +#define TEXTURELOADER_H_ + +#include +#include + +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include // Needed for GL function calls + +#ifdef _WIN32 + #include + #include + #include +//#else +// #include +// #include +#endif + +#include // For GL functions +#include +#include +#include +#include + +#include "Error.h" +#include "TsglAssert.h" // For unit testing purposes +#include "Util.h" // For testing for the existence of files + +typedef GLuint GLtexture; + +namespace tsgl { + +/*! \class TextureHandler + * \brief Handles saving, loading, and rendering of images and textures. + * \details TextureHandler provides an interface for saving, loading, and rendering images and text to Canvas + * and CartesianCanvas through the use of GLTextures. + */ +class TextureHandler { + private: + typedef std::unordered_map TextureMap; + typedef std::unordered_map FontMap; + + TextureMap loadedTextures; + FontMap loadedFonts; + FT_Library fontLibrary; + FT_Face fontFace; + + static void createGLtextureFromBuffer(GLtexture &texture, unsigned char* buffer, const unsigned int &width, + const unsigned int &height, int glMode); -// GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const; -// GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const; -// GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, -// GLtexture &texture) const; + GLtexture loadTextureFromBMP(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const; + GLtexture loadTextureFromJPG(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const; + GLtexture loadTextureFromPNG(const char* filename, unsigned int &width, unsigned int &height, + GLtexture &texture) const; -// bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; -// bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; + bool saveToPNG(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; + bool saveToBMP(const char* filename, GLubyte *pixels, unsigned int w, unsigned int h) const; -// static bool testLoadFont(TextureHandler& test); + static bool testLoadFont(TextureHandler& test); -// public: -// TextureHandler(); + public: + TextureHandler(); -// ~TextureHandler(); + ~TextureHandler(); -// bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); + bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); -// bool loadFont(const std::string& filename); + bool loadFont(const std::string& filename); -// void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); + void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); -// static void getDimensions(std::string filename, int &width, int &height); + static void getDimensions(std::string filename, int &width, int &height); -// GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); + GLtexture loadPicture(std::string filename, unsigned int &width, unsigned int &height, GLtexture &texture); -// bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; + bool saveImageToFile(std::string filename, GLubyte *pixels, unsigned int width, unsigned int height) const; -// void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); + void drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsigned int width, unsigned int height, int glMode); -// static void runTests(); -// }; + static void runTests(); +}; -// } +} -// #endif /* TEXTURELOADER_H_ */ +#endif /* TEXTURELOADER_H_ */ diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index c3c5da8da..f8a9a239c 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -20,10 +20,13 @@ Table::Table(Canvas& can, int p, PhilMethod m) { forks[i].id = i; forks[i].setCanvas(myCan); } - // float delta = 2.0f / numPhils * PI; - // for(int i = 0; i < numPhils; i++) { - // myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); - // } + spaghettis = new Image*[numPhils]; + float delta = 2.0f / numPhils * PI; + for(int i = 0; i < numPhils; i++) { + spaghettis[i] = new Image(0 + 0.8 * cos(i*delta), sin(i*delta), -0.5, "./assets/pics/spaghet.png", 1, 0.5, 0,0,0); + can.add(spaghettis[i]); + // myCan->drawImage("../assets/pics/spaghet.png", -50+(200)*cos(i*delta), -25+(215)*sin(i*delta), 100, 50, 1.0f); + } myMethod = m; switch(myMethod) { case forfeitWhenBlocked: @@ -66,6 +69,10 @@ Table::~Table() { // if (myCan2->isOpen()) // myCan2->stop(); // delete myCan2; + for (int i = 0; i < numPhils; i++) { + delete spaghettis[i]; + } + delete [] spaghettis; delete myTable; delete [] phils; delete [] forks; diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h index e4429afd5..ee81d053e 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/tests/DiningPhilosophers/Table.h @@ -29,6 +29,7 @@ class Table { Philosopher *phils; Fork *forks; Circle * myTable; + Image ** spaghettis; // TextureHandler loader; public: Table(Canvas& can, int p, PhilMethod m); diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp index 2662acd7a..eaaa5e45f 100644 --- a/src/tests/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon.cpp @@ -39,21 +39,21 @@ void concavePolygonFunction(Canvas& can) { yy[0] = 0; for (int i = 0; i < PSIZE-1; ++i) { if (i % 2 == 0) { - xx[i+1] = 0 + 2.5 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 2.5 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); } else { - xx[i+1] = 0 + 1.5 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 1.5 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); } } // for (int i = 0; i < PSIZE; ++i) { // if (i % 2 == 0) { - // xx[i] = 0 + 2.5 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 2.5 * cos((1.0f*i)/(PSIZE) * PI * 2); + // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); // } else { - // xx[i] = 0 + 1.5 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 1.5 * cos((1.0f*i)/(PSIZE) * PI * 2); + // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); // } // } diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 08187083f..72245df1e 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -17,23 +17,55 @@ using namespace tsgl; * \param can Reference to the Canvas being drawn to. */ void imageFunction(Canvas& can) { - Square * s = new Square(5,0,0,0.5,0,0,0,RED); - can.add(s); + int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; + // Square * s = new Square(5,0,0,50,0,0,0,RED); + // can.add(s); - Pyramid * p = new Pyramid(-5,0,0,5,1,0.5,0,0,0,BLUE); - can.add(p); + // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); + // can.add(p); - Image * image = new Image(0,0,0,"./assets/pics/launch.bmp", 4,3, 0,0,0); + // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); + // can.add(image); + + // Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); + // can.add(image); + // Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); + // can.add(image2); + // Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); + // can.add(image3); + // Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); + // can.add(image4); + // Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); + // can.add(image5); + // Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); + // can.add(image6); + + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); can.add(image); + Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + can.add(image2); + Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + can.add(image3); + Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + can.add(image4); + Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + can.add(image5); + Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + can.add(image6); + + // Image * image7 = new Image(0,0,0,"./assets/pics/cow.jpg", 960,480,0,0,0,th); + // can.add(image7); // image->setHeight((GLfloat)image->getPixelHeight() / 100); // image->setWidth((GLfloat)image->getPixelWidth() / 100); float floatVal = 0.0f; GLfloat delta = 0.05; + bool ss = false; while (can.isOpen()) { can.sleep(); // image->setCenterX(sin(floatVal/90)); + // printf("%f\n", image->getCenterX()); // image->setCenterY(sin(floatVal/90)); // image->setCenterZ(sin(floatVal/90)); // image->setYaw(floatVal); @@ -49,6 +81,13 @@ void imageFunction(Canvas& can) { // delta *= -1; // } // image->changeHeightBy(delta); + // printf("%d\n", can.getFrameNumber()); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // ColorInt blah = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); + // printf("%d, %d, %d, %d\n", blah.R, blah.G, blah.B, blah.A); floatVal += 1; } // int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; @@ -62,6 +101,12 @@ void imageFunction(Canvas& can) { // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay delete image; + delete image2; + delete image3; + delete image4; + delete image5; + delete image6; + // delete image7; } //Takes command-line arguments for the width and height of the screen diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index b564d125f..026abb8cd 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -18,7 +18,7 @@ void sphereFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, colors); + Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 250, 0.0, 0.0, 0.0, colors); can.add(testSphere); float rotation = 0.0f; // GLfloat delta = 0.05; diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 4cb241c9c..951c7b16b 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -18,7 +18,7 @@ void squareFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,1,0,0,0,colors/* ColorFloat(1,0,0,1) */); + Square * square = new Square(0,0,0,500,0,0,0,colors/* ColorFloat(1,0,0,1) */); // square->setCenterX(2); // square->setRotationPoint(0,0,0); can.add(square); diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index b9e0c279a..4f3cc6edd 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -13,7 +13,7 @@ void starFunction(Canvas& c) { colors[i] = ColorFloat(0,0,1,1); } - Star * s1 = new Star(0, 0, 0, 1, 5, 0,0,0, colors, true); + Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); // s1->setColor(ColorFloat(1,0,0,1)); c.add(s1); From a461f65a84c2dc4bb82a6139576106d41360c889 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 12 Jun 2020 12:23:08 -0400 Subject: [PATCH 034/105] Fix previous tests for new perspective projection --- Makefile | 3 - src/TSGL/Circle.cpp | 47 +++++++++++-- src/TSGL/Circle.h | 7 ++ src/TSGL/Cone.cpp | 4 +- src/TSGL/Cylinder.cpp | 4 +- src/TSGL/Ellipse.cpp | 39 +++++++++-- src/TSGL/Ellipse.h | 5 ++ src/TSGL/Image.cpp | 4 +- src/tests/DiningPhilosophers/Fork.h | 4 +- src/tests/DiningPhilosophers/Philosopher.cpp | 4 +- src/tests/DiningPhilosophers/Table.cpp | 14 ++-- src/tests/DiningPhilosophers3D/Fork3D.h | 4 +- .../DiningPhilosophers3D/Philosopher3D.cpp | 4 +- src/tests/DiningPhilosophers3D/Table3D.cpp | 12 ++-- src/tests/SeaUrchin/SeaUrchin.cpp | 1 + src/tests/test2Dvs3D.cpp | 14 ++-- src/tests/test3DRotation.cpp | 9 ++- src/tests/testArrows.cpp | 12 ++-- src/tests/testBallroom.cpp | 27 ++++---- src/tests/testCircle.cpp | 35 +++++----- src/tests/testClock.cpp | 26 +++---- src/tests/testCone.cpp | 12 +++- src/tests/testConvexPolygon.cpp | 10 +-- src/tests/testCube.cpp | 18 ++--- src/tests/testCuboid.cpp | 40 +++++------ src/tests/testCylinder.cpp | 6 +- src/tests/testDiorama.cpp | 68 +++++++++---------- src/tests/testEllipse.cpp | 22 +++--- src/tests/testEllipsoid.cpp | 46 ++++++------- src/tests/testImage.cpp | 63 ++++++----------- src/tests/testLines.cpp | 16 ++--- src/tests/testMergeSort.cpp | 6 +- src/tests/testPrism.cpp | 32 ++++----- src/tests/testPyramid.cpp | 34 +++++----- src/tests/testRectangle.cpp | 22 +++--- src/tests/testRegularPolygon.cpp | 18 ++--- src/tests/testShakerSort.cpp | 7 +- src/tests/testSolarSystem.cpp | 21 +++--- src/tests/testSphere.cpp | 18 ++--- src/tests/testSquare.cpp | 16 ++--- src/tests/testStar.cpp | 14 ++-- src/tests/testTriangle.cpp | 10 +-- src/tests/testTriangleStrip.cpp | 16 ++--- 43 files changed, 420 insertions(+), 374 deletions(-) diff --git a/Makefile b/Makefile index 32f040da8..f0a366551 100644 --- a/Makefile +++ b/Makefile @@ -98,13 +98,11 @@ BINARIES= \ bin/testTriangleStrip \ # bin/test_specs \ # bin/testAlphaRectangle \ -# bin/testArrows \ # bin/testAura \ # bin/testBlurImage \ # bin/testCalcPi \ # bin/testColorPoints \ # bin/testColorWheel \ -# bin/testConcavePolygon \ # bin/testConstructors \ # bin/testConway \ # bin/testCosineIntegral \ @@ -135,7 +133,6 @@ BINARIES= \ # bin/testSeaUrchin \ # bin/testSpectrogram \ # bin/testSpectrum \ -# bin/testStar \ # bin/testText \ # bin/testTextCart \ # bin/testTextTwo \ diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 1c4772567..4d5ccbb59 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -12,13 +12,20 @@ namespace tsgl { * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(radius + 5) + 1,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; + edgesOutlined = false; + verticesPerColor = (myRadius + 6) / 8; attribMutex.unlock(); - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { + addVertex(0,0,0,color); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color); } } @@ -33,14 +40,21 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch * \param filled Whether the circle should be filled * (set to true by default). */ -Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,radius * 30,yaw,pitch,roll) { +Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(GLint) (radius + 5) + 1,yaw,pitch,roll) { + if (radius <= 0) { + TsglDebug("Cannot have a Circle with radius less than or equal to 0."); + return; + } attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; + edgesOutlined = false; + verticesPerColor = (myRadius + 6) / 8; attribMutex.unlock(); - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + addVertex(0,0,0,color[0]); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); } } @@ -75,4 +89,23 @@ void Circle::changeRadiusBy(GLfloat delta) { attribMutex.unlock(); } +/** + * \brief Sets the Circle to a new array of colors. + * \param c An array of the new ColorFloats. + */ +void Circle::setColor(ColorFloat c[]) { + colors[0] = c[0].R; + colors[1] = c[0].G; + colors[2] = c[0].B; + colors[3] = c[0].A; + int colorIndex; + for (int i = 1; i < numberOfVertices; ++i) { + colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); + colors[i*4] = c[colorIndex].R; + colors[i*4 + 1] = c[colorIndex].G; + colors[i*4 + 2] = c[colorIndex].B; + colors[i*4 + 3] = c[colorIndex].A; + } +} + } \ No newline at end of file diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index ec9548f54..308180ede 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -16,6 +16,7 @@ namespace tsgl { class Circle : public ConvexPolygon { protected: GLfloat myRadius; + GLfloat verticesPerColor; public: Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color); @@ -31,6 +32,12 @@ class Circle : public ConvexPolygon { */ GLfloat getRadius() { return myRadius; } + void setColor(ColorFloat c) { Drawable::setColor(c); } + + void setColor(ColorFloat c[]); + + void displayOutlineEdges(bool b) { } + }; diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 74e72ff1a..fbcfbfb15 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; outlineGeometryType = GL_LINE_LOOP; @@ -40,7 +40,7 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Pyramid(x, y, z, 20, height, radius, yaw, pitch, roll, c) { +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { outlineStride = 6; numberOfOutlineVertices = mySides; outlineGeometryType = GL_LINE_LOOP; diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index 66a9f5962..078912b76 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) -: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { +: Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; outlineGeometryType = GL_LINES; @@ -40,7 +40,7 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl * \return A new Cylinder with a buffer for storing the specified numbered of vertices. */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Prism(x, y, z, 15, height, radius, yaw, pitch, roll, c) { +: Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { outlineStride = 3; numberOfOutlineVertices = mySides * 4; outlineGeometryType = GL_LINES; diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index f6225dd33..f4373e41b 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -13,14 +13,17 @@ namespace tsgl { * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; myZScale = 1; + edgesOutlined = false; + verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; attribMutex.unlock(); - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { + addVertex(0,0,0,color); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color); } } @@ -36,15 +39,18 @@ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, fl * \param filled Whether the Ellipse should be filled * (set to true by default). */ -Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 * 30,yaw,pitch,roll) { +Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; myZScale = 1; + edgesOutlined = false; + verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; attribMutex.unlock(); - float delta = 2.0f / numberOfVertices * PI; - for (int i = 0; i < numberOfVertices; ++i) { - addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + addVertex(0,0,0,color[0]); + float delta = 2.0f / (numberOfVertices - 2) * PI; + for (int i = 0; i < numberOfVertices - 1; ++i) { + addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); } } @@ -108,5 +114,24 @@ void Ellipse::changeYRadiusBy(GLfloat delta) { attribMutex.unlock(); } +/** + * \brief Sets the Ellipse to a new array of colors. + * \param c An array of the new ColorFloats. + */ +void Ellipse::setColor(ColorFloat c[]) { + colors[0] = c[0].R; + colors[1] = c[0].G; + colors[2] = c[0].B; + colors[3] = c[0].A; + int colorIndex; + for (int i = 1; i < numberOfVertices; ++i) { + colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); + colors[i*4] = c[colorIndex].R; + colors[i*4 + 1] = c[colorIndex].G; + colors[i*4 + 2] = c[colorIndex].B; + colors[i*4 + 3] = c[colorIndex].A; + } +} + } \ No newline at end of file diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index fde618e76..674da4c50 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -16,6 +16,7 @@ namespace tsgl { class Ellipse : public ConvexPolygon { private: GLfloat myXRadius, myYRadius; + GLfloat verticesPerColor; public: Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color); @@ -41,7 +42,11 @@ class Ellipse : public ConvexPolygon { */ GLfloat getYRadius() { return myYRadius; } + void setColor(ColorFloat c) { Drawable::setColor(c); } + void setColor(ColorFloat c[]); + + void displayOutlineEdges(bool b) { } }; } diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index 16bb5c230..afb8b6668 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -91,8 +91,8 @@ void Image::draw() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // actually generate the texture + mipmaps - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelWidth, pixelHeight, 0, + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelWidth, pixelHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); diff --git a/src/tests/DiningPhilosophers/Fork.h b/src/tests/DiningPhilosophers/Fork.h index 3d254c176..cffb1d9ad 100644 --- a/src/tests/DiningPhilosophers/Fork.h +++ b/src/tests/DiningPhilosophers/Fork.h @@ -16,8 +16,8 @@ struct Fork { user = -1; id = 0; const int POINTS = 20; // number of vertices in polygon - const float HEIGHT = .42; // 42 is preferred, but can be changed - const float WIDTH = .12; // 12 is preferred, but can be changed + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed float xs[POINTS], ys[POINTS]; // scales (out of 100) for the dimensions of the fork diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp index e0db89609..3f5c01eed 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/tests/DiningPhilosophers/Philosopher.cpp @@ -25,7 +25,7 @@ Philosopher::~Philosopher() { * Adds Philosopher to Canvas or refreshes its color. */ void Philosopher::draw(Canvas& can, float x, float y) { - const float SIZE = .45; + const float SIZE = 45; if( !myCircle) { myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorFloat(1,0,0,1)); can.add(myCircle); @@ -53,7 +53,7 @@ void Philosopher::refreshColor() { */ void Philosopher::addMeal(float x, float y, float z) { numMeals++; - meals.push_back(new RegularPolygon(x,y,z,.03,3,0,0,0,ColorFloat(0.5,0.3,0,1))); + meals.push_back(new RegularPolygon(x,y,z,3,3,0,0,0,ColorFloat(0.5,0.3,0,1))); meals.back()->displayOutlineEdges(false); } diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index f8a9a239c..081d53672 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -10,7 +10,7 @@ Table::Table(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Circle(0,0,-1,1.5,0,0,0,ColorFloat(0.5,0.5,0.5,1)); + myTable = new Circle(0,0,-1,175,0,0,0,ColorFloat(0.5,0.5,0.5,1)); can.add(myTable); // can.drawCircle(0,0,1,ColorFloat(0.5,0.5,0.5,1)); phils = new Philosopher[numPhils]; @@ -23,7 +23,7 @@ Table::Table(Canvas& can, int p, PhilMethod m) { spaghettis = new Image*[numPhils]; float delta = 2.0f / numPhils * PI; for(int i = 0; i < numPhils; i++) { - spaghettis[i] = new Image(0 + 0.8 * cos(i*delta), sin(i*delta), -0.5, "./assets/pics/spaghet.png", 1, 0.5, 0,0,0); + spaghettis[i] = new Image(120 * cos(i*delta), 140 * sin(i*delta), -0.5, "./assets/pics/spaghet.png", 100, 50, 0,0,0); can.add(spaghettis[i]); // myCan->drawImage("../assets/pics/spaghet.png", -50+(200)*cos(i*delta), -25+(215)*sin(i*delta), 100, 50, 1.0f); } @@ -459,11 +459,11 @@ void Table::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table::drawStep() { - const float RAD = 1.8; - float FORK_RAD = 1.3; + const float RAD = 225; + float FORK_RAD = 175; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; - const float BASEDIST = RAD+.54; + const float BASEDIST = RAD+54; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; @@ -477,7 +477,7 @@ void Table::drawStep() { phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+.08*(meals%10); + float angle = pangle+(meals/10)*2*PI/(RAD), dist = BASEDIST+8*(meals%10); // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); myCan->add(phils[i].getLastMeal()); @@ -490,7 +490,7 @@ void Table::drawStep() { fangle = ((i+1)*ARC) - CLOSE; fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; } else { - FORK_RAD = 1; + FORK_RAD = 140; fangle = pangle + PI / numPhils; } forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); diff --git a/src/tests/DiningPhilosophers3D/Fork3D.h b/src/tests/DiningPhilosophers3D/Fork3D.h index 12dfc920d..6425a0a50 100644 --- a/src/tests/DiningPhilosophers3D/Fork3D.h +++ b/src/tests/DiningPhilosophers3D/Fork3D.h @@ -16,8 +16,8 @@ struct Fork3D { user = -1; id = 0; const int POINTS = 20; // number of vertices in polygon - const float HEIGHT = .42; // 42 is preferred, but can be changed - const float WIDTH = .12; // 12 is preferred, but can be changed + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed float xs[POINTS], ys[POINTS]; // scales (out of 100) for the dimensions of the 3D fork diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp index d686313eb..f1bc198a8 100644 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp @@ -27,7 +27,7 @@ Philosopher3D::~Philosopher3D() { * Adds Philosopher3D to Canvas or refreshes its color. */ void Philosopher3D::draw(Canvas& can, float x, float y) { - const float SIZE = .45; + const float SIZE = 45; if( !myCylinder) { myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,RED); can.add(myCylinder); @@ -61,7 +61,7 @@ void Philosopher3D::refreshColor() { */ void Philosopher3D::addMeal(float x, float y, float z) { numMeals++; - meals.push_back(new Pyramid(x,y,z,3,.08,.04,0,0,90,ColorFloat(0.5,0.3,0,1))); + meals.push_back(new Pyramid(x,y,z,3,8,4,0,0,90,ColorFloat(0.5,0.3,0,1))); meals.back()->displayOutlineEdges(false); } diff --git a/src/tests/DiningPhilosophers3D/Table3D.cpp b/src/tests/DiningPhilosophers3D/Table3D.cpp index a4519c43b..60fe9e951 100644 --- a/src/tests/DiningPhilosophers3D/Table3D.cpp +++ b/src/tests/DiningPhilosophers3D/Table3D.cpp @@ -10,7 +10,7 @@ Table3D::Table3D(Canvas& can, int p, PhilMethod m) { numPhils = p; myCan = &can; - myTable = new Cylinder(0,0,-2,1,1.5,0,0,90,ColorFloat(0.5,0.5,0.5,1)); + myTable = new Cylinder(0,0,-55,100,150,0,0,90,ColorFloat(0.5,0.5,0.5,1)); can.add(myTable); phils = new Philosopher3D[numPhils]; forks = new Fork3D[numPhils]; @@ -451,11 +451,11 @@ void Table3D::actStep() { * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. */ void Table3D::drawStep() { - const float RAD = 1.95; - float FORK_RAD = 1; + const float RAD = 195; + float FORK_RAD = 130; const float ARC =2*PI/numPhils; const float CLOSE = 0.15f; - const float BASEDIST = RAD+.58; + const float BASEDIST = RAD+58; int i = omp_get_thread_num(); float pangle = (i*2*PI)/numPhils; @@ -469,7 +469,7 @@ void Table3D::drawStep() { phils[i].refreshColor(); if( phils[i].state() == isFull ) { int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+.08*(meals%10); + float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+8*(meals%10); // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); myCan->add(phils[i].getLastMeal()); @@ -482,7 +482,7 @@ void Table3D::drawStep() { fangle = ((i+1)*ARC) - CLOSE; fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; } else { - FORK_RAD = 0.9; + FORK_RAD = 120; fangle = pangle + PI / numPhils; } forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); diff --git a/src/tests/SeaUrchin/SeaUrchin.cpp b/src/tests/SeaUrchin/SeaUrchin.cpp index 388b5383c..b2671f550 100644 --- a/src/tests/SeaUrchin/SeaUrchin.cpp +++ b/src/tests/SeaUrchin/SeaUrchin.cpp @@ -12,6 +12,7 @@ SeaUrchin::SeaUrchin(Canvas& can, int threadId) { myColor = Colors::highContrastColor(threadId); for(int i = 0; i < MY_SPOKES; i++) { Line * l = new Line(myOldX, myOldY, myNewX, myNewY, myColor); + // Line * l = new Line() lines.push_back(l); can.add(l); } diff --git a/src/tests/test2Dvs3D.cpp b/src/tests/test2Dvs3D.cpp index 53fe9f65a..807dcda4c 100644 --- a/src/tests/test2Dvs3D.cpp +++ b/src/tests/test2Dvs3D.cpp @@ -18,19 +18,19 @@ void contrastFunction(Canvas& can) { ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; - Pyramid * testPyramid = new Pyramid(-2.0, 0.0, -1.0, 4, 2, 2, 0.0, 0.0, 45.0, pyramidcolors); + Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); // can.add(testPyramid); - Triangle * triangle1 = new Triangle(1.39,0.66,0,3.5,-0.52,0,1.62,-2,0,0,0,0,pyramidcolors); + Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); // can.add(triangle1); - Triangle * triangle2 = new Triangle(1.39,0.66,0,0.49,-0.52,0,1.62,-2,0,0,0,0,triangle2Colors); + Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); // can.add(triangle2); - Triangle * triangle3 = new Triangle(1.39,0.66,0,3.5,-0.52,0,2.27,0.40,0,0,0,0,triangle3Colors); + Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); // can.add(triangle3); - Triangle * triangle4 = new Triangle(2.65,0.64,0,3.31,-0.44,0,2.63,-1.94,0,0,0,0,pyramidcolors); + Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); // can.add(triangle4); - Triangle * triangle5 = new Triangle(2.65,0.64,0,0.16,-0.7,0,2.63,-1.94,0,0,0,0,triangle2Colors); + Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); // can.add(triangle5); - Triangle * triangle6 = new Triangle(2.65,0.64,0,0.16,-0.7,0,1.66,0.47,0,0,0,0,triangle6Colors); + Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); // can.add(triangle6); // testPyramid->setPitch(45); int stepsTaken = 0; diff --git a/src/tests/test3DRotation.cpp b/src/tests/test3DRotation.cpp index 61496b283..44e2d82d9 100644 --- a/src/tests/test3DRotation.cpp +++ b/src/tests/test3DRotation.cpp @@ -18,22 +18,21 @@ void cubeFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Cube * testCube = new Cube(2.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, colors); + Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); testCube->setRotationPoint(0,0,0); - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 90.0, colors); - Sphere * testSphere = new Sphere(3, 0, 0, 1, 0.0, 0.0, 0.0, colors); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); + Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); can.add(testCube); can.add(testPrism); can.add(testSphere); float rotation = 0.0f; - // GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); testCube->setYaw(rotation); testPrism->setYaw(-rotation); testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setCenter(testCube->getCenterX() + 1, testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); testSphere->setYaw(-rotation); rotation += 1; } diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 93b8989c8..22e7ec3a7 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -6,16 +6,16 @@ using namespace tsgl; void arrowFunction(Canvas& c) { ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1) }; - Arrow* doubleArrow = new Arrow(0, 0, 0, 2, 0.05,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(1 ,1 ,-1 ,2 ,0.05,0,0,0,ColorFloat(0,0,1,0.65), true); + Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); + Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); c.add(doubleArrow); c.add(arrow2); - // doubleArrow->setCenterX(1); + // doubleArrow->setCenterX(100); // doubleArrow->setRotationPoint(0,0,0); // doubleArrow->setYaw(45); doubleArrow->setColor(colors); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; while( c.isOpen() ) { c.sleep(); // doubleArrow->setCenterX(sin(floatVal/90)); @@ -24,8 +24,8 @@ void arrowFunction(Canvas& c) { // doubleArrow->setYaw(floatVal); // doubleArrow->setPitch(floatVal); // doubleArrow->setRoll(floatVal); - // doubleArrow->setLength(sin(floatVal/90) + 2); - if (doubleArrow->getLength() > 3 || doubleArrow->getLength() < 1) { + // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); + if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { delta *= -1; } doubleArrow->changeLengthBy(delta); diff --git a/src/tests/testBallroom.cpp b/src/tests/testBallroom.cpp index c614c3c32..722639ca3 100644 --- a/src/tests/testBallroom.cpp +++ b/src/tests/testBallroom.cpp @@ -133,18 +133,18 @@ class BouncingBall { bounced = false; vel += acc; pos += vel; - if (pos.x <= rad) { - pos.x = rad; + if (pos.x <= -rw / 2 + rad) { + pos.x = -rw / 2 + rad; vel.x *= -0.5f; - } else if (pos.x >= rw-rad) { - pos.x = rw-rad; + } else if (pos.x >= rw / 2 -rad) { + pos.x = rw / 2-rad; vel.x *= -0.5f; } - if (pos.y <= rad) { - pos.y = rad; + if (pos.y <= -rh / 2 + rad) { + pos.y = -rh / 2 + rad; vel.y *= -1.0f; - } else if (pos.y >= rh-rad) { - pos.y = rh-rad; + } else if (pos.y >= rh / 2 -rad) { + pos.y = rh / 2 -rad; vel.y *= -1.0f; } calcSpeed(); @@ -197,7 +197,7 @@ class BallRoom { gravity = 0.1f; attract = true; can = canvas; - mouseCircle = new Circle(0,0,0,1,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); + mouseCircle = new Circle(0,0,0,20,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); // mouseCircle->setLayer(2); can->add(mouseCircle); } @@ -228,7 +228,7 @@ class BallRoom { balls.push_back(b); } void step(Canvas* c) { - int mx = c->getMouseX(), my = c->getMouseY(); + int mx = c->getMouseX() - c->getWindowWidth()/2, my = c->getWindowHeight()/2 - c->getMouseY(); Vector2 mvec(mx,my); mouseCircle->setCenter(mx, my, 0); if (attract) { @@ -289,12 +289,11 @@ void ballroomFunction(Canvas& can) { const int WW = can.getWindowWidth(), // Window width WH = can.getWindowHeight(); // Window height BallRoom b(WW,WH, &can); - srand(time(NULL)); for (int i = 0; i < 100; ++ i) { float speed = 5.0f; - float dir = 2 * 3.14159f * (rand() % 100) / 100.0f; - b.addBall(25 + rand() % (WW-50),25 + rand() % (WH-50),speed*cos(dir),speed*sin(dir),10, - ColorFloat((64 + rand() % 192) / 255,(64 + rand() % 192) / 255,(64 + rand() % 192) / 255,1)); + float dir = 2 * PI * saferand(0,100) / 100.0f; + ColorInt c = ColorInt(64 + saferand(0,191),64 + saferand(0,191),64 + saferand(0,191),255); + b.addBall(saferand(-WW/2,WW/2), saferand(-WH/2, WH/2), speed*cos(dir),speed*sin(dir),10,c); } can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp index f3e736685..1de042d6d 100644 --- a/src/tests/testCircle.cpp +++ b/src/tests/testCircle.cpp @@ -21,31 +21,30 @@ void circleFunction(Canvas& can) { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Circle * circle = new Circle(0,0,0,1,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // circle->setCenterX(2); + Circle * circle = new Circle(0,0,0,100,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // circle->setCenterX(200); // circle->setRotationPoint(0,0,0); can.add(circle); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 1; while (can.isOpen()) { can.sleep(); - // circle->setCenterX(sin(floatVal/90)); - // circle->setCenterY(sin(floatVal/90)); - // circle->setCenterZ(sin(floatVal/90)); + // circle->setCenterX(sin(floatVal/90) * 100); + // circle->setCenterY(sin(floatVal/90) * 100); + // circle->setCenterZ(sin(floatVal/90) * 100); // circle->setYaw(floatVal); // circle->setPitch(floatVal); // circle->setRoll(floatVal); - // circle->setRadius(sin(floatVal/90) + 1); - // if (circle->getRadius() > 3 || circle->getRadius() < 1) { - // delta *= -1; - // circle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); - // } - // circle->changeRadiusBy(delta); - // if (delta > 0) { - // circle->setColor(colors); - // } else { - // circle->setColor(ColorFloat(1,0,0,1)); - // } + // circle->setRadius(sin(floatVal/90) * 100 + 100); + if (circle->getRadius() > 300 || circle->getRadius() < 100) { + delta *= -1; + } + circle->changeRadiusBy(delta); + if (delta > 0) { + circle->setColor(colors); + } else { + circle->setColor(RED); + } floatVal += 1; } @@ -57,7 +56,7 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Circle"); + Canvas c(-1, -1, w, h, "Basic Circle"); c.setBackgroundColor(BLACK); c.run(circleFunction); } \ No newline at end of file diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp index ade5c8870..14c54e479 100644 --- a/src/tests/testClock.cpp +++ b/src/tests/testClock.cpp @@ -11,42 +11,42 @@ using namespace tsgl; void clockFunction(Canvas& can) { - Prism * head = new Prism(0,1.33,1.01,12,1,0.59,0,0,90,ColorFloat(.6,.3,0,1)); + Prism * head = new Prism(0,133,101,12,100,59,0,0,90,ColorFloat(.6,.3,0,1)); can.add(head); - Cuboid * left = new Cuboid(-0.45,-.5,1,0.1,3,1,0,0,0,ColorFloat(.6,.3,0,1) ); + Cuboid * left = new Cuboid(-45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(left); - Cuboid * right = new Cuboid(0.45,-0.5,1,0.1,3,1,0,0,0,ColorFloat(.6,.3,0,1)); + Cuboid * right = new Cuboid(45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1)); can.add(right); - Cuboid * back = new Cuboid(0,-0.5,0.55,0.8,3,0.1,0,0,0,ColorFloat(.6,.3,0,1) ); + Cuboid * back = new Cuboid(0,-50,55,80,300,10,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(back); - Cuboid * bottom = new Cuboid(0,-1.95,1.10,0.79,0.1,0.8,0,0,0,ColorFloat(.6,.3,0,1) ); + Cuboid * bottom = new Cuboid(0,-195,110,79,10,80,0,0,0,ColorFloat(.6,.3,0,1) ); can.add(bottom); - Circle * face = new Circle(0,1.15,2.01,0.4,0,0,0,ColorFloat(1,1,0.8,1)); + Circle * face = new Circle(0,130,161,45,0,0,0,ColorFloat(1,1,0.8,1)); can.add(face); - Arrow * second = new Arrow(-0.19,1.15,2.03,0.38,0.02,0,0,0,ColorFloat(1,.8,.2,1),false); + Arrow * second = new Arrow(-19,130,163,38,2,0,0,0,ColorFloat(1,.8,.2,1),false); can.add(second); second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Arrow * minute = new Arrow(-0.19,1.15,2.02,0.38,0.02,0,0,0,ColorFloat(0,0,0,1),false); + Arrow * minute = new Arrow(-19,130,162,38,2,0,0,0,BLACK,false); can.add(minute); minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Arrow * hour = new Arrow(-0.1,1.15,2.02,0.2,0.02,0,0,0,ColorFloat(0,0,0,1),false); + Arrow * hour = new Arrow(-10,130,162,20,2,0,0,0,BLACK,false); can.add(hour); hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - Ellipsoid * pendulum = new Ellipsoid(0, -1.5, 1,0.1, 0.1,0.02,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); - pendulum->setRotationPoint(0,0.8,1); + Ellipsoid * pendulum = new Ellipsoid(0, -150, 100,10, 10,2,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); + pendulum->setRotationPoint(0,80,10); can.add(pendulum); - Rectangle * cord = new Rectangle(-1.1,0.8,1,2.2,0.05,90,0,0,ColorFloat(0,0,0,1)); - cord->setRotationPoint(0,0.8,1); + Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); + cord->setRotationPoint(0,80,10); cord->displayOutlineEdges(false); can.add(cord); diff --git a/src/tests/testCone.cpp b/src/tests/testCone.cpp index db1ad3045..5832a3608 100644 --- a/src/tests/testCone.cpp +++ b/src/tests/testCone.cpp @@ -11,6 +11,16 @@ using namespace tsgl; void coneFunction(Canvas& can) { ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), @@ -21,7 +31,7 @@ void coneFunction(Canvas& can) { ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; - Cone * testCone = new Cone(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 0.0, ColorFloat(1,0,0,1)); + Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); // Cone * testCone2 = new Cone(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); can.add(testCone); // can.add(testCone2); diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp index 747f1d947..3ded434de 100644 --- a/src/tests/testConvexPolygon.cpp +++ b/src/tests/testConvexPolygon.cpp @@ -18,8 +18,8 @@ void convexPolygonFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { -0.5,-0.5,0 ,0.25,0.5,0.5,0.25 }; - float y[] = { -0.5,0.25,0.5,0.4 ,0.1,-0.1,-0.5 }; + float x[] = { -50,-50, 0,25,50, 50, 25 }; + float y[] = { -50, 25,50,40,10,-10,-50 }; ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors/* ColorFloat(1,0,0,1) */); // cp->setCenterX(2); // cp->setRotationPoint(0,0,0); @@ -27,9 +27,9 @@ void convexPolygonFunction(Canvas& can) { float floatVal = 0.0f; while (can.isOpen()) { can.sleep(); - // cp->setCenterX(sin(floatVal/90)); - // cp->setCenterY(sin(floatVal/90)); - // cp->setCenterZ(sin(floatVal/90)); + // cp->setCenterX(sin(floatVal/90) * 100); + // cp->setCenterY(sin(floatVal/90) * 100); + // cp->setCenterZ(sin(floatVal/90) * 100); // cp->setYaw(floatVal); // cp->setPitch(floatVal); // cp->setRoll(floatVal); diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 03f635abf..38429f1a4 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -13,8 +13,8 @@ void cubeFunction(Canvas& can) { ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, ColorFloat(1,0,0,1)); - Cube * testCube2 = new Cube(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, ColorFloat(1,0,0,1)); + Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); can.add(testCube); can.add(testCube2); float rotation = 0.0f; @@ -22,18 +22,18 @@ void cubeFunction(Canvas& can) { bool boolean = false; while (can.isOpen()) { can.sleep(); - // testCube->setCenterX(sin(rotation)*2); - // testCube->setCenterY(cos(rotation)*2); - // testCube->setCenterZ(sin(rotation)); + // testCube->setCenterX(sin(rotation)*200); + // testCube->setCenterY(cos(rotation)*200); + // testCube->setCenterZ(sin(rotation)*100); // testCube->setYaw(rotation*45); testCube->setPitch(rotation*45); // testCube->setRoll(rotation*45); - // testCube->setSideLength(cos(rotation)+1.01); + // testCube->setSideLength(cos(rotation) * 100 +101); // if(testCube->getSideLength() >= 2) { - // delta = -0.05; + // delta = -5; // } - // if(testCube->getSideLength() <= 0.05) { - // delta = 0.05; + // if(testCube->getSideLength() <= 5) { + // delta = 5; // } // testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index 330e67e63..df01f9871 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -13,8 +13,8 @@ void cuboidFunction(Canvas& can) { ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 1, 4, 2, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); - // Cuboid * testCuboid2 = new Cuboid(-3.0, 0.0, 0.0, 1, 3, 2, 0.0, 0.0, 0.0, colors); + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); + // Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 300, 200, 0.0, 0.0, 0.0, colors); can.add(testCuboid); // can.add(testCuboid2); float rotation = 0.0f; @@ -22,36 +22,36 @@ void cuboidFunction(Canvas& can) { bool boolean = false;; while (can.isOpen()) { can.sleep(); - // testCuboid->setCenterX(sin(rotation)*2); - // testCuboid->setCenterY(cos(rotation)*2); - // testCuboid->setCenterZ(sin(rotation)); + // testCuboid->setCenterX(sin(rotation)*200); + // testCuboid->setCenterY(cos(rotation)*200); + // testCuboid->setCenterZ(sin(rotation)*100); // testCuboid->setYaw(rotation*45); testCuboid->setPitch(rotation*45); // testCuboid->setRoll(rotation*45); - // testCuboid->setWidth(cos(rotation)+1.01); - // testCuboid->setHeight(cos(rotation)+3.01); - // testCuboid->setLength(cos(rotation)+2.01); - // if(testCuboid->getWidth() >= 2) { - // delta = -0.05; + // testCuboid->setWidth(cos(rotation)*100+101); + // testCuboid->setHeight(cos(rotation)*100+301); + // testCuboid->setLength(cos(rotation)*100+201); + // if(testCuboid->getWidth() >= 200) { + // delta = -5; // } - // if(testCuboid->getWidth() <= 0.05) { - // delta = 0.05; + // if(testCuboid->getWidth() <= 5) { + // delta = 5; // } // testCuboid->changeWidthBy(delta); - // if(testCuboid->getHeight() >= 5) { - // delta = -0.05; + // if(testCuboid->getHeight() >= 500) { + // delta = -5; // } - // if(testCuboid->getHeight() <= 3) { - // delta = 0.05; + // if(testCuboid->getHeight() <= 300) { + // delta = 5; // } // testCuboid->changeHeightBy(delta); - // if(testCuboid->getLength() >= 3) { - // delta = -0.05; + // if(testCuboid->getLength() >= 300) { + // delta = -5; // } - // if(testCuboid->getLength() <= 1) { - // delta = 0.05; + // if(testCuboid->getLength() <= 100) { + // delta = 5; // } // testCuboid->changeLengthBy(delta); if (rotation*45 >= 360) { diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index fa2443f6a..4b4f4ff1b 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -15,10 +15,10 @@ void cylinderFunction(Canvas& can) { ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - // Cylinder * testCylinder2 = new Cylinder(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); can.add(testCylinder); - // can.add(testCylinder2); + can.add(testCylinder2); float rotation = 0.0f; // GLfloat delta = 0.05; bool boolean = false; diff --git a/src/tests/testDiorama.cpp b/src/tests/testDiorama.cpp index 090dfac93..b66dbd515 100644 --- a/src/tests/testDiorama.cpp +++ b/src/tests/testDiorama.cpp @@ -10,35 +10,35 @@ using namespace tsgl; void dioramaFunction(Canvas& can) { - Square * blankCanvas = new Square(1.8,0,1.35,2.7,0,0,0,WHITE); + Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); blankCanvas->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(blankCanvas); - Rectangle * emptyDioramaLeft = new Rectangle(-0.45,0,0,2.7,2.7,0,90,0,ColorFloat(1,1,1,0)); + Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); emptyDioramaLeft->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaLeft); - Rectangle * emptyDioramaRight = new Rectangle(-3.15,0,0,2.7,2.7,0,90,0,ColorFloat(1,1,1,0)); + Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); emptyDioramaRight->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaRight); - Rectangle * emptyDioramaTop = new Rectangle(-1.8,1.35,0,2.7,2.7,0,0,90,ColorFloat(1,1,1,0)); + Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); emptyDioramaTop->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaTop); - Rectangle * emptyDioramaBottom = new Rectangle(-1.8,-1.35,0,2.7,2.7,0,0,90,ColorFloat(1,1,1,0)); + Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); emptyDioramaBottom->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaBottom); - Cuboid * trunk = new Cuboid(-2,-.3,0,0.25,2,0.25,0,0,0,ColorFloat(.6,.3,0,1)); + Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); trunk->displayOutlineEdges(false); // can.add(trunk); - Ellipsoid * leaves = new Ellipsoid(-2,0.7,0,0.75,0.5,0.4,0,0,0,GREEN); + Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); // can.add(leaves); - Rectangle * trunkFlat = new Rectangle(1.6,-.3,1.35,0.25,2,0,0,0,ColorFloat(.6,.3,0,1)); + Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); trunkFlat->displayOutlineEdges(false); // can.add(trunkFlat); - Ellipse * leavesFlat = new Ellipse(1.6,0.7,1.35,0.75,0.5,0,0,0,ColorFloat(0,0.8,0,1)); + Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); // can.add(leavesFlat); float counter = 0; @@ -73,32 +73,32 @@ void dioramaFunction(Canvas& can) { counter++; } if(can.getFrameNumber() > 4000 && counter < 7) { - if(emptyDioramaLeft->getWidth() > .15) { - emptyDioramaLeft->changeWidthBy(-2.7/20); - emptyDioramaRight->changeWidthBy(-2.7/20); - emptyDioramaTop->changeHeightBy(-2.7/20); - emptyDioramaBottom->changeHeightBy(-2.7/20); - emptyDioramaTop->changeZBy(1.35/20); - emptyDioramaBottom->changeZBy(1.35/20); - emptyDioramaLeft->changeZBy(1.35/20); - emptyDioramaRight->changeZBy(1.35/20); - trunk->changeLengthBy(-0.25/20); - trunk->changeZBy(1.35/20); - leaves->changeZRadiusBy(-0.4/20); - leaves->changeZBy(1.35/20); + if(emptyDioramaLeft->getWidth() > 15) { + emptyDioramaLeft->changeWidthBy(-270/20); + emptyDioramaRight->changeWidthBy(-270/20); + emptyDioramaTop->changeHeightBy(-270/20); + emptyDioramaBottom->changeHeightBy(-270/20); + emptyDioramaTop->changeZBy(135/20); + emptyDioramaBottom->changeZBy(135/20); + emptyDioramaLeft->changeZBy(135/20); + emptyDioramaRight->changeZBy(135/20); + trunk->changeLengthBy(-25/20); + trunk->changeZBy(135/20); + leaves->changeZRadiusBy(-40/20); + leaves->changeZBy(135/20); } else { - emptyDioramaLeft->setWidth(0.01); - emptyDioramaRight->setWidth(0.01); - emptyDioramaTop->setHeight(0.01); - emptyDioramaBottom->setHeight(0.01); - emptyDioramaTop->setCenterZ(1.35); - emptyDioramaBottom->setCenterZ(1.35); - emptyDioramaLeft->setCenterZ(1.35); - emptyDioramaRight->setCenterZ(1.35); - trunk->setLength(0.01); - trunk->setCenterZ(1.35); - leaves->setZRadius(0.01); - leaves->setCenterZ(1.35); + emptyDioramaLeft->setWidth(1); + emptyDioramaRight->setWidth(1); + emptyDioramaTop->setHeight(1); + emptyDioramaBottom->setHeight(1); + emptyDioramaTop->setCenterZ(135); + emptyDioramaBottom->setCenterZ(135); + emptyDioramaLeft->setCenterZ(135); + emptyDioramaRight->setCenterZ(135); + trunk->setLength(1); + trunk->setCenterZ(135); + leaves->setZRadius(1); + leaves->setCenterZ(135); counter++; } } diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp index 6afdfaaf3..a5a29b989 100644 --- a/src/tests/testEllipse.cpp +++ b/src/tests/testEllipse.cpp @@ -21,30 +21,28 @@ void ellipseFunction(Canvas& can) { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipse * ellipse = new Ellipse(0,0,0,1,2,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // ellipse->setCenterX(2); + Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // ellipse->setCenterX(200); // ellipse->setRotationPoint(0,0,0); can.add(ellipse); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; while (can.isOpen()) { can.sleep(); - // ellipse->setCenterX(sin(floatVal/90)); - // ellipse->setCenterY(sin(floatVal/90)); - // ellipse->setCenterZ(sin(floatVal/90)); + // ellipse->setCenterX(sin(floatVal/90) * 100); + // ellipse->setCenterY(sin(floatVal/90) * 100); + // ellipse->setCenterZ(sin(floatVal/90) * 100); // ellipse->setYaw(floatVal); // ellipse->setPitch(floatVal); // ellipse->setRoll(floatVal); - // ellipse->setXRadius(sin(floatVal/90) + 1); - // ellipse->setYRadius(sin(floatVal/90) + 2); - // if (ellipse->getXRadius() > 3 || ellipse->getXRadius() < 1) { + // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); + // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); + // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { // delta *= -1; - // ellipse->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // ellipse->changeXRadiusBy(delta); - // if (ellipse->getYRadius() > 3 || ellipse->getYRadius() < 1) { + // if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { // delta *= -1; - // ellipse->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // ellipse->changeYRadiusBy(delta); // if (delta > 0) { diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 147cfc02d..8b02e5500 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -18,19 +18,19 @@ void ellipsoidFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 2, 2, 2, 0.0, 0.0, 0.0, colors/* ColorFloat(1,0,0,1) */); - // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, colors); + Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors/* ColorFloat(1,0,0,1) */); + // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 150, 150, 150, 0.0, 0.0, 0.0, colors); can.add(testEllipsoid); // can.add(testEllipsoid2); float rotation = 0.0f; // GLfloat delta = 0.05; bool boolean = true; - // testEllipsoid->setXRadius(1.5); - // testEllipsoid->setYRadius(1.5); - // testEllipsoid->setZRadius(1.5); - // testEllipsoid->changeXRadiusBy(1.4); - // testEllipsoid->changeYRadiusBy(1.4); - // testEllipsoid->changeZRadiusBy(1.4); + // testEllipsoid->setXRadius(150); + // testEllipsoid->setYRadius(150); + // testEllipsoid->setZRadius(150); + // testEllipsoid->changeXRadiusBy(140); + // testEllipsoid->changeYRadiusBy(140); + // testEllipsoid->changeZRadiusBy(140); while (can.isOpen()) { can.sleep(); // testEllipsoid->setCenterX(sin(rotation)); @@ -40,30 +40,30 @@ void ellipsoidFunction(Canvas& can) { testEllipsoid->setPitch(rotation*45); // testEllipsoid2->setPitch(rotation*45); // testEllipsoid->setRoll(rotation*45); - // testEllipsoid->setXRadius(cos(rotation)+1.01); - // testEllipsoid->setYRadius(sin(rotation)+2.01); - // testEllipsoid->setZRadius(sin(rotation)+3.01); - // if(testEllipsoid->getXRadius() >= 2) { - // delta = -0.05; + // testEllipsoid->setXRadius(cos(rotation) * 100 +101); + // testEllipsoid->setYRadius(sin(rotation) * 100 +201); + // testEllipsoid->setZRadius(sin(rotation) * 100 +301); + // if(testEllipsoid->getXRadius() >= 200) { + // delta = -5; // } - // if(testEllipsoid->getXRadius() <= 0.05) { - // delta = 0.05; + // if(testEllipsoid->getXRadius() <= 5) { + // delta = 5; // } // testEllipsoid->changeXRadiusBy(delta); - // if(testEllipsoid->getYRadius() >= 5) { - // delta = -0.05; + // if(testEllipsoid->getYRadius() >= 500) { + // delta = -5; // } - // if(testEllipsoid->getYRadius() <= 3) { - // delta = 0.05; + // if(testEllipsoid->getYRadius() <= 300) { + // delta = 5; // } // testEllipsoid->changeYRadiusBy(delta); - // if(testEllipsoid->getZRadius() >= 3) { - // delta = -0.05; + // if(testEllipsoid->getZRadius() >= 300) { + // delta = -5; // } - // if(testEllipsoid->getZRadius() <= 1) { - // delta = 0.05; + // if(testEllipsoid->getZRadius() <= 100) { + // delta = 5; // } // testEllipsoid->changeZRadiusBy(delta); // if (rotation*45 >= 360) { diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 72245df1e..bdab44087 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -27,57 +27,40 @@ void imageFunction(Canvas& can) { // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); // can.add(image); - // Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); - // can.add(image); - // Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); - // can.add(image2); - // Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); - // can.add(image3); - // Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); - // can.add(image4); - // Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); - // can.add(image5); - // Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); - // can.add(image6); - - Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); can.add(image); - Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); can.add(image2); - Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); can.add(image3); - Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); can.add(image4); - Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); can.add(image5); - Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/launch.bmp", ww,hh, 0,0,0); + Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); can.add(image6); - // Image * image7 = new Image(0,0,0,"./assets/pics/cow.jpg", 960,480,0,0,0,th); - // can.add(image7); - - // image->setHeight((GLfloat)image->getPixelHeight() / 100); - // image->setWidth((GLfloat)image->getPixelWidth() / 100); + // image->setHeight((GLfloat)image->getPixelHeight()); + // image->setWidth((GLfloat)image->getPixelWidth()); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; bool ss = false; while (can.isOpen()) { can.sleep(); - // image->setCenterX(sin(floatVal/90)); - // printf("%f\n", image->getCenterX()); - // image->setCenterY(sin(floatVal/90)); - // image->setCenterZ(sin(floatVal/90)); + // image->setCenterX(sin(floatVal/90) * 100); + // image->setCenterY(sin(floatVal/90) * 100); + // image->setCenterZ(sin(floatVal/90) * 100); // image->setYaw(floatVal); - // image->setPitch(floatVal); + image->setPitch(floatVal); // image->setRoll(floatVal); - // image->setWidth(sin(floatVal/90) + 4); - // image->setHeight(sin(floatVal/90) + 4); - // if (image->getWidth() > 5 || image->getWidth() < 3) { + // image->setWidth(sin(floatVal/90) * 100 + 400); + // image->setHeight(sin(floatVal/90) * 100 + 400); + // if (image->getWidth() > 500 || image->getWidth() < 300) { // delta *= -1; // } // image->changeWidthBy(delta); - // if (image->getHeight() > 5 || image->getHeight() < 3) { + // if (image->getHeight() > 500 || image->getHeight() < 300) { // delta *= -1; // } // image->changeHeightBy(delta); @@ -86,17 +69,10 @@ void imageFunction(Canvas& can) { // can.takeScreenShot(); // ss = true; // } - // ColorInt blah = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); - // printf("%d, %d, %d, %d\n", blah.R, blah.G, blah.B, blah.A); + // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); + // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); floatVal += 1; } - // int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; - // can.drawImage("../assets/pics/test.png", 0, 0, ww, hh); - // can.drawImage("../assets/pics/ship.bmp", ww, 0, ww, hh); // possibly lost - // can.drawImage("../assets/pics/shiprgb.bmp", ww*2, 0, ww, hh); // definitely lost - // can.drawImage("../assets/pics/sky_main.jpg", 0, hh, ww, hh); - // can.drawImage("../assets/pics/colorfulKeyboard.jpg", ww, hh, ww, hh); - // can.drawImage("../assets/pics/cow.jpg", ww*2, hh, ww, hh); // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay @@ -106,7 +82,6 @@ void imageFunction(Canvas& can) { delete image4; delete image5; delete image6; - // delete image7; } //Takes command-line arguments for the width and height of the screen diff --git a/src/tests/testLines.cpp b/src/tests/testLines.cpp index 79377fa2f..79d9d1015 100644 --- a/src/tests/testLines.cpp +++ b/src/tests/testLines.cpp @@ -9,18 +9,18 @@ void lineFunction(Canvas& c) { ColorFloat(0,0,1,1), ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(0,1,1,1), ColorFloat(0,0,1,1) }; - Line * l = new Line(0,0,0,2,0,0,0,ColorFloat(1,0,0,1)); + Line * l = new Line(0,0,0,200,0,0,0,RED); // l->setColor(RED); l->setColor(colors); - float vertices[] = { -1.5,-1,-1, - -1,1,0, - -0.5,-1,1, - 0,-1,-1, - 0.5,1,0, - 1,-1,1, - 1.5,-1,-1 }; + float vertices[] = { -150,-100,-100, + -100,100,0, + -50,-100,100, + 0,-100,-100, + 50,100,0, + 100,-100,100, + 150,-100,-100 }; Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,BLUE); diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp index 9cff52d99..8fd7bdee9 100644 --- a/src/tests/testMergeSort.cpp +++ b/src/tests/testMergeSort.cpp @@ -113,10 +113,10 @@ void mergeSortFunction(Canvas& can, int threads, int size) { const int IPF = 1; // Iterations per frame float* numbers = new float[size]; // Array to store the data Rectangle** rectangles = new Rectangle*[size]; // Array to store the data - float start = -5; - float width = 0.01 * 1024/size; + float start = -can.getWindowWidth() * .45; + float width = can.getWindowWidth() * .9 / size; for (int i = 0; i < size; i++) { - numbers[i] = (float) (saferand(1,200000)) / 50000; + numbers[i] = saferand(1,can.getWindowHeight()); rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index 2a96d230d..da9dd2803 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -15,9 +15,9 @@ void prismFunction(Canvas& can) { ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Prism * testPrism2 = new Prism(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); - Prism * testPrism3 = new Prism(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); can.add(testPrism); can.add(testPrism2); can.add(testPrism3); @@ -26,26 +26,26 @@ void prismFunction(Canvas& can) { bool boolean = false; while (can.isOpen()) { can.sleep(); - // testPrism->setCenterX(sin(rotation)*2); - // testPrism->setCenterY(cos(rotation)*2); - // testPrism->setCenterZ(sin(rotation)); + // testPrism->setCenterX(sin(rotation)*200); + // testPrism->setCenterY(cos(rotation)*200); + // testPrism->setCenterZ(sin(rotation)*100); // testPrism->setYaw(rotation*45); testPrism->setPitch(rotation*45); // testPrism->setRoll(rotation*45); - // testPrism->setHeight(sin(rotation)+1.01); - // testPrism->setRadius(sin(rotation)+1.01); - // if(testPrism->getHeight() >= 2) { - // delta = -0.05; + // testPrism->setHeight(sin(rotation)*100+101); + // testPrism->setRadius(sin(rotation)*100+101); + // if(testPrism->getHeight() >= 200) { + // delta = -5; // } - // if(testPrism->getHeight() <= 0.05) { - // delta = 0.05; + // if(testPrism->getHeight() <= 5) { + // delta = 5; // } // testPrism->changeHeightBy(delta); - // if(testPrism->getRadius() >= 2) { - // delta = -0.05; + // if(testPrism->getRadius() >= 200) { + // delta = -5; // } - // if(testPrism->getRadius() <= 0.05) { - // delta = 0.05; + // if(testPrism->getRadius() <= 5) { + // delta = 5; // } // testPrism->changeRadiusBy(delta); // if (rotation*45 >= 360) { diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 173f4cced..3ef56e202 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -15,9 +15,9 @@ void pyramidFunction(Canvas& can) { ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 1, 1, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Pyramid * testPyramid2 = new Pyramid(-3.0, 0.0, 0.0, 5, 1, 1, 0.0, 0.0, 45.0, colors); - Pyramid * testPyramid3 = new Pyramid(3.0, 0.0, 0.0, 8, 1, 1, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); can.add(testPyramid); can.add(testPyramid2); can.add(testPyramid3); @@ -26,28 +26,28 @@ void pyramidFunction(Canvas& can) { bool boolean = false; while (can.isOpen()) { can.sleep(); - // testPyramid->setCenterX(sin(rotation)*2); - // testPyramid->setCenterY(cos(rotation)*2); - // testPyramid->setCenterZ(sin(rotation)); + // testPyramid->setCenterX(sin(rotation)*200); + // testPyramid->setCenterY(cos(rotation)*200); + // testPyramid->setCenterZ(sin(rotation)*100); // testPyramid->setYaw(rotation*45); testPyramid->setPitch(rotation*45); testPyramid2->setPitch(rotation*45); testPyramid3->setPitch(rotation*45); - // testPyramid->setRoll(rotation*45); - // testPyramid->setHeight(sin(rotation)+1.01); - // testPyramid->setRadius(sin(rotation)+1.01); - // if(testPyramid->getHeight() >= 2) { - // delta = -0.05; + // testPyramid->setRoll(sin(rotation*45)*100+101); + // testPyramid->setHeight(sin(rotation)*100+101); + // testPyramid->setRadius(sin(rotation)*100+101); + // if(testPyramid->getHeight() >= 200) { + // delta = -5; // } - // if(testPyramid->getHeight() <= 0.05) { - // delta = 0.05; + // if(testPyramid->getHeight() <= 5) { + // delta = 5; // } // testPyramid->changeHeightBy(delta); - // if(testPyramid->getRadius() >= 2) { - // delta = -0.05; + // if(testPyramid->getRadius() >= 200) { + // delta = -5; // } - // if(testPyramid->getRadius() <= 0.05) { - // delta = 0.05; + // if(testPyramid->getRadius() <= 5) { + // delta = 5; // } // testPyramid->changeRadiusBy(delta); if (rotation*45 >= 360) { diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp index 734b2a7a1..987d349cd 100644 --- a/src/tests/testRectangle.cpp +++ b/src/tests/testRectangle.cpp @@ -18,30 +18,30 @@ void rectangleFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Rectangle * rectangle = new Rectangle(0,0,0,1,2,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // rectangle->setCenterX(2); + Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // rectangle->setCenterX(200); // rectangle->setRotationPoint(0,0,0); can.add(rectangle); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); - // rectangle->setCenterX(sin(floatVal/90)); - // rectangle->setCenterY(sin(floatVal/90)); - // rectangle->setCenterZ(sin(floatVal/90)); + // rectangle->setCenterX(sin(floatVal/90)*100); + // rectangle->setCenterY(sin(floatVal/90)*100); + // rectangle->setCenterZ(sin(floatVal/90)*100); // rectangle->setYaw(floatVal); // rectangle->setPitch(floatVal); // rectangle->setRoll(floatVal); - // rectangle->setWidth(sin(floatVal/90) + 1); - // rectangle->setHeight(sin(floatVal/90) + 2); - // if (rectangle->getWidth() > 2 || rectangle->getWidth() < 1) { + // rectangle->setWidth(sin(floatVal/90) *100 + 100); + // rectangle->setHeight(sin(floatVal/90) *100 + 200); + // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // rectangle->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); // } // rectangle->changeWidthBy(delta); - // if (rectangle->getHeight() > 3 || rectangle->getHeight() < 1) { + // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // rectangle->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); // } // rectangle->changeHeightBy(delta); // if (delta > 0) { diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index 08c42fd60..bbf5234c6 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -18,24 +18,24 @@ void rpFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - RegularPolygon * rp = new RegularPolygon(0,0,0,1,7,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // rp->setCenterX(2); + RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // rp->setCenterX(200); // rp->setRotationPoint(0,0,0); can.add(rp); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; while (can.isOpen()) { can.sleep(); - // rp->setCenterX(sin(floatVal/90)); - // rp->setCenterY(sin(floatVal/90)); - // rp->setCenterZ(sin(floatVal/90)); + // rp->setCenterX(sin(floatVal/90)*100); + // rp->setCenterY(sin(floatVal/90)*100); + // rp->setCenterZ(sin(floatVal/90)*100); // rp->setYaw(floatVal); // rp->setPitch(floatVal); // rp->setRoll(floatVal); - // rp->setRadius(sin(floatVal/90) + 3); - // if (rp->getRadius() > 3 || rp->getRadius() < 1) { + // rp->setRadius(sin(floatVal/90)*100 + 300); + // if (rp->getRadius() > 300 || rp->getRadius() < 100) { // delta *= -1; - // rp->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // rp->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); // } // rp->changeRadiusBy(delta); // if (delta > 0) { diff --git a/src/tests/testShakerSort.cpp b/src/tests/testShakerSort.cpp index d98719cb5..f25ef31d3 100644 --- a/src/tests/testShakerSort.cpp +++ b/src/tests/testShakerSort.cpp @@ -44,12 +44,11 @@ void shakerSortFunction(Canvas& can) { int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; float temp; bool goingUp = true; - printf("%d, %d\n", can.getWindowWidth(), can.getDisplayWidth()); int canWidth = (can.getWindowWidth() > can.getDisplayWidth()) ? can.getDisplayWidth() : can.getWindowWidth(); - float start = -3.6 * canWidth / 960; - float rectangleWidth = 0.013 * canWidth / 960; + float start = canWidth * -.45; + float rectangleWidth = canWidth * .9 / SIZE; for (int i = 0; i < SIZE; i++) { - rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, (float) (saferand(1,200000)) / 50000, 0, 0, 0, RED); + rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, saferand(1,can.getWindowHeight()*.9), 0, 0, 0, RED); numbers[i] = rectangles[i]->getHeight(); rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); diff --git a/src/tests/testSolarSystem.cpp b/src/tests/testSolarSystem.cpp index 302be0b71..3f4dd6551 100644 --- a/src/tests/testSolarSystem.cpp +++ b/src/tests/testSolarSystem.cpp @@ -10,16 +10,16 @@ using namespace tsgl; void ssFunction(Canvas& can) { - Sphere * sun = new Sphere(0, 0, 0, 0.75, 15, 0.0, 15.0, YELLOW); - Sphere * mercury = new Sphere(0.95, 0, 0, .15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); - Sphere * venus = new Sphere(1.4, 0, 0, .25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); - Sphere * earth = new Sphere(2.05, 0, 0, .3, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); - Sphere * mars = new Sphere(2.7, 0, 0, .2, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); - Sphere * jupiter = new Sphere(3.45, 0, 0, .5, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); - Sphere * saturn = new Sphere(4.45, 0, 0, .4, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); - Circle * saturnRings = new Circle(4.45, 0, 0, .7, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); - Sphere * uranus = new Sphere(5.15, 0, 0, .25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); - Sphere * neptune = new Sphere(5.75, 0, 0, .2, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); + Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); saturnRings->displayOutlineEdges(false); @@ -44,7 +44,6 @@ void ssFunction(Canvas& can) { can.add(uranus); can.add(neptune); float rotation = 0.0f; - // GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); sun->setPitch(rotation); diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index 026abb8cd..da8ee2aba 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -21,22 +21,22 @@ void sphereFunction(Canvas& can) { Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 250, 0.0, 0.0, 0.0, colors); can.add(testSphere); float rotation = 0.0f; - // GLfloat delta = 0.05; + // GLfloat delta = 5; bool boolean = true; while (can.isOpen()) { can.sleep(); - // testSphere->setCenterX(sin(rotation)); - // testSphere->setCenterY(cos(rotation)); - // testSphere->setCenterZ(sin(rotation)); + // testSphere->setCenterX(sin(rotation) * 100); + // testSphere->setCenterY(cos(rotation) * 100); + // testSphere->setCenterZ(sin(rotation) * 100); // testSphere->setYaw(rotation*45); // testSphere->setPitch(rotation*45); testSphere->setRoll(rotation*45); - // testSphere->setRadius(cos(rotation)+1.01); - // if(testSphere->getRadius() >= 2) { - // delta = -0.05; + // testSphere->setRadius(cos(rotation) * 100 +101); + // if(testSphere->getRadius() >= 200) { + // delta = -5; // } - // if(testSphere->getRadius() <= 0.05) { - // delta = 0.05; + // if(testSphere->getRadius() <= 500) { + // delta = 5; // } // testSphere->changeRadiusBy(delta); // if (rotation*45 >= 360) { diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 951c7b16b..468492789 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -18,24 +18,24 @@ void squareFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,500,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // square->setCenterX(2); + Square * square = new Square(0,0,0,200,0,0,0,colors/* RED */); + // square->setCenterX(200); // square->setRotationPoint(0,0,0); can.add(square); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); - // square->setCenterX(sin(floatVal/90)); - // square->setCenterY(sin(floatVal/90)); - // square->setCenterZ(sin(floatVal/90)); + // square->setCenterX(sin(floatVal/90) * 100); + // square->setCenterY(sin(floatVal/90) * 100); + // square->setCenterZ(sin(floatVal/90) * 100); // square->setYaw(floatVal); // square->setPitch(floatVal); // square->setRoll(floatVal); - // square->setSideLength(sin(floatVal/90) + 3); - // if (square->getSideLength() > 3 || square->getSideLength() < 1) { + // square->setSideLength(sin(floatVal/90) * 100 + 300); + // if (square->getSideLength() > 300 || square->getSideLength() < 100) { // delta *= -1; - // // square->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // square->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); // } // square->changeSideLengthBy(delta); // if (delta > 0) { diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 4f3cc6edd..24658cfe4 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -21,22 +21,22 @@ void starFunction(Canvas& c) { GLfloat delta = 0.05; while (c.isOpen()) { c.sleep(); - // s1->setCenterX(sin(floatVal/90)); - // s1->setCenterY(sin(floatVal/90)); - // s1->setCenterZ(sin(floatVal/90)); + // s1->setCenterX(sin(floatVal/90) * 100); + // s1->setCenterY(sin(floatVal/90) * 100); + // s1->setCenterZ(sin(floatVal/90) * 100); // s1->setYaw(floatVal); // s1->setPitch(floatVal); // s1->setRoll(floatVal); - // s1->setRadius(sin(floatVal/90) + 3); - // if (s1->getRadius() > 3 || s1->getRadius() < 1) { + // s1->setRadius(sin(floatVal/90) * 100 + 300); + // if (s1->getRadius() > 300 || s1->getRadius() < 100) { // delta *= -1; - // // s1->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); + // // s1->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); // } // s1->changeRadiusBy(delta); // if (delta > 0) { // s1->setColor(colors); // } else { - // s1->setColor(ColorFloat(1,0,0,1)); + // s1->setColor(RED); // } floatVal += 1; } diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp index 0f38de60f..a939f922b 100644 --- a/src/tests/testTriangle.cpp +++ b/src/tests/testTriangle.cpp @@ -18,17 +18,17 @@ void triangleFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Triangle * triangle = new Triangle(-0.5,-0.5,0,0,0.5,0,0.5,-0.5,0,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // triangle->setCenterX(2); + Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // triangle->setCenterX(200); // triangle->setRotationPoint(0,0,0); can.add(triangle); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); - // triangle->setCenterX(sin(floatVal/90)); - // triangle->setCenterY(sin(floatVal/90)); - // triangle->setCenterZ(sin(floatVal/90)); + // triangle->setCenterX(sin(floatVal/90) * 100); + // triangle->setCenterY(sin(floatVal/90) * 100); + // triangle->setCenterZ(sin(floatVal/90) * 100); // triangle->setYaw(floatVal); // triangle->setPitch(floatVal); // triangle->setRoll(floatVal); diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp index 23b8a3acd..62ca425bc 100644 --- a/src/tests/testTriangleStrip.cpp +++ b/src/tests/testTriangleStrip.cpp @@ -18,22 +18,22 @@ void triangleStripFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { 0,-0.5,0.5,-0.5,0.5,0 }; - float y[] = { -1,-0.5,-0.5,0.5,0.5,1 }; - float z[] = { 0,0.5,0.5,0.5,0.5,0 }; + float x[] = { 0,-50,50,-50,50,0 }; + float y[] = { -100,-50,-50,50,50,100 }; + float z[] = { 0,50,50,50,50,0 }; TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors/* RED */); // ts->setCenterX(2); - // ts->setRotationPoint(0,0,0); + ts->setRotationPoint(0,0,0); can.add(ts); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { can.sleep(); - // ts->setCenterX(sin(floatVal/90)); - // ts->setCenterY(sin(floatVal/90)); - // ts->setCenterZ(sin(floatVal/90)); + // ts->setCenterX(sin(floatVal/90) * 100); + // ts->setCenterY(sin(floatVal/90) * 100); + // ts->setCenterZ(sin(floatVal/90) * 100); // ts->setYaw(floatVal); - // ts->setPitch(floatVal); + ts->setPitch(floatVal); // ts->setRoll(floatVal); // if (floatVal < 200) { // ts->setColor(colors); From a82056a038bed54a5415ee0d00db876c2480216e Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 12 Jun 2020 15:01:07 -0400 Subject: [PATCH 035/105] Fixing new tests for 3D --- Makefile | 7 +-- src/TSGL/Util.h | 9 +++ src/tests/Pong/Ball.cpp | 64 +++++++++----------- src/tests/Pong/Ball.h | 25 ++++---- src/tests/Pong/Paddle.cpp | 76 +++++++++--------------- src/tests/Pong/Paddle.h | 34 +++++------ src/tests/Pong/Pong.cpp | 99 +++++++++++++++---------------- src/tests/Pong/Pong.h | 12 ++-- src/tests/SeaUrchin/SeaUrchin.cpp | 19 +++--- src/tests/SeaUrchin/SeaUrchin.h | 2 +- src/tests/testNewtonPendulum.cpp | 53 +++++++++-------- src/tests/testRectangle.cpp | 4 +- src/tests/testRegularPolygon.cpp | 2 +- src/tests/testRotation.cpp | 70 ---------------------- src/tests/testSquare.cpp | 2 +- src/tests/testStar.cpp | 2 +- 16 files changed, 195 insertions(+), 285 deletions(-) delete mode 100644 src/tests/testRotation.cpp diff --git a/Makefile b/Makefile index f0a366551..5d40c4ad6 100644 --- a/Makefile +++ b/Makefile @@ -84,12 +84,15 @@ BINARIES= \ bin/testImage \ bin/testLines \ bin/testMergeSort \ + bin/testNewtonPendulum \ bin/testPhilosophers \ + bin/testPong \ bin/testPrism \ bin/testPyramid \ bin/testRectangle \ bin/testRegularPolygon \ bin/testShakerSort \ + bin/testSeaUrchin \ bin/testSolarSystem \ bin/testSphere \ bin/testSquare \ @@ -122,15 +125,11 @@ BINARIES= \ # bin/testLineFan \ # bin/testMandelbrot \ # bin/testMouse \ -# bin/testNewtonPendulum \ # bin/testProducerConsumer \ -# bin/testPong \ # bin/testProgressBar \ # bin/testProjectiles \ # bin/testReaderWriter \ -# bin/testRotation \ # bin/testScreenshot \ -# bin/testSeaUrchin \ # bin/testSpectrogram \ # bin/testSpectrum \ # bin/testText \ diff --git a/src/TSGL/Util.h b/src/TSGL/Util.h index e1cc2907c..91278f753 100644 --- a/src/TSGL/Util.h +++ b/src/TSGL/Util.h @@ -156,6 +156,15 @@ inline int saferand(int min, int max) // return (*generator)(); } + /*! + * \brief Thread safe random float generator + * \details Calculates a random float to return. + * \param divisor Divisor used to calculate the random float. + */ +inline float randfloat(int divisor = 10000) { + return (float) saferand(0, divisor) / divisor; +} + } #endif /* SRC_TSGL_UTIL_H_ */ diff --git a/src/tests/Pong/Ball.cpp b/src/tests/Pong/Ball.cpp index 155fbbfdd..676f6f47c 100644 --- a/src/tests/Pong/Ball.cpp +++ b/src/tests/Pong/Ball.cpp @@ -13,16 +13,16 @@ * \return The constructed Ball object. */ Ball::Ball(Canvas& can, int & speed) { - mySpeed = speed; - myX = can.getWindowWidth() / 2-8; - myY = can.getWindowHeight() / 2-8; - do { - myDir = randfloat(1000) * 2 * PI; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while(myXX > -4 && myXX < 4); - myCircle = new Circle(myX, myY, 8, WHITE); - can.add(myCircle); + mySpeed = speed; + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while(myXX > -4 && myXX < 4); + myCircle = new Circle(myX, myY, 0, 8, 0,0,0, WHITE); + can.add(myCircle); } /*! @@ -30,7 +30,7 @@ Ball::Ball(Canvas& can, int & speed) { * \return myX The x-coordinate of the Ball object. */ float Ball::getX() const { - return myX; + return myX; } /*! @@ -38,7 +38,7 @@ float Ball::getX() const { * \return myY The y-coordinate of the Ball object. */ float Ball::getY() const { - return myY; + return myY; } /*! @@ -49,12 +49,12 @@ float Ball::getY() const { * \see Paddle class, Pong class. */ void Ball::invert(int choice) { - if(choice == 0) { - myYY = -myYY; - } else if(choice == 1) { - myXX = -myXX; - myYY += randfloat(1000) * 2 - 1; - } + if(choice == 0) { + myYY = -myYY; + } else if(choice == 1) { + myXX = -myXX; + myYY += randfloat(1000) * 2 - 1; + } } /*! @@ -62,17 +62,9 @@ void Ball::invert(int choice) { * \details Actually moves the Ball object around. */ void Ball::move() { - myX += myXX; - myY += myYY; - myCircle->setCenter(myX, myY); -} - - /*! - * \brief Private helper returning a random float. - * \details Calculates a random float to return. - */ -float Ball::randfloat(int divisor) { - return (rand() % divisor) / (float) divisor; + myX += myXX; + myY += myYY; + myCircle->setCenter(myX, myY, 0); } /*! @@ -82,11 +74,11 @@ float Ball::randfloat(int divisor) { * \param can Reference to the Canvas object that has the Ball object. */ void Ball::reset(Canvas& can) { - myX = can.getWindowWidth() / 2-8; - myY = can.getWindowHeight() / 2-8; - do { - myDir = randfloat(1000) * 2 * 3.14159f; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while (myXX > -4 && myXX < 4); + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while (myXX > -4 && myXX < 4); } diff --git a/src/tests/Pong/Ball.h b/src/tests/Pong/Ball.h index e45a3b892..322f5c471 100644 --- a/src/tests/Pong/Ball.h +++ b/src/tests/Pong/Ball.h @@ -21,27 +21,26 @@ using namespace tsgl; */ class Ball { public: - Ball(Canvas& can, int & speed); + Ball(Canvas& can, int & speed); - float getX() const; + float getX() const; - float getY() const; + float getY() const; - void invert(int choice); + void invert(int choice); - void move(); + void move(); - void reset(Canvas& can); + void reset(Canvas& can); - /*! - * \brief Destroys the Ball object. - */ - virtual ~Ball() { delete myCircle; } + /*! + * \brief Destroys the Ball object. + */ + virtual ~Ball() { delete myCircle; } private: - float myX, myY, myXX, myYY, mySpeed, myDir; - float randfloat(int divisor = 10000); - Circle* myCircle; + float myX, myY, myXX, myYY, mySpeed, myDir; + Circle* myCircle; }; #endif /* BALL_H_ */ diff --git a/src/tests/Pong/Paddle.cpp b/src/tests/Pong/Paddle.cpp index 008f66b21..091c7d9c2 100644 --- a/src/tests/Pong/Paddle.cpp +++ b/src/tests/Pong/Paddle.cpp @@ -12,18 +12,18 @@ * \return The constructed Paddle object. */ Paddle::Paddle(Canvas& can, int & speed, int side) { - mySpeed = speed; - myDir = myPoints = 0; - myY = can.getWindowHeight() / 2 - 32; - myRect = new Rectangle(0,0,24,64, BLACK); - if(side == -1) { //Left side - myRect->setColor(BLUE); - myRect->setCenter(20, myY); - } else if(side == 1) { //Right side - myRect->setColor(RED); - myRect->setCenter(can.getWindowWidth() - 20, myY); - } - can.add(myRect); + mySpeed = speed; + myDir = myPoints = 0; + myY = - 32; + myRect = new Rectangle(0,myY,0,24,64,0,0,0, BLACK); + if(side == -1) { //Left side + myRect->setColor(BLUE); + myRect->setCenterX(-can.getWindowWidth() / 2 + 20); + } else if(side == 1) { //Right side + myRect->setColor(RED); + myRect->setCenterX(can.getWindowWidth() / 2 - 20); + } + can.add(myRect); } /*! @@ -33,50 +33,32 @@ Paddle::Paddle(Canvas& can, int & speed, int side) { * \param side The side that the Paddle object is on (left = -1 and the W and S keys are bound, right = 1 and the Up and Down arrow keys are bound). */ void Paddle::bindings(Canvas& can, int side) { - if(side == 1) { //Right - can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = -1;}); - can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = 1;}); - can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); - can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); - } else if(side == -1) { //Left - can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = -1;}); - can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = 1;}); - can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); - can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); - } -} - - /*! - * \brief Draw the Paddle object. - * \details Actually draws the Paddle object onto the Canvas. - * \param can Reference to the Canvas to draw on. - * \param side The side that the Paddle object is drawn to on the Canvas (left = -1, right = 1). - */ -void Paddle::draw(Canvas& can, int side) { - if(side == -1) { //Left side - // ColorFloat color[4]; - // for (unsigned i = 0; i < 4; ++i) { - // color[i] = Colors::randomColor(1.0f); - // } - can.drawRectangle(8, myY, 32, myY + 64, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f) /* color */, false); - } else if(side == 1) { //Right side - can.drawRectangle(can.getWindowWidth() - 24 - 8, myY, can.getWindowWidth() - 8, myY + 64, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f), true); - } + if(side == 1) { //Right + can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = 1;}); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = -1;}); + can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); + } else if(side == -1) { //Left + can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = 1;}); + can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = -1;}); + can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); + } } /*! * \brief Increments the Paddle object's score in the game of Pong. */ void Paddle::increment() { - ++myPoints; + ++myPoints; } /*! * \brief Actually Moves the Paddle object up or down. */ void Paddle::move() { - myY += mySpeed * myDir; - myRect->moveShapeBy(0, mySpeed * myDir); + myY += mySpeed * myDir; + myRect->changeYBy(mySpeed * myDir); } /*! @@ -84,7 +66,7 @@ void Paddle::move() { * \return myPoints The current score of the Paddle object in the game of Pong. */ int Paddle::getPoints() const { - return myPoints; + return myPoints; } /*! @@ -92,7 +74,7 @@ int Paddle::getPoints() const { * \return myY The y-coordinate of the Paddle object. */ float Paddle::getY() const { - return myY; + return myY; } /*! @@ -100,5 +82,5 @@ float Paddle::getY() const { * \details Changes the current direction of the Paddle object (up or down). */ void Paddle::setDir(int direction) { - myDir = direction; + myDir = direction; } diff --git a/src/tests/Pong/Paddle.h b/src/tests/Pong/Paddle.h index b11db2b53..f5b56960b 100644 --- a/src/tests/Pong/Paddle.h +++ b/src/tests/Pong/Paddle.h @@ -25,33 +25,33 @@ using namespace tsgl; */ class Paddle { public: - Paddle(Canvas& can, int & speed, int side); + Paddle(Canvas& can, int & speed, int side); - void bindings(Canvas& can, int side); + void bindings(Canvas& can, int side); - void draw(Canvas& can, int side); + void draw(Canvas& can, int side); - void increment(); + void increment(); - void move(); + void move(); - int getPoints() const; + int getPoints() const; - float getY() const; + float getY() const; - void setDir(int direction); + void setDir(int direction); - /** - * \brief Destroys the Paddle object. - */ - ~Paddle() { delete myRect; } + /** + * \brief Destroys the Paddle object. + */ + ~Paddle() { delete myRect; } private: - int myDir; //-1 = up, 1 = down, 0 = stationary - int myPoints; //Score - int mySpeed; //Speed - float myY; //y-coordinate for Paddle - Rectangle * myRect; + int myDir; //-1 = up, 1 = down, 0 = stationary + int myPoints; //Score + int mySpeed; //Speed + float myY; //y-coordinate for Paddle + Rectangle * myRect; }; #endif /* PADDLE_H_ */ diff --git a/src/tests/Pong/Pong.cpp b/src/tests/Pong/Pong.cpp index 32d9e2603..8ac917cc6 100644 --- a/src/tests/Pong/Pong.cpp +++ b/src/tests/Pong/Pong.cpp @@ -15,16 +15,15 @@ using namespace tsgl; * \param paddleSpeed Reference to the paddle speed to use in the game. */ Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { - leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object - rightPaddle = new Paddle(can, paddleSpeed, 1); - srand(time(NULL)); - //Bind the buttons - leftPaddle->bindings(can, -1); // W & S keys - rightPaddle->bindings(can, 1); // Up and Down arrow keys - pongBall = new Ball(can, ballSpeed); - leftScore = new Text(L"0", can.getWindowWidth() / 2-64, 40, 32, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); - rightScore = new Text(L"0", can.getWindowWidth()/2+64, 40, 32, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); - can.add(leftScore); can.add(rightScore); + leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object + rightPaddle = new Paddle(can, paddleSpeed, 1); + //Bind the buttons + leftPaddle->bindings(can, -1); // W & S keys + rightPaddle->bindings(can, 1); // Up and Down arrow keys + pongBall = new Ball(can, ballSpeed); + // leftScore = new Text(L"0", can.getWindowWidth() / 2-64, 40, 32, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); + // rightScore = new Text(L"0", can.getWindowWidth()/2+64, 40, 32, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); + // can.add(leftScore); can.add(rightScore); } /*! @@ -35,51 +34,51 @@ Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { * \see Paddle class, Ball class. */ void Pong::draw(Canvas& can) { - // While the window has not been closed.... - while (can.isOpen()) { - can.sleep(); - // Move the ball - pongBall->move(); - // Handle ball boundary collisions - if (pongBall->getX() > can.getWindowWidth() + 8) { - leftPaddle->increment(); // Increment the points - leftScore->setText( std::to_wstring(leftPaddle->getPoints())); - pongBall->reset(can); // Reset the ball's position - } else if (pongBall->getX() < -8) { - rightPaddle->increment(); - rightScore->setText( std::to_wstring(rightPaddle->getPoints())); - pongBall->reset(can); - } else if (pongBall->getY() > can.getWindowHeight() - 8 || pongBall->getY() < 8) pongBall->invert(0); //Invert the ball's y-coordinate changer - // Handle ball paddle collisions - // handle left - if (pongBall->getX() - 8 < 32 && - pongBall->getX() - 8 > 16 && - pongBall->getY() > leftPaddle->getY() - 32&& - pongBall->getY() < leftPaddle->getY() + 32) - { - pongBall->invert(1); - } - // handle right - else if (pongBall->getX() + 8 > can.getWindowWidth() - 32 && - pongBall->getX() + 8 < can.getWindowWidth() - 16 && - pongBall->getY() > rightPaddle->getY() - 32 && - pongBall->getY() < rightPaddle->getY() + 32) - { - pongBall->invert(1); + // While the window has not been closed.... + while (can.isOpen()) { + can.sleep(); + // Move the ball + pongBall->move(); + // Handle ball boundary collisions + if (pongBall->getX() > can.getWindowWidth() / 2 + 8) { + leftPaddle->increment(); // Increment the points + // leftScore->setText( std::to_wstring(leftPaddle->getPoints())); + pongBall->reset(can); // Reset the ball's position + } else if (pongBall->getX() < -can.getWindowWidth() / 2 -8) { + rightPaddle->increment(); + // rightScore->setText( std::to_wstring(rightPaddle->getPoints())); + pongBall->reset(can); + } else if (pongBall->getY() > can.getWindowHeight() / 2 - 8 || pongBall->getY() < -can.getWindowHeight() / 2 + 8) pongBall->invert(0); //Invert the ball's y-coordinate changer + // Handle ball paddle collisions + // handle left + if (pongBall->getX() - 8 < -can.getWindowWidth() / 2 + 32 && + pongBall->getX() - 8 > -can.getWindowWidth() / 2 + 16 && + pongBall->getY() > leftPaddle->getY() - 32 && + pongBall->getY() < leftPaddle->getY() + 32) + { + pongBall->invert(1); + } + // handle right + else if (pongBall->getX() + 8 > can.getWindowWidth() / 2 - 32 && + pongBall->getX() + 8 < can.getWindowWidth() / 2 - 16 && + pongBall->getY() > rightPaddle->getY() - 32 && + pongBall->getY() < rightPaddle->getY() + 32) + { + pongBall->invert(1); + } + // Move the paddles if necessary + leftPaddle->move(); + rightPaddle->move(); } - // Move the paddles if necessary - leftPaddle->move(); - rightPaddle->move(); - } } /** * \brief Destroys the Pong game object. */ Pong::~Pong() { - delete pongBall; - delete leftPaddle; - delete rightPaddle; - delete leftScore; - delete rightScore; + delete pongBall; + delete leftPaddle; + delete rightPaddle; + // delete leftScore; + // delete rightScore; } \ No newline at end of file diff --git a/src/tests/Pong/Pong.h b/src/tests/Pong/Pong.h index 38c7c423f..c8af2d11a 100644 --- a/src/tests/Pong/Pong.h +++ b/src/tests/Pong/Pong.h @@ -29,16 +29,16 @@ using namespace tsgl; class Pong { public: - Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); + Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); - void draw(Canvas& can); + void draw(Canvas& can); - ~Pong(); + ~Pong(); private: - Paddle *leftPaddle, *rightPaddle; - Ball *pongBall; - Text *leftScore, *rightScore; + Paddle *leftPaddle, *rightPaddle; + Ball *pongBall; + // Text *leftScore, *rightScore; }; #endif /* PONG_H_ */ diff --git a/src/tests/SeaUrchin/SeaUrchin.cpp b/src/tests/SeaUrchin/SeaUrchin.cpp index b2671f550..042b62f65 100644 --- a/src/tests/SeaUrchin/SeaUrchin.cpp +++ b/src/tests/SeaUrchin/SeaUrchin.cpp @@ -5,26 +5,23 @@ #include "SeaUrchin.h" SeaUrchin::SeaUrchin(Canvas& can, int threadId) { - myOldX = myOldY = 50; - myOldX += (threadId % 8) * 110; - myOldY += (threadId / 8) * 110; - myNewX = myNewY = 0; + myX = -can.getWindowWidth() / 2 + 60; + myY = -can.getWindowHeight() / 2 + 60; + myX += (threadId % 8) * 110; + myY += (threadId / 8) * 110; + float delta = 180 / MY_SPOKES; myColor = Colors::highContrastColor(threadId); for(int i = 0; i < MY_SPOKES; i++) { - Line * l = new Line(myOldX, myOldY, myNewX, myNewY, myColor); - // Line * l = new Line() + Line * l = new Line(myX, myY, 0, 100, i * delta, 0, 0, myColor); lines.push_back(l); can.add(l); } } void SeaUrchin::move(Canvas& can) { - float delta = (2.0f / MY_SPOKES) * PI; + float delta = 180 / MY_SPOKES; for(int j = 0; j < MY_SPOKES; ++j) { - myNewX = myOldX + 50 * cos(j * delta + can.getReps()); - myNewY = myOldY + 50 * sin(j * delta + can.getReps()); - lines[j]->setFirstEnd(myOldX, myOldY); - lines[j]->setSecondEnd(myNewX, myNewY); + lines[j]->setYaw(j * delta + can.getReps() * 180 / PI); } } diff --git a/src/tests/SeaUrchin/SeaUrchin.h b/src/tests/SeaUrchin/SeaUrchin.h index 4c2893450..e163e22d3 100644 --- a/src/tests/SeaUrchin/SeaUrchin.h +++ b/src/tests/SeaUrchin/SeaUrchin.h @@ -48,7 +48,7 @@ class SeaUrchin { private: static const int MY_SPOKES = 8; - int myOldX, myOldY, myNewX, myNewY; + int myX, myY; ColorFloat myColor; std::vector lines; }; diff --git a/src/tests/testNewtonPendulum.cpp b/src/tests/testNewtonPendulum.cpp index 6c4446778..180361c3c 100644 --- a/src/tests/testNewtonPendulum.cpp +++ b/src/tests/testNewtonPendulum.cpp @@ -38,25 +38,29 @@ void newtonPendulumFunction(Canvas& can, int numberOfBalls) { TOPSPEED = 9.0f, //Starting speed of balls AMP = 100; //Inverse amplitude of balls - //Automatic variables - const int WINDOW_W = can.getWindowWidth(), - WINDOW_H = can.getWindowHeight(), - CX = WINDOW_W / 2, //Center of window - CY = WINDOW_H / 2; - const float LINELEN = CY, + const float LINELEN = can.getWindowHeight() / 2, OFFSET = RADIUS*(BALLS-1); - for (float i = -(BALLS/2)+1; i < BALLS/2; ++i) { - can.drawLine(CX + RADIUS*2*i, 0, CX + RADIUS*2*i, LINELEN, BLACK); - can.drawCircle(CX + RADIUS*2*i, CY, RADIUS, GRAY, WHITE); + Line ** lines = new Line*[BALLS - 2]; + Circle ** balls = new Circle*[BALLS - 2]; + for (int i = -(BALLS/2)+1; i < BALLS/2; ++i) { + lines[i + BALLS/2 - 1] = new Line(RADIUS*2*i,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + can.add(lines[i + BALLS/2 - 1]); + balls[i + BALLS/2 - 1] = new Circle(RADIUS*2*i,0,0, RADIUS, 0,0,0,GRAY); + can.add(balls[i + BALLS/2 - 1]); } //Add moving Shapes - Circle* leftCircle = new Circle(CX - OFFSET, LINELEN, RADIUS, GRAY, WHITE); - Circle* rightCircle = new Circle(CX + OFFSET, LINELEN, RADIUS, GRAY, WHITE); - Line* leftLine = new Line(CX - OFFSET, 0, CX - OFFSET, LINELEN, BLACK); - Line* rightLine = new Line(CX + OFFSET, 0, CX + OFFSET, LINELEN, BLACK); - can.add(rightLine); can.add(leftLine); can.add(leftCircle); can.add(rightCircle); + Circle* leftCircle = new Circle(-OFFSET,0,0, RADIUS, 0,0,0,GRAY); + leftCircle->setRotationPoint(-OFFSET, LINELEN, 0); + Circle* rightCircle = new Circle(OFFSET,0,0, RADIUS, 0,0,0,GRAY); + rightCircle->setRotationPoint(OFFSET, LINELEN, 0); + Line* leftLine = new Line(-OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + leftLine->setRotationPoint(-OFFSET, LINELEN, 0); + Line* rightLine = new Line(OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + rightLine->setRotationPoint(OFFSET, LINELEN, 0); + can.add(rightLine); can.add(leftLine); + can.add(leftCircle); can.add(rightCircle); //Computation float rightPos = 0, leftPos = 0; //Initial positions of the edge balls @@ -88,26 +92,25 @@ void newtonPendulumFunction(Canvas& can, int numberOfBalls) { //Move the lines and balls! //Left - leftLine->setSecondEnd(CX - OFFSET + LINELEN*sin(leftPos/AMP), LINELEN*cos(leftPos/AMP)); - leftCircle->setCenter(CX - OFFSET + LINELEN*sin(leftPos/AMP), LINELEN*cos(leftPos/AMP)); + leftLine->setYaw(leftPos/AMP * 180 / PI - 90); + leftCircle->setYaw(leftPos/AMP * 180 / PI); //Right - rightLine->setSecondEnd(CX + OFFSET + LINELEN*sin(rightPos/AMP), LINELEN*cos(rightPos/AMP)); - rightCircle->setCenter(CX + OFFSET + LINELEN*sin(rightPos/AMP), LINELEN*cos(rightPos/AMP)); + rightLine->setYaw(rightPos/AMP * 180 / PI - 90); + rightCircle->setYaw(rightPos/AMP * 180 / PI); } delete leftCircle; delete rightCircle; delete leftLine; delete rightLine; + for (int i = 0; i < BALLS - 2; i++) { + delete balls[i]; + delete lines[i]; + } + delete [] balls; + delete [] lines; } -// saving this if we ever get procedural stuff working -// //Draw stationary lines and balls -// for (float i = -(BALLS/2)+1; i < BALLS/2; ++i) { -// can.drawLine(CX + RADIUS*2*i, 0, CX + RADIUS*2*i, LINELEN); -// can.drawCircle(CX + RADIUS*2*i, CY, RADIUS, GRAY, true); -// } - //Takes command line arguments for the width and height of the screen //as well as for the number of balls int main(int argc, char * argv[]) { diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp index 987d349cd..6e8bfb499 100644 --- a/src/tests/testRectangle.cpp +++ b/src/tests/testRectangle.cpp @@ -36,12 +36,12 @@ void rectangleFunction(Canvas& can) { // rectangle->setHeight(sin(floatVal/90) *100 + 200); // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); + // // rectangle->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // rectangle->changeWidthBy(delta); // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); + // // rectangle->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // rectangle->changeHeightBy(delta); // if (delta > 0) { diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index bbf5234c6..6c548f875 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -35,7 +35,7 @@ void rpFunction(Canvas& can) { // rp->setRadius(sin(floatVal/90)*100 + 300); // if (rp->getRadius() > 300 || rp->getRadius() < 100) { // delta *= -1; - // rp->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); + // rp->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // rp->changeRadiusBy(delta); // if (delta > 0) { diff --git a/src/tests/testRotation.cpp b/src/tests/testRotation.cpp deleted file mode 100644 index d2e309d93..000000000 --- a/src/tests/testRotation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - * testRotation.cpp tests various Drawable rotation functionalities. - */ -#include "tsgl.h" - -using namespace tsgl; - -void rotationFunction(Canvas& can) { - TextureHandler loader; - - Line * l = new Line(0,0,50,50, PURPLE); - l->setCenter(can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - Square * sq = new Square(50, 50, 50, BLUE); - sq->setCenter(can.getWindowWidth() / 2, 3 * can.getWindowHeight() / 4); - - Image * im = new Image("../assets/pics/test.png", loader, 0, 0, 50, 50); - im->setCenter(can.getWindowWidth() / 2, can.getWindowHeight() / 4); - - Text * text = new Text(L"dog", 100, 100, 32, GREEN); - text->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - Arrow * a = new Arrow(0,0,0,50,ORANGE, true); - a->setCenter(can.getWindowWidth() / 2, can.getWindowHeight()/2); - - // l->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - // sq->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - // im->setCenter(3* can.getWindowWidth() / 4, can.getWindowHeight() / 2); - - l->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - im->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - text->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - sq->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - a->setRotationPoint(can.getWindowWidth() / 2, can.getWindowHeight() / 2); - - can.add(sq); - can.add(im); - can.add(text); - can.add(l); - can.add(a); - - float rotation = 0; - while(can.isOpen()) { - sq->setRotation(rotation); - im->setRotation(rotation); - text->setRotation(rotation); - l->setRotation(rotation); - a->setRotation(rotation); - rotation += PI/365; - // sq->moveShapeBy(1,0); - // im->moveImageBy(1,0); - // text->moveTextBy(1,0); - // l->moveShapeBy(1,0); - can.sleepFor(.02); - } - - delete l; - delete sq; - delete im; - delete text; - delete a; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1000; - int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Rotation"); //Can change the size of the window - c.run(rotationFunction); -} \ No newline at end of file diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 468492789..bf421faf2 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -35,7 +35,7 @@ void squareFunction(Canvas& can) { // square->setSideLength(sin(floatVal/90) * 100 + 300); // if (square->getSideLength() > 300 || square->getSideLength() < 100) { // delta *= -1; - // // square->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); + // // square->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // square->changeSideLengthBy(delta); // if (delta > 0) { diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 24658cfe4..349ca78b9 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -30,7 +30,7 @@ void starFunction(Canvas& c) { // s1->setRadius(sin(floatVal/90) * 100 + 300); // if (s1->getRadius() > 300 || s1->getRadius() < 100) { // delta *= -1; - // // s1->setEdgeColor(ColorFloat(saferand(0,255) / 255, saferand(0,255) / 255, saferand(0,255) / 255, 1)); + // // s1->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // s1->changeRadiusBy(delta); // if (delta > 0) { From c2a9538fae236e9357c71a5e11cdb57f8324f229 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 19 Jun 2020 16:02:14 -0400 Subject: [PATCH 036/105] Updated to OpenGL3.3. Image fixed? Text not. --- Makefile | 2 +- assets/shaders/shape.fs | 12 + assets/shaders/shape.vs | 15 ++ assets/shaders/text.fs | 12 + assets/shaders/text.vs | 15 ++ assets/shaders/texture_simple.fs | 12 + assets/shaders/texture_simple.vs | 15 ++ src/TSGL/Arrow.cpp | 16 +- src/TSGL/Canvas.cpp | 328 +++++++++++------------ src/TSGL/Canvas.h | 32 ++- src/TSGL/Circle.cpp | 16 +- src/TSGL/Circle.h | 2 +- src/TSGL/ConcavePolygon.cpp | 57 ++-- src/TSGL/ConcavePolygon.h | 2 +- src/TSGL/ConvexPolygon.cpp | 15 +- src/TSGL/Cube.cpp | 120 +++++---- src/TSGL/Cube.h | 8 +- src/TSGL/Cuboid.cpp | 106 +++++--- src/TSGL/Cuboid.h | 8 +- src/TSGL/Drawable.cpp | 107 -------- src/TSGL/Drawable.h | 40 +-- src/TSGL/Ellipse.cpp | 16 +- src/TSGL/Ellipse.h | 2 +- src/TSGL/Ellipsoid.cpp | 58 ++-- src/TSGL/Ellipsoid.h | 6 +- src/TSGL/Image.cpp | 151 ++++------- src/TSGL/Image.h | 10 +- src/TSGL/Polyline.cpp | 9 +- src/TSGL/Polyline.h | 6 +- src/TSGL/Prism.cpp | 68 +++-- src/TSGL/Prism.h | 8 +- src/TSGL/Pyramid.cpp | 88 +++---- src/TSGL/Pyramid.h | 6 +- src/TSGL/Rectangle.cpp | 2 - src/TSGL/RegularPolygon.cpp | 11 +- src/TSGL/RegularPolygon.h | 4 + src/TSGL/Shape.cpp | 92 ++++++- src/TSGL/Shape.h | 20 +- src/TSGL/Sphere.cpp | 58 ++-- src/TSGL/Sphere.h | 6 +- src/TSGL/Square.cpp | 2 - src/TSGL/Text.cpp | 436 +++++++++++++++---------------- src/TSGL/Text.h | 84 +++--- src/TSGL/Triangle.cpp | 2 + src/TSGL/Util.h | 4 + src/TSGL/getBMP.cpp | 77 ------ src/TSGL/getBMP.h | 13 - src/TSGL/shader_s.h | 198 ++++++++++++++ src/tests/testArrows.cpp | 2 +- src/tests/testCube.cpp | 4 +- src/tests/testCuboid.cpp | 5 +- src/tests/testEllipse.cpp | 18 +- src/tests/testImage.cpp | 4 + src/tests/testPrism.cpp | 18 +- src/tests/testPyramid.cpp | 2 +- src/tests/testRegularPolygon.cpp | 20 +- src/tests/testSquare.cpp | 2 +- src/tests/testStar.cpp | 24 +- src/tests/testText.cpp | 25 +- 59 files changed, 1302 insertions(+), 1199 deletions(-) create mode 100644 assets/shaders/shape.fs create mode 100644 assets/shaders/shape.vs create mode 100644 assets/shaders/text.fs create mode 100644 assets/shaders/text.vs create mode 100644 assets/shaders/texture_simple.fs create mode 100644 assets/shaders/texture_simple.vs delete mode 100644 src/TSGL/getBMP.cpp delete mode 100644 src/TSGL/getBMP.h create mode 100644 src/TSGL/shader_s.h diff --git a/Makefile b/Makefile index 5d40c4ad6..35943c034 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ BINARIES= \ bin/testSphere \ bin/testSquare \ bin/testStar \ + bin/testText \ bin/testTriangle \ bin/testTriangleStrip \ # bin/test_specs \ @@ -132,7 +133,6 @@ BINARIES= \ # bin/testScreenshot \ # bin/testSpectrogram \ # bin/testSpectrum \ -# bin/testText \ # bin/testTextCart \ # bin/testTextTwo \ # bin/testUnits \ diff --git a/assets/shaders/shape.fs b/assets/shaders/shape.fs new file mode 100644 index 000000000..957caa68c --- /dev/null +++ b/assets/shaders/shape.fs @@ -0,0 +1,12 @@ +#version 330 core +out vec4 FragColor; + +in vec4 color; + +// texture samplers +// uniform sampler2D texture1; + +void main() +{ + FragColor = color; +} \ No newline at end of file diff --git a/assets/shaders/shape.vs b/assets/shaders/shape.vs new file mode 100644 index 000000000..186f588af --- /dev/null +++ b/assets/shaders/shape.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec4 aColor; + +out vec4 color; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + color = aColor; +} \ No newline at end of file diff --git a/assets/shaders/text.fs b/assets/shaders/text.fs new file mode 100644 index 000000000..f3112a712 --- /dev/null +++ b/assets/shaders/text.fs @@ -0,0 +1,12 @@ +#version 330 core +in vec2 TexCoords; +out vec4 FragColor; + +uniform sampler2D text; +uniform vec4 textColor; + +void main() +{ + vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); + FragColor = textColor * sampled; +} \ No newline at end of file diff --git a/assets/shaders/text.vs b/assets/shaders/text.vs new file mode 100644 index 000000000..c9601998e --- /dev/null +++ b/assets/shaders/text.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoords; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + TexCoords = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/assets/shaders/texture_simple.fs b/assets/shaders/texture_simple.fs new file mode 100644 index 000000000..44224d03a --- /dev/null +++ b/assets/shaders/texture_simple.fs @@ -0,0 +1,12 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +// texture sampler +uniform sampler2D texture1; + +void main() +{ + FragColor = texture(texture1, TexCoords); +} \ No newline at end of file diff --git a/assets/shaders/texture_simple.vs b/assets/shaders/texture_simple.vs new file mode 100644 index 000000000..9ce732af5 --- /dev/null +++ b/assets/shaders/texture_simple.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoords; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + TexCoords = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index d9ad02688..eac36bc25 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -141,17 +141,17 @@ void Arrow::changeWidthBy(GLfloat delta) { */ void Arrow::setColor(ColorFloat c[]) { for(int i = 0; i < 7; i++) { - colors[i*4] = c[i/5].R; - colors[i*4 + 1] = c[i/5].G; - colors[i*4 + 2] = c[i/5].B; - colors[i*4 + 3] = c[i/5].A; + vertices[i*7 + 3] = c[i/5].R; + vertices[i*7 + 4] = c[i/5].G; + vertices[i*7 + 5] = c[i/5].B; + vertices[i*7 + 6] = c[i/5].A; } if (isDoubleArrow) { for(int i = 7; i < 10; i++) { - colors[i*4] = c[1].R; - colors[i*4 + 1] = c[1].G; - colors[i*4 + 2] = c[1].B; - colors[i*4 + 3] = c[1].A; + vertices[i*7 + 3] = c[1].R; + vertices[i*7 + 4] = c[1].G; + vertices[i*7 + 5] = c[1].B; + vertices[i*7 + 6] = c[1].A; } } } diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index e03e31c7d..ed3df0523 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -11,49 +11,49 @@ namespace tsgl { // Shader sources -static const GLchar* vertexSource = - "#version 150 core\n" - "in vec3 position;" - "in vec4 color;" - "out vec4 Color;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 1.0);" - "}"; -static const GLchar* fragmentSource = - "#version 150\n" - "in vec4 Color;" - "out vec4 outColor;" - "void main() {" - " outColor = vec4(Color);" - "}"; -static const GLchar* textureVertexSource = - "#version 150 core\n" - "in vec3 position;" - "in vec4 color;" - "in vec2 texcoord;" - "out vec4 Color;" - "out vec2 Texcoord;" - "uniform mat4 model;" - "uniform mat4 view;" - "uniform mat4 proj;" - "void main() {" - " Texcoord = texcoord;" - " Color = color;" - " gl_Position = proj * view * model * vec4(position, 1.0);" - "}"; -static const GLchar* textureFragmentSource = - "#version 150\n" - "in vec4 Color;" - "in vec2 Texcoord;" - "out vec4 outColor;" - "uniform sampler2D tex;" - "void main() {" - " outColor = texture(tex, Texcoord) * vec4(Color);" - "}"; +// static const GLchar* vertexSource = +// "#version 150 core\n" +// "in vec3 position;" +// "in vec4 color;" +// "out vec4 Color;" +// "uniform mat4 model;" +// "uniform mat4 view;" +// "uniform mat4 proj;" +// "void main() {" +// " Color = color;" +// " gl_Position = proj * view * model * vec4(position, 1.0);" +// "}"; +// static const GLchar* fragmentSource = +// "#version 150\n" +// "in vec4 Color;" +// "out vec4 outColor;" +// "void main() {" +// " outColor = vec4(Color);" +// "}"; +// static const GLchar* textureVertexSource = +// "#version 150 core\n" +// "in vec3 position;" +// "in vec4 color;" +// "in vec2 texcoord;" +// "out vec4 Color;" +// "out vec2 Texcoord;" +// "uniform mat4 model;" +// "uniform mat4 view;" +// "uniform mat4 proj;" +// "void main() {" +// " Texcoord = texcoord;" +// " Color = color;" +// " gl_Position = proj * view * model * vec4(position, 1.0);" +// "}"; +// static const GLchar* textureFragmentSource = +// "#version 150\n" +// "in vec4 Color;" +// "in vec2 Texcoord;" +// "out vec4 outColor;" +// "uniform sampler2D tex;" +// "void main() {" +// " outColor = texture(tex, Texcoord) * vec4(Color);" +// "}"; int Canvas::drawBuffer = GL_FRONT_LEFT; bool Canvas::glfwIsReady = false; @@ -260,44 +260,23 @@ void Canvas::draw() // Draw stuff glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // glMatrixMode(GL_PROJECTION_MATRIX); // glMatrixMode is deprecated, so it's ignored regardless of whether it's called - glLoadIdentity(); - gluPerspective( 60, (double)windowWidth / (double)windowHeight, 0.1, 1000 ); - - // glMatrixMode(GL_MODELVIEW_MATRIX); // glMatrixMode is deprecated, so it's ignored regardless of whether it's called - // based on a gluPerspective angle of 60 (PI/3) - glTranslatef(0,0,(-windowHeight / 2) / tan(PI/6)); - - /* commented out stuff really only seems to - need to be called once per draw cycle tbh */ - // glEnableClientState(GL_VERTEX_ARRAY); - // glEnableClientState(GL_COLOR_ARRAY); if (objectBuffer.size() > 0) { for (unsigned int i = 0; i < objectBuffer.size(); i++) { Drawable* d = objectBuffer[i]; - // if(d->isProcessed()) { - // d->draw(); - // } if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - // should be noted that the texture shader programs do literally nothing right now, and need correction. - // calls to stuff like glEnableClientState() override them, it seems. - // but at least they're not causing compilation errors anymore. - // tried fixing them, for image at least, but I think model, view, and projection matrices need work. - textureShaders(true); - d->draw(); - textureShaders(false); + textureShaders(d->getShaderType()); + if (d->getShaderType() == SHAPE_SHADER_TYPE) { + d->draw(shapeShader); + } else if (d->getShaderType() == IMAGE_SHADER_TYPE) { + d->draw(imageShader); + } else if (d->getShaderType() == TEXT_SHADER_TYPE) { + d->draw(textShader); } } } } else { objectBufferEmpty = true; } - /* Cleanup states */ - // glDisableClientState(GL_COLOR_ARRAY); - // glDisableClientState(GL_VERTEX_ARRAY); // Update our screenBuffer copy with the screen // glViewport(0,0,winWidth*scaling,winHeight*scaling); @@ -2073,18 +2052,21 @@ int Canvas::getWindowY() { void Canvas::glDestroy() { // Free up our resources - glDetachShader(shaderProgram, shaderFragment); - glDetachShader(shaderProgram, shaderVertex); - glDeleteShader(shaderFragment); - glDeleteShader(shaderVertex); - glDeleteProgram(shaderProgram); - glDetachShader(textureShaderProgram, textureShaderFragment); - glDetachShader(textureShaderProgram, textureShaderVertex); - glDeleteShader(textureShaderFragment); - glDeleteShader(textureShaderVertex); - glDeleteProgram(textureShaderProgram); - glDeleteBuffers(1, &vertexBuffer); - glDeleteVertexArrays(1, &vertexArray); + // glDetachShader(shaderProgram, shaderFragment); + // glDetachShader(shaderProgram, shaderVertex); + // glDeleteShader(shaderFragment); + // glDeleteShader(shaderVertex); + // glDeleteProgram(shaderProgram); + // glDetachShader(textureShaderProgram, textureShaderFragment); + // glDetachShader(textureShaderProgram, textureShaderVertex); + // glDeleteShader(textureShaderFragment); + // glDeleteShader(textureShaderVertex); + // glDeleteProgram(textureShaderProgram); + delete textShader; + delete shapeShader; + delete imageShader; + glDeleteBuffers(1, &VBO); + glDeleteVertexArrays(1, &VAO); } /*! @@ -2192,7 +2174,7 @@ void Canvas::initGl() { #endif // Specify how texture values combine with current surface color values. - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE + // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE glEnable(GL_TEXTURE_2D); // Enable and disable necessary stuff @@ -2200,9 +2182,6 @@ void Canvas::initGl() { glDepthFunc(GL_LEQUAL); glDisable(GL_CULL_FACE); glCullFace(GL_BACK); - // glDisable(GL_DEPTH_TEST); // Disable depth testing because we're not drawing in 3d - // glDisable(GL_DITHER); // Disable dithering because pixels do not (generally) overlap - // glDisable(GL_CULL_FACE); // Disable culling because the camera is stationary glEnable(GL_BLEND); // Enable blending glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Set blending mode to standard alpha blending @@ -2259,58 +2238,43 @@ void Canvas::initGlew() { // TsglDebug("EXT Framebuffer available"); #endif - GLint status; - - // Create and bind our Vertex Array Object - glGenVertexArrays(1, &vertexArray); - glBindVertexArray(vertexArray); - - // Create and bind our Vertex Buffer Object - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - - // Create / compile vertex shader - shaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(shaderVertex, 1, &vertexSource, NULL); - glCompileShader(shaderVertex); - glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile fragment shader - shaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(shaderFragment, 1, &fragmentSource, NULL); - glCompileShader(shaderFragment); - glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to a shader program, link the program - shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, shaderVertex); - glAttachShader(shaderProgram, shaderFragment); - glBindFragDataLocation(shaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our standard shader - glLinkProgram(shaderProgram); - - // Create / compile textured vertex shader - textureShaderVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(textureShaderVertex, 1, &textureVertexSource, NULL); - glCompileShader(textureShaderVertex); - glGetShaderiv(textureShaderVertex, GL_COMPILE_STATUS, &status); - - // Create / compile textured fragment shader - textureShaderFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(textureShaderFragment, 1, &textureFragmentSource, NULL); - glCompileShader(textureShaderFragment); - glGetShaderiv(textureShaderFragment, GL_COMPILE_STATUS, &status); - - // Attach both shaders to another shader program, link the program - textureShaderProgram = glCreateProgram(); - glAttachShader(textureShaderProgram, textureShaderVertex); - glAttachShader(textureShaderProgram, textureShaderFragment); - glBindFragDataLocation(textureShaderProgram, 0, "outColor"); - - // Specify the layout of the vertex data in our textured shader - glLinkProgram(textureShaderProgram); - textureShaders(false); + // GLint status; + + // Create our Vertex Array Object + glGenVertexArrays(1, &VAO); + + // Create our Vertex Buffer Object + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + + // glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)winWidth/(float)winHeight, 0.1f, 1000.0f); + // glm::mat4 view = glm::mat4(1.0f); + // view = glm::translate(view, glm::vec3(0.0f, 0.0f, -((winHeight / 2) / tan(glm::pi()/6)))); + + textShader = new Shader("./assets/shaders/text.vs", "./assets/shaders/text.fs"); + + // textShader->use(); + // glUniformMatrix4fv(glGetUniformLocation(textShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + // unsigned int viewLoc = glGetUniformLocation(textShader->ID, "view"); + // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); + + shapeShader = new Shader("./assets/shaders/shape.vs", "./assets/shaders/shape.fs"); + + // shapeShader->use(); + // glUniformMatrix4fv(glGetUniformLocation(shapeShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + // viewLoc = glGetUniformLocation(shapeShader->ID, "view"); + // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); + + imageShader = new Shader("./assets/shaders/texture_simple.vs", "./assets/shaders/texture_simple.fs"); + + // imageShader->use(); + // glUniformMatrix4fv(glGetUniformLocation(imageShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + // viewLoc = glGetUniformLocation(imageShader->ID, "view"); + // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); + + /****** NEW ******/ // Create a framebuffer @@ -2363,10 +2327,10 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); // Set target GL minor version to 2.0 glfwWindowHint(GLFW_CLIENT_API,GLFW_OPENGL_ES_API); // Pi uses OpenGL ES #else - // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Set target GL major version to 3 - // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Set target GL minor version to 3.2 - // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile - // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Set target GL major version to 3 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Set target GL minor version to 3.2 + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer @@ -2752,46 +2716,54 @@ void Canvas::takeScreenShot() { if (toRecord == 0) toRecord = 1; } -void Canvas::textureShaders(bool on) { - GLint program; - if (!on) { - program = shaderProgram; - - // Relocate the shader attributes - GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); +void Canvas::textureShaders(unsigned int sType) { + Shader * program; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0); - GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); glEnableVertexAttribArray(colAttrib); - glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*) (3 * sizeof(float))); - - } else { - program = textureShaderProgram; - - // Relocate the shader attributes - GLint texturePosAttrib = glGetAttribLocation(textureShaderProgram, "position"); - glEnableVertexAttribArray(texturePosAttrib); - glVertexAttribPointer(texturePosAttrib, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0); - GLint textureColAttrib = glGetAttribLocation(textureShaderProgram, "color"); - glEnableVertexAttribArray(textureColAttrib); - glVertexAttribPointer(textureColAttrib, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(float), - (void*) (3 * sizeof(float))); - GLint textureTexAttrib = glGetAttribLocation(textureShaderProgram, "texcoord"); - glEnableVertexAttribArray(textureTexAttrib); - glVertexAttribPointer(textureTexAttrib, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(float), - (void*) (7 * sizeof(float))); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + } else if (sType == IMAGE_SHADER_TYPE) { + program = imageShader; + GLint posAttrib = glGetAttribLocation(imageShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(imageShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); } - - // Reallocate the shader program for use - glUseProgram(program); + + program->use(); // Recompute the camera matrices - uniModel = glGetUniformLocation(program, "model"); - uniView = glGetUniformLocation(program, "view"); - uniProj = glGetUniformLocation(program, "proj"); - - // Update the camera - setupCamera(); + uniModel = glGetUniformLocation(program->ID, "model"); + uniView = glGetUniformLocation(program->ID, "view"); + uniProj = glGetUniformLocation(program->ID, "projection"); + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)winWidth/(float)winHeight, 0.1f, 1000.0f); + glm::mat4 view = glm::mat4(1.0f); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -((winHeight / 2) / tan(glm::pi()/6)))); + glm::mat4 model = glm::mat4(1.0f); + + glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(uniView, 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model)); } /*! diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 96c28dab4..c7d6b6261 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -34,12 +34,21 @@ #include "Sphere.h" // Our own class for drawing spheres #include "Square.h" // Our own class for drawing squares #include "Star.h" // Our own class for drawing stars -// #include "Text.h" // Our own class for drawing text +#include "Text.h" // Our own class for drawing text #include "Timer.h" // Our own timer for steady FPS #include "Triangle.h" // Our own class for drawing triangles #include "TextureHandler.h" // Currently used for screenshots, might change this #include "Util.h" // Needed constants and has cmath for performing math operations +#include "shader_s.h" +#include +#include +#include + +#include +#include +#include + #include // For callback upon key presses #include // DEBUGGING #include // Needed for locking the Canvas for thread-safety @@ -117,25 +126,28 @@ class Canvas { GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window unsigned proceduralBufferSize; doubleFunction scrollFunction; // Single function object for scrolling - GLtexture shaderFragment, // Address of the fragment shader - shaderProgram, // Addres of the shader program to send to the GPU - shaderVertex; // Address of the vertex shader + // GLtexture shaderFragment, // Address of the fragment shader + // shaderProgram, // Addres of the shader program to send to the GPU + // shaderVertex; // Address of the vertex shader + Shader * textShader; + Shader * shapeShader; + Shader * imageShader; std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread int syncMutexLocked; // Whether the syncMutex is currently locked int syncMutexOwner; // Thread ID of the owner of the syncMutex - GLtexture textureShaderFragment, // Address of the textured fragment shader - textureShaderProgram, // Addres of the textured shader program to send to the GPU - textureShaderVertex; // Address of the textured vertex shader + // GLtexture textureShaderFragment, // Address of the textured fragment shader + // textureShaderProgram, // Addres of the textured shader program to send to the GPU + // textureShaderVertex; // Address of the textured vertex shader bool toClose; // If the Canvas has been asked to close unsigned int toRecord; // To record the screen each frame GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - GLtexture vertexArray, // Address of GL's array buffer object - vertexBuffer; // Address of GL's vertex buffer object + GLuint VAO, // Address of GL's array buffer object + VBO; // Address of GL's vertex buffer object float* vertexData; // The allPoints array GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not @@ -175,7 +187,7 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void textureShaders(bool state); // Turn textures on or off + void textureShaders(unsigned int choice); // Turn textures on or off // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works // static bool testLine(Canvas& can); // Unit tester for lines static bool testAccessors(Canvas& can); // Unit tester for accessor methods diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 4d5ccbb59..f02b84382 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -94,17 +94,17 @@ void Circle::changeRadiusBy(GLfloat delta) { * \param c An array of the new ColorFloats. */ void Circle::setColor(ColorFloat c[]) { - colors[0] = c[0].R; - colors[1] = c[0].G; - colors[2] = c[0].B; - colors[3] = c[0].A; + vertices[3] = c[0].R; + vertices[4] = c[0].G; + vertices[5] = c[0].B; + vertices[6] = c[0].A; int colorIndex; for (int i = 1; i < numberOfVertices; ++i) { colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); - colors[i*4] = c[colorIndex].R; - colors[i*4 + 1] = c[colorIndex].G; - colors[i*4 + 2] = c[colorIndex].B; - colors[i*4 + 3] = c[colorIndex].A; + vertices[i*7 + 3] = c[colorIndex].R; + vertices[i*7 + 4] = c[colorIndex].G; + vertices[i*7 + 5] = c[colorIndex].B; + vertices[i*7 + 6] = c[colorIndex].A; } } diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index 308180ede..dd6224486 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -32,7 +32,7 @@ class Circle : public ConvexPolygon { */ GLfloat getRadius() { return myRadius; } - void setColor(ColorFloat c) { Drawable::setColor(c); } + void setColor(ColorFloat c) { Shape::setColor(c); } void setColor(ColorFloat c[]); diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index 099e9629e..c078361bd 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -15,8 +15,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numberOfVertices = numVertices; numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 3]; - colors = new GLfloat[numberOfOutlineVertices * 4]; + vertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } @@ -39,8 +38,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numberOfVertices = numVertices; numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 3]; - colors = new GLfloat[numberOfOutlineVertices * 4]; + vertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -66,8 +64,7 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numberOfVertices = numVertices; numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 3]; - colors = new GLfloat[numberOfOutlineVertices * 4]; + vertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -80,21 +77,24 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int * \details This function actually draws the ConcavePolygon to the Canvas. * \note This function overrides Drawable::draw() * \note This function does nothing if the vertex buffer is not yet full. - * \note A message indicating that the Drawable cannot be drawn yet will be given + * \note A message indicating that the ConcavePolygon cannot be drawn yet will be given * if the above condition is met (vertex buffer = not full). */ -void ConcavePolygon::draw() { +void ConcavePolygon::draw(Shader * shader) { if (!init) { TsglDebug("Vertex buffer is not full."); return; } - glPushMatrix(); - glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); - glRotatef(myCurrentYaw, 0, 0, 1); - glRotatef(myCurrentPitch, 0, 1, 0); - glRotatef(myCurrentRoll, 1, 0, 0); - glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); - glScalef(myXScale, myYScale, myZScale); + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); /* extra stencil buffer stuff, because it's concave */ glClearStencil(0); @@ -105,12 +105,7 @@ void ConcavePolygon::draw() { glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); /* end */ - /* We have a color array and a vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - glColorPointer(4, GL_FLOAT, 0, colors); - + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); glDrawArrays(geometryType, 0, numberOfVertices); /* extra stencil buffer stuff, because it's concave */ @@ -118,25 +113,17 @@ void ConcavePolygon::draw() { glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - glVertexPointer(3, GL_FLOAT, 0, vertices); - glColorPointer(4, GL_FLOAT, 0, colors); - + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); glDrawArrays(geometryType, 0, numberOfVertices); glDisable(GL_STENCIL_TEST); /* end */ - if (edgesOutlined) { - glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); - glColorPointer(4, GL_FLOAT, 0, outlineArray); - - glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); - } - - glPopMatrix(); + // if (edgesOutlined) { + // glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); + // glColorPointer(4, GL_FLOAT, 0, outlineArray); - /* Cleanup states */ - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + // glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); + // } } } diff --git a/src/TSGL/ConcavePolygon.h b/src/TSGL/ConcavePolygon.h index 29f53d442..c964a6c6d 100755 --- a/src/TSGL/ConcavePolygon.h +++ b/src/TSGL/ConcavePolygon.h @@ -30,7 +30,7 @@ class ConcavePolygon : public Shape { ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]); - virtual void draw(); + virtual void draw(Shader * shader); }; } diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 72b570dbc..ec041ece7 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -12,11 +12,10 @@ namespace tsgl { */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - geometryType = GL_POLYGON; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } @@ -34,11 +33,10 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - geometryType = GL_POLYGON; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -59,11 +57,10 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - geometryType = GL_POLYGON; + geometryType = GL_TRIANGLE_FAN; numberOfVertices = numberOfOutlineVertices = numVertices; outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 87ef174fe..12b755223 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -17,49 +17,60 @@ namespace tsgl { * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c) -: Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices +: Shape(x, y, z, yaw, pitch, roll) { if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } attribMutex.lock(); - geometryType = GL_QUADS; + geometryType = GL_TRIANGLES; mySideLength = sideLength; myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = numberOfOutlineVertices = 24; + numberOfVertices = numberOfOutlineVertices = 36; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); } @@ -78,49 +89,60 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch * \return A new Cube with a buffer for storing the specified numbered of vertices. */ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat c[]) -: Drawable(x, y, z, yaw, pitch, roll) { // FIXME vertices +: Shape(x, y, z, yaw, pitch, roll) { if (sideLength <= 0) { TsglDebug("Cannot have a Cube with non-positive sidelength."); } attribMutex.lock(); - geometryType = GL_QUADS; + geometryType = GL_TRIANGLES; mySideLength = sideLength; myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = numberOfOutlineVertices = 24; + numberOfVertices = numberOfOutlineVertices = 36; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(0.5, -0.5, 0.5, c[5]); addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, 0.5, -0.5, c[7]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, -0.5, 0.5, c[5]); addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(0.5, 0.5, -0.5, c[7]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, -0.5, 0.5, c[5]); } @@ -165,45 +187,45 @@ void Cube::changeSideLengthBy(GLfloat delta) { */ void Cube::setColor(ColorFloat c[]) { attribMutex.lock(); - colors[0] = colors[36] = colors[64] = c[0].R; - colors[1] = colors[37] = colors[65] = c[0].G; - colors[2] = colors[38] = colors[66] = c[0].B; - colors[3] = colors[39] = colors[67] = c[0].A; - - colors[4] = colors[40] = colors[80] = c[1].R; - colors[5] = colors[41] = colors[81] = c[1].G; - colors[6] = colors[42] = colors[82] = c[1].B; - colors[7] = colors[43] = colors[83] = c[1].A; - - colors[8] = colors[56] = colors[84] = c[2].R; - colors[9] = colors[57] = colors[85] = c[2].G; - colors[10] = colors[58] = colors[86] = c[2].B; - colors[11] = colors[59] = colors[87] = c[2].A; - - colors[12] = colors[52] = colors[68] = c[3].R; - colors[13] = colors[53] = colors[69] = c[3].G; - colors[14] = colors[54] = colors[70] = c[3].B; - colors[15] = colors[55] = colors[71] = c[3].A; - - colors[16] = colors[32] = colors[76] = c[4].R; - colors[17] = colors[33] = colors[77] = c[4].G; - colors[18] = colors[34] = colors[78] = c[4].B; - colors[19] = colors[35] = colors[79] = c[4].A; - - colors[20] = colors[44] = colors[92] = c[5].R; - colors[21] = colors[45] = colors[93] = c[5].G; - colors[22] = colors[46] = colors[94] = c[5].B; - colors[23] = colors[47] = colors[95] = c[5].A; - - colors[24] = colors[60] = colors[88] = c[6].R; - colors[25] = colors[61] = colors[89] = c[6].G; - colors[26] = colors[62] = colors[90] = c[6].B; - colors[27] = colors[63] = colors[91] = c[6].A; - - colors[28] = colors[48] = colors[72] = c[7].R; - colors[29] = colors[49] = colors[73] = c[7].G; - colors[30] = colors[50] = colors[74] = c[7].B; - colors[31] = colors[51] = colors[75] = c[7].A; + vertices[3] = vertices[24] = vertices[94] = vertices[171] = vertices[192] = c[0].R; + vertices[4] = vertices[25] = vertices[95] = vertices[172] = vertices[193] = c[0].G; + vertices[5] = vertices[26] = vertices[96] = vertices[173] = vertices[194] = c[0].B; + vertices[6] = vertices[27] = vertices[97] = vertices[174] = vertices[195] = c[0].A; + + vertices[10] = vertices[101] = vertices[115] = vertices[213] = vertices[234] = c[1].R; + vertices[11] = vertices[102] = vertices[116] = vertices[214] = vertices[235] = c[1].G; + vertices[12] = vertices[103] = vertices[117] = vertices[215] = vertices[236] = c[1].B; + vertices[13] = vertices[104] = vertices[118] = vertices[216] = vertices[237] = c[1].A; + + vertices[17] = vertices[31] = vertices[143] = vertices[157] = vertices[220] = c[2].R; + vertices[18] = vertices[32] = vertices[144] = vertices[158] = vertices[221] = c[2].G; + vertices[19] = vertices[33] = vertices[145] = vertices[159] = vertices[222] = c[2].B; + vertices[20] = vertices[34] = vertices[146] = vertices[160] = vertices[223] = c[2].A; + + vertices[38] = vertices[136] = vertices[178] = c[3].R; + vertices[39] = vertices[137] = vertices[179] = c[3].G; + vertices[40] = vertices[138] = vertices[180] = c[3].B; + vertices[41] = vertices[139] = vertices[181] = c[3].A; + + vertices[45] = vertices[66] = vertices[87] = vertices[108] = vertices[206] = c[4].R; + vertices[46] = vertices[67] = vertices[88] = vertices[109] = vertices[207] = c[4].G; + vertices[47] = vertices[68] = vertices[89] = vertices[110] = vertices[208] = c[4].B; + vertices[48] = vertices[69] = vertices[90] = vertices[111] = vertices[209] = c[4].A; + + vertices[52] = vertices[122] = vertices[248] = c[5].R; + vertices[53] = vertices[123] = vertices[249] = c[5].G; + vertices[54] = vertices[124] = vertices[250] = c[5].B; + vertices[55] = vertices[125] = vertices[251] = c[5].A; + + vertices[59] = vertices[73] = vertices[164] = vertices[227] = vertices[241] = c[6].R; + vertices[60] = vertices[74] = vertices[165] = vertices[228] = vertices[242] = c[6].G; + vertices[61] = vertices[75] = vertices[166] = vertices[229] = vertices[243] = c[6].B; + vertices[62] = vertices[76] = vertices[167] = vertices[230] = vertices[244] = c[6].A; + + vertices[80] = vertices[129] = vertices[150] = vertices[185] = vertices[199] = c[7].R; + vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; + vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; + vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; attribMutex.unlock(); } diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 8c9558de1..44f422f50 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -5,7 +5,7 @@ #ifndef CUBE_H_ #define CUBE_H_ -#include "Drawable.h" // For extending our Prism object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cube * \brief Draw an arbitrary Cube with colored vertices. * \details Cube is a class for holding vertex data for a Cube. - * \details Cube is a 6-sided subclass of Drawable with all square faces. + * \details Cube is a 6-sided subclass of Shape with all square faces. */ -class Cube : public Drawable { +class Cube : public Shape { protected: GLfloat mySideLength; public: @@ -33,7 +33,7 @@ class Cube : public Drawable { */ virtual GLfloat getSideLength() { return mySideLength; } - virtual void setColor(ColorFloat c) { Drawable::setColor(c); } + virtual void setColor(ColorFloat c) { Shape::setColor(c); } virtual void setColor(ColorFloat c[]); diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index fb88d2822..ff0802607 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -19,51 +19,62 @@ namespace tsgl { * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c) -: Drawable(x, y, z, yaw, pitch, roll) { +: Shape(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } attribMutex.lock(); - geometryType = GL_QUADS; + geometryType = GL_TRIANGLES; myLength = length; myWidth = width; myHeight = height; myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = numberOfOutlineVertices = 24; + numberOfVertices = numberOfOutlineVertices = 36; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(-0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, -0.5, -0.5, c); + addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(-0.5, 0.5, 0.5, c); + addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, 0.5, -0.5, c); addVertex(0.5, 0.5, -0.5, c); + addVertex(-0.5, -0.5, -0.5, c); + addVertex(0.5, 0.5, -0.5, c); addVertex(0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); addVertex(-0.5, 0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); + addVertex(-0.5, -0.5, 0.5, c); + addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); } @@ -84,51 +95,62 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat * \return A new Cuboid with a buffer for storing the specified numbered of vertices. */ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat length, float yaw, float pitch, float roll, ColorFloat c[]) -: Drawable(x, y, z, yaw, pitch, roll) { +: Shape(x, y, z, yaw, pitch, roll) { if (length <= 0 || width <= 0 || height <= 0) { TsglDebug("Cannot have a Cuboid with non-positive length, width, or height."); } attribMutex.lock(); - geometryType = GL_QUADS; + geometryType = GL_TRIANGLES; myLength = length; myWidth = width; myHeight = height; myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = numberOfOutlineVertices = 24; + numberOfVertices = numberOfOutlineVertices = 36; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(0.5, -0.5, 0.5, c[5]); addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, 0.5, -0.5, c[7]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, -0.5, -0.5, c[4]); + addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, -0.5, 0.5, c[5]); addVertex(0.5, 0.5, -0.5, c[7]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(-0.5, 0.5, 0.5, c[2]); + addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, 0.5, -0.5, c[3]); addVertex(0.5, 0.5, -0.5, c[7]); + addVertex(-0.5, -0.5, -0.5, c[0]); + addVertex(0.5, 0.5, -0.5, c[7]); addVertex(0.5, -0.5, -0.5, c[4]); addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(-0.5, 0.5, 0.5, c[2]); addVertex(0.5, 0.5, 0.5, c[6]); + addVertex(-0.5, -0.5, 0.5, c[1]); + addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, -0.5, 0.5, c[5]); } @@ -229,45 +251,45 @@ void Cuboid::changeHeightBy(GLfloat delta) { */ void Cuboid::setColor(ColorFloat c[]) { attribMutex.lock(); - colors[0] = colors[36] = colors[64] = c[0].R; - colors[1] = colors[37] = colors[65] = c[0].G; - colors[2] = colors[38] = colors[66] = c[0].B; - colors[3] = colors[39] = colors[67] = c[0].A; + vertices[3] = vertices[24] = vertices[94] = vertices[171] = vertices[192] = c[0].R; + vertices[4] = vertices[25] = vertices[95] = vertices[172] = vertices[193] = c[0].G; + vertices[5] = vertices[26] = vertices[96] = vertices[173] = vertices[194] = c[0].B; + vertices[6] = vertices[27] = vertices[97] = vertices[174] = vertices[195] = c[0].A; - colors[4] = colors[40] = colors[80] = c[1].R; - colors[5] = colors[41] = colors[81] = c[1].G; - colors[6] = colors[42] = colors[82] = c[1].B; - colors[7] = colors[43] = colors[83] = c[1].A; + vertices[10] = vertices[101] = vertices[115] = vertices[213] = vertices[234] = c[1].R; + vertices[11] = vertices[102] = vertices[116] = vertices[214] = vertices[235] = c[1].G; + vertices[12] = vertices[103] = vertices[117] = vertices[215] = vertices[236] = c[1].B; + vertices[13] = vertices[104] = vertices[118] = vertices[216] = vertices[237] = c[1].A; - colors[8] = colors[56] = colors[84] = c[2].R; - colors[9] = colors[57] = colors[85] = c[2].G; - colors[10] = colors[58] = colors[86] = c[2].B; - colors[11] = colors[59] = colors[87] = c[2].A; + vertices[17] = vertices[31] = vertices[143] = vertices[157] = vertices[220] = c[2].R; + vertices[18] = vertices[32] = vertices[144] = vertices[158] = vertices[221] = c[2].G; + vertices[19] = vertices[33] = vertices[145] = vertices[159] = vertices[222] = c[2].B; + vertices[20] = vertices[34] = vertices[146] = vertices[160] = vertices[223] = c[2].A; - colors[12] = colors[52] = colors[68] = c[3].R; - colors[13] = colors[53] = colors[69] = c[3].G; - colors[14] = colors[54] = colors[70] = c[3].B; - colors[15] = colors[55] = colors[71] = c[3].A; + vertices[38] = vertices[136] = vertices[178] = c[3].R; + vertices[39] = vertices[137] = vertices[179] = c[3].G; + vertices[40] = vertices[138] = vertices[180] = c[3].B; + vertices[41] = vertices[139] = vertices[181] = c[3].A; - colors[16] = colors[32] = colors[76] = c[4].R; - colors[17] = colors[33] = colors[77] = c[4].G; - colors[18] = colors[34] = colors[78] = c[4].B; - colors[19] = colors[35] = colors[79] = c[4].A; + vertices[45] = vertices[66] = vertices[87] = vertices[108] = vertices[206] = c[4].R; + vertices[46] = vertices[67] = vertices[88] = vertices[109] = vertices[207] = c[4].G; + vertices[47] = vertices[68] = vertices[89] = vertices[110] = vertices[208] = c[4].B; + vertices[48] = vertices[69] = vertices[90] = vertices[111] = vertices[209] = c[4].A; - colors[20] = colors[44] = colors[92] = c[5].R; - colors[21] = colors[45] = colors[93] = c[5].G; - colors[22] = colors[46] = colors[94] = c[5].B; - colors[23] = colors[47] = colors[95] = c[5].A; + vertices[52] = vertices[122] = vertices[248] = c[5].R; + vertices[53] = vertices[123] = vertices[249] = c[5].G; + vertices[54] = vertices[124] = vertices[250] = c[5].B; + vertices[55] = vertices[125] = vertices[251] = c[5].A; - colors[24] = colors[60] = colors[88] = c[6].R; - colors[25] = colors[61] = colors[89] = c[6].G; - colors[26] = colors[62] = colors[90] = c[6].B; - colors[27] = colors[63] = colors[91] = c[6].A; + vertices[59] = vertices[73] = vertices[164] = vertices[227] = vertices[241] = c[6].R; + vertices[60] = vertices[74] = vertices[165] = vertices[228] = vertices[242] = c[6].G; + vertices[61] = vertices[75] = vertices[166] = vertices[229] = vertices[243] = c[6].B; + vertices[62] = vertices[76] = vertices[167] = vertices[230] = vertices[244] = c[6].A; - colors[28] = colors[48] = colors[72] = c[7].R; - colors[29] = colors[49] = colors[73] = c[7].G; - colors[30] = colors[50] = colors[74] = c[7].B; - colors[31] = colors[51] = colors[75] = c[7].A; + vertices[80] = vertices[129] = vertices[150] = vertices[185] = vertices[199] = c[7].R; + vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; + vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; + vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; attribMutex.unlock(); } diff --git a/src/TSGL/Cuboid.h b/src/TSGL/Cuboid.h index 5ad1b2956..25e21611f 100644 --- a/src/TSGL/Cuboid.h +++ b/src/TSGL/Cuboid.h @@ -5,7 +5,7 @@ #ifndef CUBOID_H_ #define CUBOID_H_ -#include "Drawable.h" // For extending our Prism object +#include "Shape.h" // For extending our Prism object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -13,9 +13,9 @@ namespace tsgl { /*! \class Cuboid * \brief Draw an arbitrary Cuboid with colored vertices. * \details Cuboid is a class for holding vertex data for a Cuboid. - * \details Cuboid is a 6-sided subclass of Drawable with all rectangular faces. + * \details Cuboid is a 6-sided subclass of Shape with all rectangular faces. */ -class Cuboid : public Drawable { +class Cuboid : public Shape { protected: GLfloat myLength, myWidth, myHeight; public: @@ -53,7 +53,7 @@ class Cuboid : public Drawable { */ virtual GLfloat getWidth() { return myWidth; } - virtual void setColor(ColorFloat c) { Drawable::setColor(c); } + virtual void setColor(ColorFloat c) { Shape::setColor(c); } virtual void setColor(ColorFloat c[]); diff --git a/src/TSGL/Drawable.cpp b/src/TSGL/Drawable.cpp index 005b8f513..1f9632271 100644 --- a/src/TSGL/Drawable.cpp +++ b/src/TSGL/Drawable.cpp @@ -23,116 +23,11 @@ Drawable::Drawable(float x, float y, float z, float yaw, float pitch, float roll myRotationPointZ = myCenterZ; } -/*! - * \brief Draw the Drawable. - * \details This function actually draws the Drawable to the Canvas. - * \note This function does nothing if the vertex buffer is not yet full. - * \note A message indicating that the Drawable cannot be drawn yet will be given - * if the above condition is met (vertex buffer = not full). - */ -void Drawable::draw() { - if (!init) { - TsglDebug("Vertex buffer is not full."); - return; - } - glPushMatrix(); - glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); - glRotatef(myCurrentYaw, 0, 0, 1); - glRotatef(myCurrentPitch, 0, 1, 0); - glRotatef(myCurrentRoll, 1, 0, 0); - glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); - glScalef(myXScale, myYScale, myZScale); - - /* We have a color array and a vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - glColorPointer(4, GL_FLOAT, 0, colors); - - glDrawArrays(geometryType, 0, numberOfVertices); - - if (edgesOutlined) { - glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); - glColorPointer(4, GL_FLOAT, 0, outlineArray); - - glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); - } - - glPopMatrix(); - - /* Cleanup states */ - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); -} - - /*! - * \brief Adds another vertex to a Drawable. - * \details This function initializes the next vertex in the Drawable and adds it to a Drawable buffer. - * \param x The x position of the vertex. - * \param y The y position of the vertex. - * \param z The z position of the vertex. - * \param color The reference variable of the color of the vertex. - * \note This function does nothing if the vertex buffer is already full. - * \note A message is given indicating that the vertex buffer is full. - */ -void Drawable::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { - if (init) { - TsglDebug("Cannot add anymore vertices."); - return; - } - attribMutex.lock(); - vertices[currentVertex] = x; - vertices[currentVertex + 1] = y; - vertices[currentVertex + 2] = z; - currentVertex += 3; - colors[currentColor] = color.R; - colors[currentColor+1] = color.G; - colors[currentColor+2] = color.B; - colors[currentColor+3] = color.A; - currentColor += 4; - attribMutex.unlock(); - if (currentVertex == numberOfVertices*3) { - attribMutex.lock(); - outlineArray = new GLfloat[numberOfOutlineVertices*4]; - std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); - init = true; - attribMutex.unlock(); - } -} - ///////////////////////////////////////////////// // MUTATORS ///////////////////////////////////////////////// -/** - * \brief Sets the Drawable to a new color. - * \param c The new ColorFloat. - */ -void Drawable::setColor(ColorFloat c) { - attribMutex.lock(); - for(int i = 0; i < numberOfVertices; i++) { - colors[i*4] = c.R; - colors[i*4 + 1] = c.G; - colors[i*4 + 2] = c.B; - colors[i*4 + 3] = c.A; - } - attribMutex.unlock(); -} - -/** - * \brief Sets the Drawable's outline/edges to a new color - * \param c The new ColorFloat. - */ -void Drawable::setEdgeColor(ColorFloat c) { - for (int i = 0; i < numberOfOutlineVertices; i++) { - outlineArray[4*i] = c.R; - outlineArray[4*i+1] = c.G; - outlineArray[4*i+2] = c.B; - outlineArray[4*i+3] = c.A; - } -} - /** * \brief Alters the Drawable's x position * \param deltaX The difference between the new and old vertex x coordinates. @@ -459,8 +354,6 @@ float Drawable::getCenterZ() { Drawable::~Drawable() { delete[] vertices; - delete[] colors; - delete[] outlineArray; } } \ No newline at end of file diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 54380a500..9eb71dafa 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -6,6 +6,10 @@ #define DRAWABLE_H_ #include "Color.h" // Needed for color type +#include "shader_s.h" +#include +#include +#include #include // Needed for locking the attribute mutex for thread-safety namespace tsgl { @@ -26,25 +30,13 @@ namespace tsgl { class Drawable { protected: std::mutex attribMutex; ///< Protects the attributes of the Drawable from being accessed while simultaneously being changed - bool isTextured = false; - bool edgesOutlined = true; - int numberOfVertices; - int numberOfOutlineVertices; - GLsizei outlineStride = 0; GLfloat* vertices; - GLfloat* colors; - GLfloat* outlineArray; - int currentVertex = 0; - int currentColor = 0; float myCurrentYaw, myCurrentPitch, myCurrentRoll; float myXScale, myYScale, myZScale; float myRotationPointX, myRotationPointY, myRotationPointZ; float myCenterX, myCenterY, myCenterZ; - GLenum geometryType; - GLenum outlineGeometryType; bool init = false; - virtual void addVertex(float x, float y, float z, const ColorFloat &color = WHITE); - + unsigned int shaderType = SHAPE_SHADER_TYPE; /*! * \brief Protected helper method that determines if the Drawable's center matches its rotation point. * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ @@ -58,16 +50,7 @@ class Drawable { virtual ~Drawable(); - virtual void draw(); - - virtual void setColor(ColorFloat c); - /** - * \brief Pure virtual mutator. Sets the Drawable to a new array of colors. - * \param c An array of the new ColorFloats. - * \warning Inheriting subclasses MUST define an override method for this method. - */ - virtual void setColor(ColorFloat c[]) = 0; - virtual void setEdgeColor(ColorFloat c); + virtual void draw(Shader * shader) = 0; virtual void changeXBy(float deltaX); virtual void changeYBy(float deltaY); @@ -94,7 +77,6 @@ class Drawable { virtual void setRotationPointZ(float z); virtual void setRotationPoint(float x, float y, float z); - virtual float getCenterX(); virtual float getCenterY(); virtual float getCenterZ(); @@ -135,21 +117,13 @@ class Drawable { */ virtual float getRotationPointZ() { return myRotationPointZ; } - /* - * \brief Mutator that determines if the edges of the Drawable should be highlighted. - * \details Updates the value of the edgesOutlined instance variable. Defaults to true. - */ - virtual void displayOutlineEdges(bool on=true) { edgesOutlined=on; } - - - /*! * \brief Accessor that returns if Drawable is processed and ready to be drawn * \details This function returns true only if all vertices have been inserted into an array. */ virtual bool isProcessed() { return init; } - virtual bool getIsTextured() { return isTextured; } + virtual unsigned int getShaderType() { return shaderType; } }; } diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index f4373e41b..450ed33c9 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -119,17 +119,17 @@ void Ellipse::changeYRadiusBy(GLfloat delta) { * \param c An array of the new ColorFloats. */ void Ellipse::setColor(ColorFloat c[]) { - colors[0] = c[0].R; - colors[1] = c[0].G; - colors[2] = c[0].B; - colors[3] = c[0].A; + vertices[3] = c[0].R; + vertices[4] = c[0].G; + vertices[5] = c[0].B; + vertices[6] = c[0].A; int colorIndex; for (int i = 1; i < numberOfVertices; ++i) { colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); - colors[i*4] = c[colorIndex].R; - colors[i*4 + 1] = c[colorIndex].G; - colors[i*4 + 2] = c[colorIndex].B; - colors[i*4 + 3] = c[colorIndex].A; + vertices[i*7 + 3] = c[colorIndex].R; + vertices[i*7 + 4] = c[colorIndex].G; + vertices[i*7 + 5] = c[colorIndex].B; + vertices[i*7 + 6] = c[colorIndex].A; } } diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index 674da4c50..a1adbcb1d 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -42,7 +42,7 @@ class Ellipse : public ConvexPolygon { */ GLfloat getYRadius() { return myYRadius; } - void setColor(ColorFloat c) { Drawable::setColor(c); } + void setColor(ColorFloat c) { Shape::setColor(c); } void setColor(ColorFloat c[]); diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 38e3e09f5..d377a8f13 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } @@ -29,8 +29,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; outlineGeometryType = GL_LINES; edgesOutlined = false; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myXRadius = xRadius; myYRadius = yRadius; myZRadius = zRadius; @@ -65,7 +64,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius * \warning An invariant is held where if any radius isn't positive then an error message is given. * \return A new Ellipsoid with a buffer for storing the specified numbered of vertices. */ -Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { +Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, GLfloat zRadius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { if (xRadius <= 0 || yRadius <= 0 || zRadius <= 0) { TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } @@ -76,8 +75,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; outlineGeometryType = GL_LINES; edgesOutlined = false; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myXRadius = xRadius; myYRadius = yRadius; myZRadius = zRadius; @@ -196,20 +194,20 @@ void Ellipsoid::setColor(ColorFloat c) { { for(int a=0;aID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &myTexture); // enable textures and bind the texture id glBindTexture(GL_TEXTURE_2D, myTexture); @@ -96,50 +93,14 @@ void Image::draw() { GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); - // transformation matrix - glPushMatrix(); - glTranslatef(myRotationPointX, myRotationPointY, myRotationPointZ); - glRotatef(myCurrentYaw, 0, 0, 1); - glRotatef(myCurrentPitch, 0, 1, 0); - glRotatef(myCurrentRoll, 1, 0, 0); - glTranslatef(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ); - glScalef(myXScale, myYScale, myZScale); - - // enable necessary states (vertex, color, and texture) - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - // link arrays to their respective opengl pointers - glVertexPointer(3, GL_FLOAT, 0, vertices); - glColorPointer(4, GL_FLOAT, 0, colors); - glTexCoordPointer(2, GL_FLOAT, 0, texcoords); - - // draw the image - // glBufferData(GL_ARRAY_BUFFER, 36 * sizeof(GLfloat), vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_QUADS, 0, numberOfVertices); - - // pop transformation matrix - glPopMatrix(); - - /* Cleanup states */ - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); - glDisable(GL_TEXTURE_2D); -} + glDeleteTextures(1, &myTexture); -void Image::setColor(ColorFloat c[]) { - for (int i = 0; i < numberOfVertices; i++) { - colors[i*4] = c[i].R; - colors[i*4+1] = c[i].G; - colors[i*4+2] = c[i].B; - colors[i*4+3] = c[i].A; - } + glDisable(GL_TEXTURE_2D); } - /** * \brief Mutates the distance from the left side of the Image base to its right side. * \param width The Image's new width. @@ -200,30 +161,24 @@ void Image::changeHeightBy(GLfloat delta) { attribMutex.unlock(); } -// /*! -// * \brief Alters the file the Image draws. -// * \details Alters the values of the myFile, myWidth, myHeight, and mutates vertices. -// * \param filename New string value for myFile. -// * \param width New width of the Image. -// * \param height New height of the Image. -// */ -// void Image::changeFileName(std::string filename, int width, int height) { -// attribMutex.lock(); -// myFile = filename; -// myWidth = width; myHeight = height; -// if (myWidth <= 0 || myHeight <= 0) { -// TextureHandler::getDimensions(filename,myWidth,myHeight); -// } -// vertices[0] = myCenterX - myWidth/2; -// vertices[1] = myCenterY - myHeight/2; -// vertices[8] = myCenterX + myWidth/2; -// vertices[9] = myCenterY - myHeight/2; -// vertices[16] = myCenterX - myWidth/2; -// vertices[17] = myCenterY + myHeight/2; -// vertices[24] = myCenterX + myWidth/2; -// vertices[25] = myCenterY + myHeight/2; -// attribMutex.unlock(); -// } +/*! + * \brief Alters the file the Image draws. + * \details Alters the values of the myFile, myWidth, myHeight, and mutates vertices. + * \param filename New string value for myFile. + * \param width New width of the Image. + * \param height New height of the Image. + */ +void Image::changeFile(std::string filename) { + attribMutex.lock(); + init = false; + stbi_image_free(data); + // Load the image. + stbi_set_flip_vertically_on_load(true); + data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); + tsglAssert(data, "stbi_load(filename) failed."); + init = true; + attribMutex.unlock(); +} Image::~Image() { glDeleteTextures(1, &myTexture); diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index 7ea1ca741..6bdd36a5c 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -31,14 +31,10 @@ class Image : public Drawable { GLint pixelWidth, pixelHeight; std::string myFile; GLuint myTexture; - GLfloat texcoords[8] = - { - 0, 0, 0, 1, 1, 1, 1, 0 - }; public: Image(float x, float y, float z, std::string filename, GLfloat width, GLfloat height, float yaw, float pitch, float roll, float alpha = 1.0f); - virtual void draw(); + virtual void draw(Shader * shader); /*! * \brief Accessor for the image's height. @@ -60,12 +56,12 @@ class Image : public Drawable { void changeHeightBy(GLfloat delta); + void changeFile(std::string filename); + GLint getPixelHeight() { return pixelHeight; } GLint getPixelWidth() { return pixelWidth; } - void setColor(ColorFloat c[]); - ~Image(); }; diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index aba5bd17e..d7c128ccc 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -23,8 +23,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float yaw, float numberOfOutlineVertices = 0; edgesOutlined = false; myXScale = myYScale = myZScale = 1; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; attribMutex.unlock(); } @@ -52,8 +51,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice numberOfOutlineVertices = 0; edgesOutlined = false; myXScale = myYScale = myZScale = 1; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -84,8 +82,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice numberOfOutlineVertices = 0; edgesOutlined = false; myXScale = myYScale = myZScale = 1; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { diff --git a/src/TSGL/Polyline.h b/src/TSGL/Polyline.h index 0709f7ed3..f8729bd64 100755 --- a/src/TSGL/Polyline.h +++ b/src/TSGL/Polyline.h @@ -19,11 +19,9 @@ namespace tsgl { * \note Calling Drawable::draw() before all vertices have been added will do nothing. */ class Polyline : public Shape { - private: - - public: - + protected: Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll); + public: Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color); diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index 957c1d1b9..d3c374cc4 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { if (radius <= 0 || height <= 0 || sides < 3) { TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); } @@ -34,8 +34,7 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu outlineStride = 2; numberOfOutlineVertices = mySides * 6; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); @@ -72,7 +71,7 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu * \warning An invariant is held where if all points in vertices are not in the same plane then an error message is given. * \return A new Prism with a buffer for storing the specified numbered of vertices. */ -Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { +Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { if (radius <= 0 || height <= 0 || sides < 3) { TsglDebug("Cannot have a Prism with non-positive height or radius or fewer than 3 sides"); } @@ -88,8 +87,7 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu outlineStride = 2; numberOfOutlineVertices = mySides * 6; outlineGeometryType = GL_LINES; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[1]); @@ -180,35 +178,35 @@ void Prism::changeRadiusBy(GLfloat delta) { void Prism::setColor(ColorFloat c[]) { attribMutex.lock(); for (int i = 0; i < mySides; i++) { - colors[i*48] = c[1].R; - colors[i*48+1] = c[1].G; - colors[i*48+2] = c[1].B; - colors[i*48+3] = c[1].A; - - colors[i*48+4] = c[0].R; - colors[i*48+5] = c[0].G; - colors[i*48+6] = c[0].B; - colors[i*48+7] = c[0].A; - - colors[i*48+8] = c[1].R; - colors[i*48+9] = c[1].G; - colors[i*48+10] = c[1].B; - colors[i*48+11] = c[1].A; - - colors[i*48+12] = colors[i*48+16] = colors[i*48+20] = colors[i*48+24] = colors[i*48+28] = colors[i*48+32] = c[2].R; - colors[i*48+13] = colors[i*48+17] = colors[i*48+21] = colors[i*48+25] = colors[i*48+29] = colors[i*48+33] = c[2].G; - colors[i*48+14] = colors[i*48+18] = colors[i*48+22] = colors[i*48+26] = colors[i*48+30] = colors[i*48+34] = c[2].B; - colors[i*48+15] = colors[i*48+19] = colors[i*48+23] = colors[i*48+27] = colors[i*48+31] = colors[i*48+35] = c[2].A; - - colors[i*48+36] = colors[i*48+40] = c[3].R; - colors[i*48+37] = colors[i*48+41] = c[3].G; - colors[i*48+38] = colors[i*48+42] = c[3].B; - colors[i*48+39] = colors[i*48+43] = c[3].A; - - colors[i*48+44] = c[4].R; - colors[i*48+45] = c[4].G; - colors[i*48+46] = c[4].B; - colors[i*48+47] = c[4].A; + vertices[i*84+3] = c[1].R; + vertices[i*84+4] = c[1].G; + vertices[i*84+5] = c[1].B; + vertices[i*84+6] = c[1].A; + + vertices[i*84+10] = c[0].R; + vertices[i*84+11] = c[0].G; + vertices[i*84+12] = c[0].B; + vertices[i*84+13] = c[0].A; + + vertices[i*84+17] = c[1].R; + vertices[i*84+18] = c[1].G; + vertices[i*84+19] = c[1].B; + vertices[i*84+20] = c[1].A; + + vertices[i*84+24] = vertices[i*84+31] = vertices[i*84+38] = vertices[i*84+45] = vertices[i*84+52] = vertices[i*84+59] = c[2].R; + vertices[i*84+25] = vertices[i*84+32] = vertices[i*84+39] = vertices[i*84+46] = vertices[i*84+53] = vertices[i*84+60] = c[2].G; + vertices[i*84+26] = vertices[i*84+33] = vertices[i*84+40] = vertices[i*84+47] = vertices[i*84+54] = vertices[i*84+61] = c[2].B; + vertices[i*84+27] = vertices[i*84+34] = vertices[i*84+41] = vertices[i*84+48] = vertices[i*84+55] = vertices[i*84+62] = c[2].A; + + vertices[i*84+66] = vertices[i*84+73] = c[3].R; + vertices[i*84+67] = vertices[i*84+74] = c[3].G; + vertices[i*84+68] = vertices[i*84+75] = c[3].B; + vertices[i*84+69] = vertices[i*84+76] = c[3].A; + + vertices[i*84+80] = c[4].R; + vertices[i*84+81] = c[4].G; + vertices[i*84+82] = c[4].B; + vertices[i*84+83] = c[4].A; } attribMutex.unlock(); } diff --git a/src/TSGL/Prism.h b/src/TSGL/Prism.h index c18edb0e5..37ac28ce3 100644 --- a/src/TSGL/Prism.h +++ b/src/TSGL/Prism.h @@ -1,11 +1,11 @@ /* - * Prism.h extends Drawable and provides a class for drawing a prism. + * Prism.h extends Shape and provides a class for drawing a prism. */ #ifndef PRISM_H_ #define PRISM_H_ -#include "Drawable.h" // For extending our Drawable object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Prism with colored vertices. * \details Prism is a class for holding vertex data for a Prism with a base with at least 3 sides. */ -class Prism : public Drawable { +class Prism : public Shape { protected: GLfloat myHeight; GLfloat myRadius; @@ -46,7 +46,7 @@ class Prism : public Drawable { */ virtual GLfloat getHeight() { return myHeight; } - virtual void setColor(ColorFloat c) { Drawable::setColor(c); } + virtual void setColor(ColorFloat c) { Shape::setColor(c); } virtual void setColor(ColorFloat c[]); }; diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index 11019a4b6..aea8419f1 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -19,7 +19,7 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } @@ -38,8 +38,7 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r outlineStride = 2; outlineGeometryType = GL_LINE_LOOP; numberOfOutlineVertices = mySides * 3; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); @@ -69,7 +68,7 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Pyramid with a buffer for storing the specified numbered of vertices. */ -Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { +Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { if (sides < 3) { TsglDebug("Cannot have a Pyramid with fewer than 3 sides."); } @@ -88,17 +87,16 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r outlineStride = 2; outlineGeometryType = GL_LINE_LOOP; numberOfOutlineVertices = mySides * 3; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[i+1]); addVertex(0,-0.5,0, c[mySides+2]); - addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[i+2]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[(i+1) % mySides + 1]); addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[i+1]); addVertex(0,0.5,0, c[0]); - addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[i+2]); + addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[(i+1) % mySides + 1]); } } @@ -173,15 +171,15 @@ void Pyramid::changeHeightBy(float delta) { void Pyramid::setColor(ColorFloat c) { attribMutex.lock(); for(int i = 0; i < mySides; i++) { - colors[i*24] = colors[i*24 + 4] = colors[i*24 + 8] = colors[i*24 + 12] = colors[i*24 + 20] = c.R; - colors[i*24 + 1] = colors[i*24 + 5] = colors[i*24 + 9] = colors[i*24 + 13] = colors[i*24 + 21] = c.G; - colors[i*24 + 2] = colors[i*24 + 6] = colors[i*24 + 10] = colors[i*24 + 14] = colors[i*24 + 22] = c.B; - colors[i*24 + 3] = colors[i*24 + 7] = colors[i*24 + 11] = colors[i*24 + 15] = colors[i*24 + 23] = c.A; - - colors[i*24 + 16] = c.R *.5; - colors[i*24 + 17] = c.G *.5; - colors[i*24 + 18] = c.B *.5; - colors[i*24 + 19] = c.A; + vertices[i*42 + 3] = vertices[i*42 + 10] = vertices[i*42 + 17] = vertices[i*42 + 24] = vertices[i*42 + 38] = c.R; + vertices[i*42 + 4] = vertices[i*42 + 11] = vertices[i*42 + 18] = vertices[i*42 + 25] = vertices[i*42 + 39] = c.G; + vertices[i*42 + 5] = vertices[i*42 + 12] = vertices[i*42 + 19] = vertices[i*42 + 26] = vertices[i*42 + 40] = c.B; + vertices[i*42 + 6] = vertices[i*42 + 13] = vertices[i*42 + 20] = vertices[i*42 + 27] = vertices[i*42 + 41] = c.A; + + vertices[i*42 + 31] = c.R *.5; + vertices[i*42 + 32] = c.G *.5; + vertices[i*42 + 33] = c.B *.5; + vertices[i*42 + 34] = c.A; } attribMutex.unlock(); } @@ -194,35 +192,35 @@ void Pyramid::setColor(ColorFloat c) { void Pyramid::setColor(ColorFloat c[]) { attribMutex.lock(); for(int i = 0; i < mySides; i++) { - colors[i*24] = c[i+1].R; - colors[i*24 + 1] = c[i+1].G; - colors[i*24 + 2] = c[i+1].B; - colors[i*24 + 3] = c[i+1].A; - - colors[i*24 + 4] = c[mySides+2].R; - colors[i*24 + 5] = c[mySides+2].G; - colors[i*24 + 6] = c[mySides+2].B; - colors[i*24 + 7] = c[mySides+2].A; - - colors[i*24 + 8] = c[i+2].R; - colors[i*24 + 9] = c[i+2].G; - colors[i*24 + 10] = c[i+2].B; - colors[i*24 + 11] = c[i+2].A; + vertices[i*42 + 3] = c[i+1].R; + vertices[i*42 + 4] = c[i+1].G; + vertices[i*42 + 5] = c[i+1].B; + vertices[i*42 + 6] = c[i+1].A; + + vertices[i*42 + 10] = c[mySides+2].R; + vertices[i*42 + 11] = c[mySides+2].G; + vertices[i*42 + 12] = c[mySides+2].B; + vertices[i*42 + 13] = c[mySides+2].A; + + vertices[i*42 + 17] = c[(i+1) % mySides + 1].R; + vertices[i*42 + 18] = c[(i+1) % mySides + 1].G; + vertices[i*42 + 19] = c[(i+1) % mySides + 1].B; + vertices[i*42 + 20] = c[(i+1) % mySides + 1].A; - colors[i*24 + 12] = c[i+1].R; - colors[i*24 + 13] = c[i+1].G; - colors[i*24 + 14] = c[i+1].B; - colors[i*24 + 15] = c[i+1].A; - - colors[i*24 + 16] = c[0].R; - colors[i*24 + 17] = c[0].G; - colors[i*24 + 18] = c[0].B; - colors[i*24 + 19] = c[0].A; - - colors[i*24 + 20] = c[i+2].R; - colors[i*24 + 21] = c[i+2].G; - colors[i*24 + 22] = c[i+2].B; - colors[i*24 + 23] = c[i+2].A; + vertices[i*42 + 24] = c[i+1].R; + vertices[i*42 + 25] = c[i+1].G; + vertices[i*42 + 26] = c[i+1].B; + vertices[i*42 + 27] = c[i+1].A; + + vertices[i*42 + 31] = c[0].R; + vertices[i*42 + 32] = c[0].G; + vertices[i*42 + 33] = c[0].B; + vertices[i*42 + 34] = c[0].A; + + vertices[i*42 + 38] = c[(i+1) % mySides + 1].R; + vertices[i*42 + 39] = c[(i+1) % mySides + 1].G; + vertices[i*42 + 40] = c[(i+1) % mySides + 1].B; + vertices[i*42 + 41] = c[(i+1) % mySides + 1].A; } attribMutex.unlock(); } diff --git a/src/TSGL/Pyramid.h b/src/TSGL/Pyramid.h index e4b8e7419..dadc2f5f9 100644 --- a/src/TSGL/Pyramid.h +++ b/src/TSGL/Pyramid.h @@ -1,11 +1,11 @@ /* - * Pyramid.h extends Drawable and provides a class for drawing a pyramid. + * Pyramid.h extends Shape and provides a class for drawing a pyramid. */ #ifndef PYRAMID_H_ #define PYRAMID_H_ -#include "Drawable.h" // For extending our Drawable object +#include "Shape.h" // For extending our Shape object #include "TsglAssert.h" // For unit testing purposes namespace tsgl { @@ -14,7 +14,7 @@ namespace tsgl { * \brief Draw an arbitrary Pyramid with colored vertices. * \details Pyramid is a class for holding vertex data for a pyramid with a base with at least 3 sides. */ -class Pyramid : public Drawable { +class Pyramid : public Shape { protected: GLfloat myHeight; GLfloat myRadius; diff --git a/src/TSGL/Rectangle.cpp b/src/TSGL/Rectangle.cpp index 5b57dee7a..2fdf74d39 100644 --- a/src/TSGL/Rectangle.cpp +++ b/src/TSGL/Rectangle.cpp @@ -20,7 +20,6 @@ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, f return; } attribMutex.lock(); - geometryType = GL_QUADS; myXScale = myWidth = width; myYScale = myHeight = height; myZScale = 1; @@ -49,7 +48,6 @@ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, f return; } attribMutex.lock(); - geometryType = GL_QUADS; myXScale = myWidth = width; myYScale = myHeight = height; myZScale = 1; diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index cba8da9c6..2d42470a0 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -45,7 +45,7 @@ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int si attribMutex.unlock(); float delta = 2.0f / sides * PI; for (int i = 0; i < sides; ++i) { - addVertex(cos(i*delta), sin(i*delta), 0, color[i]); + addVertex(cos(i*delta), sin(i*delta), 0, color[i % (mySides - 1)]); } } @@ -81,4 +81,13 @@ void RegularPolygon::changeRadiusBy(GLfloat delta) { attribMutex.unlock(); } +void RegularPolygon::setColor(ColorFloat c[]) { + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c[i % (mySides - 1)].R; + vertices[i*7 + 4] = c[i % (mySides - 1)].G; + vertices[i*7 + 5] = c[i % (mySides - 1)].B; + vertices[i*7 + 6] = c[i % (mySides - 1)].A; + } +} + } \ No newline at end of file diff --git a/src/TSGL/RegularPolygon.h b/src/TSGL/RegularPolygon.h index 4d2d44bc8..e6177da8e 100644 --- a/src/TSGL/RegularPolygon.h +++ b/src/TSGL/RegularPolygon.h @@ -37,6 +37,10 @@ class RegularPolygon : public ConvexPolygon { void setRadius(GLfloat radius); void changeRadiusBy(GLfloat delta); + + void setColor(ColorFloat c) { Shape::setColor(c); } + + void setColor(ColorFloat c[]); }; } diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index 4b37c0587..8c8fb0d12 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -13,17 +13,80 @@ namespace tsgl { */ Shape::Shape(float x, float y, float z, float yaw, float pitch, float roll) : Drawable(x,y,z,yaw,pitch,roll) { } +/*! + * \brief Draw the Shape. + * \details This function actually draws the Shape to the Canvas. + * \note This function does nothing if the vertex buffer is not yet full. + * \note A message indicating that the Shape cannot be drawn yet will be given + * if the above condition is met (vertex buffer = not full). + */ +void Shape::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); +} + + /*! + * \brief Adds another vertex to a Shape. + * \details This function initializes the next vertex in the Shape and adds it to a Shape buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Shape::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { + if (init) { + TsglDebug("Cannot add anymore vertices."); + return; + } + attribMutex.lock(); + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + vertices[currentVertex + 3] = color.R; + vertices[currentVertex + 4] = color.G; + vertices[currentVertex + 5] = color.B; + vertices[currentVertex + 6] = color.A; + currentVertex += 7; + attribMutex.unlock(); + if (currentVertex == numberOfVertices*7) { + attribMutex.lock(); + // outlineArray = new GLfloat[numberOfOutlineVertices*4]; + // std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); + init = true; + attribMutex.unlock(); + } +} + /** * \brief Sets the Shape to a new color. * \param c The new ColorFloat. */ void Shape::setColor(ColorFloat c) { + attribMutex.lock(); for(int i = 0; i < numberOfVertices; i++) { - colors[i*4] = c.R; - colors[i*4 + 1] = c.G; - colors[i*4 + 2] = c.B; - colors[i*4 + 3] = c.A; + vertices[i*7 + 3] = c.R; + vertices[i*7 + 4] = c.G; + vertices[i*7 + 5] = c.B; + vertices[i*7 + 6] = c.A; } + attribMutex.unlock(); } /** @@ -32,11 +95,24 @@ void Shape::setColor(ColorFloat c) { */ void Shape::setColor(ColorFloat c[]) { for(int i = 0; i < numberOfVertices; i++) { - colors[i*4] = c[i].R; - colors[i*4 + 1] = c[i].G; - colors[i*4 + 2] = c[i].B; - colors[i*4 + 3] = c[i].A; + vertices[i*7 + 3] = c[i].R; + vertices[i*7 + 4] = c[i].G; + vertices[i*7 + 5] = c[i].B; + vertices[i*7 + 6] = c[i].A; } } +/** + * \brief Sets the Shape's outline/edges to a new color + * \param c The new ColorFloat. + */ +void Shape::setEdgeColor(ColorFloat c) { + // for (int i = 0; i < numberOfOutlineVertices; i++) { + // outlineArray[4*i] = c.R; + // outlineArray[4*i+1] = c.G; + // outlineArray[4*i+2] = c.B; + // outlineArray[4*i+3] = c.A; + // } +} + } \ No newline at end of file diff --git a/src/TSGL/Shape.h b/src/TSGL/Shape.h index 33cd8a6c8..f855beb4c 100755 --- a/src/TSGL/Shape.h +++ b/src/TSGL/Shape.h @@ -27,12 +27,30 @@ namespace tsgl { * \details However, this is not recommended for normal use of the TSGL library. */ class Shape : public Drawable { + protected: + bool edgesOutlined = true; + int numberOfVertices; + int numberOfOutlineVertices; + GLsizei outlineStride = 0; + int currentVertex = 0; + GLenum geometryType; + GLenum outlineGeometryType; + virtual void addVertex(float x, float y, float z, const ColorFloat &color = WHITE); + public: Shape(float x, float y, float z, float yaw, float pitch, float roll); - virtual void setColor(ColorFloat c); + virtual void draw(Shader * shader); + virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); + virtual void setEdgeColor(ColorFloat c); + + /* + * \brief Mutator that determines if the edges of the Shape should be highlighted. + * \details Updates the value of the edgesOutlined instance variable. Defaults to true. + */ + virtual void displayOutlineEdges(bool on=true) { edgesOutlined=on; } }; } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 726e66cc4..788d0f7e8 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -16,7 +16,7 @@ namespace tsgl { * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ -Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Drawable(x, y, z, yaw, pitch, roll) { +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Shape(x, y, z, yaw, pitch, roll) { // FIXME alpha param works kinda weirdly if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); @@ -28,8 +28,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2+1; outlineGeometryType = GL_LINES; edgesOutlined = false; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myRadius = radius; myXScale = radius; myYScale = radius; @@ -60,7 +59,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch * \warning An invariant is held where if radius isn't positive then an error message is given. * \return A new Sphere with a buffer for storing the specified numbered of vertices. */ -Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Drawable(x, y, z, yaw, pitch, roll) { +Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c[]) : Shape(x, y, z, yaw, pitch, roll) { if (radius <= 0) { TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } @@ -71,8 +70,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; outlineGeometryType = GL_LINES; edgesOutlined = false; - vertices = new GLfloat[numberOfVertices * 3]; - colors = new GLfloat[numberOfVertices * 4]; + vertices = new GLfloat[numberOfVertices * 7]; myRadius = radius; myXScale = radius; myYScale = radius; @@ -133,20 +131,20 @@ void Sphere::setColor(ColorFloat c) { { for(int a=0;acalculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); - -// setRotationPoint(myCenterX, myCenterY); -// } - -// /*! -// * \brief Draw the Text. -// * \details This function actually draws the Text to the Canvas. -// */ -// void Text::draw() { -// vertices[0] = myX; // Pre-init the array with the start coords -// vertices[1] = myY; - -// vertices[2] = vertices[10] = vertices[18] = vertices[26] = myColor.R; // Texture color of the coords -// vertices[3] = vertices[11] = vertices[19] = vertices[27] = myColor.G; // (Default to opaque white) -// vertices[4] = vertices[12] = vertices[20] = vertices[28] = myColor.B; -// vertices[5] = vertices[13] = vertices[21] = vertices[29] = myColor.A; - -// vertices[6] = vertices[7] = 0.0f; // Texture coords of top left -// vertices[14] = 1.0f, vertices[15] = 0.0f; // Texture coords of top right -// vertices[22] = 0.0f, vertices[23] = 1.0f; // Texture coords of bottom left -// vertices[30] = vertices[31] = 1.0f; // Texture coords of bottom right - -// myLoader->drawText(myString, myFontSize, vertices, myCenterX, myCenterY, myRotation); -// } - -// /*! -// * \brief Alter the Text's string -// * \details This function changes myString to the parameter text -// * \param text The text to change myString to. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::setText(std::wstring text) { -// myString = text; -// bool shiftRotationPoint = false; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// shiftRotationPoint = true; -// } -// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); -// if(shiftRotationPoint) { -// setRotationPoint(myCenterX, myCenterY); -// } -// } - -// /*! -// * \brief Alter the Text's font size -// * \details This function changes myFontSize to the parameter fontsize. -// * \param fontsize The new fontsize. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::setFontSize(int fontsize) { -// myFontSize = fontsize; -// bool shiftRotationPoint = false; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// shiftRotationPoint = true; -// } -// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); -// if(shiftRotationPoint) { -// setRotationPoint(myCenterX, myCenterY); -// } -// } - -// /*! -// * \brief Alter the Text's font -// * \details This function changes myLoader's font to the parameter font. -// * \param filename The new font file name. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::setFont(std::string filename) { -// myLoader->loadFont(filename); -// bool shiftRotationPoint = false; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// shiftRotationPoint = true; -// } -// myLoader->calculateTextCenter(myString, myFontSize, myX, myY, myCenterX, myCenterY); -// if(shiftRotationPoint) { -// setRotationPoint(myCenterX, myCenterY); -// } -// } - -// /*! -// * \brief Alter the Text's lower left hand corner location -// * \details This function changes myX and myY to the parameter x and y. -// * \param x The new x-coordinate for myX. -// * \param y The new y-coordinate for myY. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::setBottomLeftCorner(float x, float y) { -// float deltaX = x - myX; -// float deltaY = y - myY; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// myRotationPointX += deltaX; -// myRotationPointY += deltaY; -// } -// myCenterX += deltaX; -// myCenterY += deltaY; -// myX = x; -// myY = y; -// } - -// /*! -// * \brief Alter the Text's lower left hand corner location -// * \details This function changes myX and myY to the parameter x and y. -// * \param x The new x-coordinate for myX. -// * \param y The new y-coordinate for myY. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::setCenter(float x, float y) { -// float deltaX = x - myCenterX; -// float deltaY = y - myCenterY; -// myX += deltaX; -// myY += deltaY; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// setRotationPoint(x, y); -// } -// myCenterX = x; -// myCenterY = y; -// } - -// /*! -// * \brief Alter the Text's location by deltaX and deltaY. -// * \details This function changes all coordinate variables by the parameter deltaX and deltaY -// * \param deltaX The amount to change x-coordinates by. -// * \param deltaY The amount to change y-coordinates by. -// * \warning This will also alter the Text's rotation point to the new center if and only if -// * the old rotation point was at the Text's old center. -// */ -// void Text::moveTextBy(float deltaX, float deltaY) { -// myX += deltaX; -// myY += deltaY; -// if(myCenterX == myRotationPointX && myCenterY == myRotationPointY) { -// myRotationPointX += deltaX; -// myRotationPointY += deltaY; -// } -// myCenterX += deltaX; -// myCenterY += deltaY; -// } - -// /*! -// * \brief Mutator for the rotation of the Text. -// * \details Rotates the Text vertices around centerX, centerY. -// * \param radians Float value denoting how many radians to rotate the Text. -// */ -// void Text::setRotation(float radians) { -// // myRotation = radians; -// if(radians != myRotation) { -// attribMutex.lock(); - -// // distance between myCenter and bottom left corner -// float deltaX = std::roundf(myCenterX - myX); -// float deltaY = std::roundf(myCenterY - myY); - -// //deal with rotation variables -// float s = sin(radians - myRotation); -// float c = cos(radians - myRotation); -// myRotation = radians; - -// //rotate myCenter around myRotationPoint -// float x = myCenterX; -// float y = myCenterY; -// x -= myRotationPointX; -// y -= myRotationPointY; -// float xnew = x * c - y * s; -// float ynew = x * s + y * c; -// x = xnew + myRotationPointX; -// y = ynew + myRotationPointY; -// myCenterX = x; -// myCenterY = y; - -// //calculate new location of bottom left corner -// myX = myCenterX - deltaX; -// myY = myCenterY - deltaY; -// attribMutex.unlock(); -// } -// } - -// /*! -// * \brief Alter the Text's color -// * \details This function changes myColor to the parameter ColorFloat -// * \param color The ColorFloat to change myColor to. -// */ -// void Text::setColor(const ColorFloat& color) { -// myColor = color; -// } - -// Text::~Text() { -// delete myLoader; -// delete[] vertices; -// } - - - -// } \ No newline at end of file +#include "Text.h" +#include "iostream" + +namespace tsgl { + +/*! + * \brief Explicitly constructs a new Text instance. + * \details This is the constructor for the Text class. + * \param text The string to draw. + * \param loader A reference pointer to the TextureHandler with which to load the font. + * \param x The x coordinate. + * \param y The y coordinate. + * \param fontsize The size of the text in pixels. + * \param color A reference to the ColorFloat to use. + * \return A new Text instance with the specified string, position, and color. + */ +Text::Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color) + : Drawable(x,y,z,yaw,pitch,roll) { + shaderType = TEXT_SHADER_TYPE; + myString = text; + myFont = fontFilename; + myFontSize = fontsize; + myColor = color; + + // FreeType + // -------- + // All functions return a value different than 0 whenever an error occurred + if (FT_Init_FreeType(&ft)) + std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; + + // load font as face + if (FT_New_Face(ft, fontFilename.c_str(), 0, &face)) + std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; + + // set size to load glyphs as + FT_Set_Pixel_Sizes(face, 0, myFontSize); + + // disable byte-alignment restriction + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + myWidth = 0; + myHeight = 0; + + // load first 128 characters of ASCII set + // for (unsigned char c = 0; c < 128; c++) { + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + // Load character glyph + if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) + { + std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; + continue; + } + // now store character for later use + Character character = { + face->glyph->bitmap.buffer, + glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), + glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), + face->glyph->advance.x + }; + Characters.insert(std::pair(*c, character)); + myWidth += face->glyph->advance.x >> 6; + if (face->glyph->bitmap.rows > myHeight) + myHeight = face->glyph->bitmap.rows; + } + + vertices = new float[30]; // Allocate the vertices + + // z and texture coordinates never change + vertices[2] = 0; vertices[3] = vertices[4] = 0.0f; + vertices[7] = 0; vertices[8] = 0.0f; vertices[9] = 1.0f; + vertices[12] = 0; vertices[13] = vertices[14] = 1.0f; + vertices[17] = 0; vertices[18] = vertices[19] = 0.0f; + vertices[22] = 0; vertices[23] = vertices[24] = 1.0f; + vertices[27] = 0; vertices[28] = 1.0f; vertices[29] = 0.0f; + + printf("%f, %f\n", myWidth, myHeight); + init = true; +} + +/*! + * \brief Draw the Text. + * \details This function actually draws the Text to the Canvas. + */ +void Text::draw(Shader * shader) { + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glUniform4f(glGetUniformLocation(shader->ID, "textColor"), myColor.R, myColor.G, myColor.B, myColor.A); + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + float mouseX = -myWidth / 2; + float mouseY = -myHeight / 2; + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + Character ch = Characters[*c]; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + GLuint texture; + glGenTextures(1, &texture); + // create and render a new texture based off the data in Characters + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + ch.Size.x, + ch.Size.y, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + ch.Data + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // update vertices for each character + float xpos = mouseX + ch.Bearing.x * 1.0f; + float ypos = mouseY - (ch.Size.y - ch.Bearing.y) * 1.0f; + + float w = ch.Size.x * 1.0f; + float h = ch.Size.y * 1.0f; + + //triangle 1 + vertices[0] = xpos; vertices[1] = ypos + h; + vertices[5] = xpos; vertices[6] = ypos; + vertices[10] = xpos + w; vertices[11] = ypos; + //triangle 2 + vertices[15] = xpos; vertices[16] = ypos + h; + vertices[20] = xpos + w; vertices[21] = ypos; + vertices[25] = xpos + w; vertices[26] = ypos + h; + + glBindTexture(GL_TEXTURE_2D, texture); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDeleteTextures(1, &texture); + + // now advance cursors for next glyph (note that advance is number of 1/64 pixels) + mouseX += (ch.Advance >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) + } + glDisable(GL_TEXTURE_2D); +} + +/*! + * \brief Alter the Text's string + * \details This function changes myString to the parameter text + * \param text The text to change myString to. + * \warning This will also alter the Text's rotation point to the new center if and only if + * the old rotation point was at the Text's old center. + */ +void Text::setText(std::string text) { + +} + +/*! + * \brief Alter the Text's font size + * \details This function changes myFontSize to the parameter fontsize. + * \param fontsize The new fontsize. + * \warning This will also alter the Text's rotation point to the new center if and only if + * the old rotation point was at the Text's old center. + */ +void Text::setFontSize(int fontsize) { + +} + +/*! + * \brief Alter the Text's font + * \details This function changes myLoader's font to the parameter font. + * \param filename The new font file name. + * \warning This will also alter the Text's rotation point to the new center if and only if + * the old rotation point was at the Text's old center. + */ +void Text::setFont(std::string filename) { + +} + +/*! + * \brief Alter the Text's color + * \details This function changes myColor to the parameter ColorFloat + * \param color The ColorFloat to change myColor to. + */ +void Text::setColor(const ColorFloat& color) { + myColor = color; +} + +Text::~Text() { + // destroy FreeType once we're finished + FT_Done_Face(face); + FT_Done_FreeType(ft); +} + + + +} \ No newline at end of file diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index 1364ad451..1a1a150d9 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -1,54 +1,62 @@ -// /* -// * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. -// */ +/* + * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. + */ -// #ifndef TEXT_H_ -// #define TEXT_H_ +#ifndef TEXT_H_ +#define TEXT_H_ -// #include "Drawable.h" // For extending our Shape object -// #include "TextureHandler.h" +#include "Drawable.h" // For extending our Shape object +#include +#include +#include "TextureHandler.h" -// namespace tsgl { +namespace tsgl { -// /*! \class Text -// * \brief Draw a string of text. -// * \details Text is a class for holding the data necessary for rendering a string of text. -// * \note Text is aligned by the upper-left corner. -// * \note Fonts supported by FreeType are also supported. -// */ -// class Text : public Drawable { -// private: -// ColorFloat myColor; -// unsigned int myFontSize; -// TextureHandler* myLoader; -// float * vertices; -// std::wstring myString; -// float myX, myY; -// float myRotation; -// public: -// Text(std::wstring text, float x, float y, unsigned int fontsize, const ColorFloat &color); +/*! \class Text + * \brief Draw a string of text. + * \details Text is a class for holding the data necessary for rendering a string of text. + * \note Text is aligned by the upper-left corner. + * \note Fonts supported by FreeType are also supported. + */ +class Text : public Drawable { + private: + std::string myString; + unsigned int myFontSize; + std::string myFont; + ColorFloat myColor; -// virtual void draw(); + GLfloat myWidth; + GLfloat myHeight; -// virtual void setText(std::wstring text); + FT_Face face; + FT_Library ft; -// virtual void setFontSize(int fontsize); -// virtual void setFont(std::string filename); + /// Holds all state information relevant to a character as loaded using FreeType + struct Character { + unsigned char* Data; // ID handle of the glyph data + glm::ivec2 Size; // Size of glyph + glm::ivec2 Bearing; // Offset from baseline to left/top of glyph + unsigned int Advance; // Horizontal offset to advance to next glyph + }; + std::map Characters; -// virtual void setBottomLeftCorner(float x, float y); + public: + Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); -// virtual void setCenter(float x, float y); + virtual void draw(Shader * shader); -// virtual void moveTextBy(float deltaX, float deltaY); + virtual void setText(std::string text); -// virtual void setRotation(float radians); + virtual void setFontSize(int fontsize); -// virtual void setColor(const ColorFloat& color); + virtual void setFont(std::string filename); -// ~Text(); -// }; + virtual void setColor(const ColorFloat& color); -// } + ~Text(); +}; -// #endif /* TEXT_H_ */ \ No newline at end of file +} + +#endif /* TEXT_H_ */ \ No newline at end of file diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index 3eb1788f1..7cbd1e727 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -27,6 +27,7 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color); addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color); addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color); + geometryType = GL_TRIANGLES; } /*! @@ -54,5 +55,6 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color[0]); addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color[1]); addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color[2]); + geometryType = GL_TRIANGLES; } } diff --git a/src/TSGL/Util.h b/src/TSGL/Util.h index 91278f753..7817f54d4 100644 --- a/src/TSGL/Util.h +++ b/src/TSGL/Util.h @@ -26,6 +26,10 @@ const double RAD = PI / 180; // One radian in degrees const int FPS = 60; // Frames per second const float FRAME = 1.0f/FPS; // Number of seconds between frames +const unsigned int TEXT_SHADER_TYPE = 0; +const unsigned int SHAPE_SHADER_TYPE = 1; +const unsigned int IMAGE_SHADER_TYPE = 2; + /*! * \var typedef long double Decimal * \brief A type definition for a long double. diff --git a/src/TSGL/getBMP.cpp b/src/TSGL/getBMP.cpp deleted file mode 100644 index d662b982d..000000000 --- a/src/TSGL/getBMP.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Routine to read an uncompressed 24-bit unindexed color RGB BMP file into a -// 32-bit color RGBA image file (alpha values all being set to 1). - -#include - -#include "getBMP.h" - -imageFile *getBMP(std::string fileName) -{ - int offset, // No. of bytes to start of image data in input BMP file. - w, // Width in pixels of input BMP file. - h; // Height in pixels of input BMP file. - - // Initialize imageFile objects. - imageFile *tempStore = new imageFile; // Temporary storage. - imageFile *outRGB = new imageFile; // RGB output file. - imageFile *outRGBA = new imageFile; // RGBA output file. - - // Initialize input stream. - std::ifstream inFile(fileName.c_str(), std::ios::binary); - - // Get start point of image data in input BMP file. - inFile.seekg(10); - inFile.read((char *)&offset, 4); - - // Get image width and height. - inFile.seekg(18); - inFile.read((char *)&w, 4); - inFile.read((char *)&h, 4); - - // Determine the length of padding of the pixel rows - // (each pixel row of a BMP file is 4-byte aligned by padding with zero bytes). - int padding = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; - - // Allocate storage for temporary input file, read in image data from the BMP file, close input stream. - tempStore->data = new unsigned char[(3 * w + padding) * h]; - inFile.seekg(offset); - inFile.read((char *)tempStore->data, (3 * w + padding) * h); - inFile.close(); - - // Set image width and height and allocate storage for image in output RGB file. - outRGB->width = w; - outRGB->height = h; - outRGB->data = new unsigned char[3 * w * h]; - - // Copy data from temporary input file to output RGB file adjusting for padding and performing BGR to RGB conversion. - int tempStorePos = 0; - int outRGBpos = 0; - for (int j = 0; j < h; j++) - for (int i = 0; i < 3 * w; i += 3) - { - tempStorePos = (3 * w + padding) * j + i; - outRGBpos = 3 * w * j + i; - outRGB->data[outRGBpos] = tempStore->data[tempStorePos + 2]; - outRGB->data[outRGBpos + 1] = tempStore->data[tempStorePos + 1]; - outRGB->data[outRGBpos + 2] = tempStore->data[tempStorePos]; - } - - // Set image width and height and allocate storage for image in output RGBA file. - outRGBA->width = w; - outRGBA->height = h; - outRGBA->data = new unsigned char[4 * w * h]; - - // Copy image data from output RGB file to output RGBA file, setting all A values to 1. - for (int j = 0; j < 4 * w * h; j += 4) - { - outRGBA->data[j] = outRGB->data[(j / 4) * 3]; - outRGBA->data[j + 1] = outRGB->data[(j / 4) * 3 + 1]; - outRGBA->data[j + 2] = outRGB->data[(j / 4) * 3 + 2]; - outRGBA->data[j + 3] = 0xFF; - } - - // Release temporary storage and the output RGB file and return the RGBA version. - delete[] tempStore; - delete[] outRGB; - return outRGBA; -} diff --git a/src/TSGL/getBMP.h b/src/TSGL/getBMP.h deleted file mode 100644 index 457c8fc0e..000000000 --- a/src/TSGL/getBMP.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef GETBMP_H -#define GETBMP_H - -struct imageFile -{ - int width; - int height; - unsigned char *data; -}; - -imageFile *getBMP(std::string fileName); - -#endif diff --git a/src/TSGL/shader_s.h b/src/TSGL/shader_s.h new file mode 100644 index 000000000..5d3241d5f --- /dev/null +++ b/src/TSGL/shader_s.h @@ -0,0 +1,198 @@ +#ifndef SHADER_H +#define SHADER_H + +#include +#include + +#include +#include +#include +#include + +class Shader +{ +public: + unsigned int ID; + // constructor generates the shader on the fly + // ------------------------------------------------------------------------ + Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) + { + // 1. retrieve the vertex/fragment source code from filePath + std::string vertexCode; + std::string fragmentCode; + std::string geometryCode; + std::ifstream vShaderFile; + std::ifstream fShaderFile; + std::ifstream gShaderFile; + // ensure ifstream objects can throw exceptions: + vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + try + { + GLenum err = glewInit(); + if (err != GLEW_OK) + exit(1); // or handle the error in a nicer way + if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. + exit(1); // or handle the error in a nicer way + // open files + vShaderFile.open(vertexPath); + fShaderFile.open(fragmentPath); + std::stringstream vShaderStream, fShaderStream; + // read file's buffer contents into streams + vShaderStream << vShaderFile.rdbuf(); + fShaderStream << fShaderFile.rdbuf(); + // close file handlers + vShaderFile.close(); + fShaderFile.close(); + // convert stream into string + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + // if geometry shader path is present, also load a geometry shader + if(geometryPath != nullptr) + { + gShaderFile.open(geometryPath); + std::stringstream gShaderStream; + gShaderStream << gShaderFile.rdbuf(); + gShaderFile.close(); + geometryCode = gShaderStream.str(); + } + } + catch (std::ifstream::failure& e) + { + std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; + } + const char* vShaderCode = vertexCode.c_str(); + const char * fShaderCode = fragmentCode.c_str(); + // 2. compile shaders + unsigned int vertex, fragment; + // vertex shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vShaderCode, NULL); + glCompileShader(vertex); + checkCompileErrors(vertex, "VERTEX"); + // fragment Shader + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fShaderCode, NULL); + glCompileShader(fragment); + checkCompileErrors(fragment, "FRAGMENT"); + // if geometry shader is given, compile geometry shader + unsigned int geometry; + + + if(geometryPath != nullptr) + { + const char * gShaderCode = geometryCode.c_str(); + geometry = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(geometry, 1, &gShaderCode, NULL); + glCompileShader(geometry); + checkCompileErrors(geometry, "GEOMETRY"); + } + // shader Program + ID = glCreateProgram(); + glAttachShader(ID, vertex); + glAttachShader(ID, fragment); + if(geometryPath != nullptr) + glAttachShader(ID, geometry); + glLinkProgram(ID); + checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessery + glDeleteShader(vertex); + glDeleteShader(fragment); + if(geometryPath != nullptr) + glDeleteShader(geometry); + + } + // activate the shader + // ------------------------------------------------------------------------ + void use() + { + glUseProgram(ID); + } + // utility uniform functions + // ------------------------------------------------------------------------ + void setBool(const std::string &name, bool value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); + } + // ------------------------------------------------------------------------ + void setInt(const std::string &name, int value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setFloat(const std::string &name, float value) const + { + glUniform1f(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setVec2(const std::string &name, const glm::vec2 &value) const + { + glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec2(const std::string &name, float x, float y) const + { + glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); + } + // ------------------------------------------------------------------------ + void setVec3(const std::string &name, const glm::vec3 &value) const + { + glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec3(const std::string &name, float x, float y, float z) const + { + glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); + } + // ------------------------------------------------------------------------ + void setVec4(const std::string &name, const glm::vec4 &value) const + { + glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec4(const std::string &name, float x, float y, float z, float w) + { + glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); + } + // ------------------------------------------------------------------------ + void setMat2(const std::string &name, const glm::mat2 &mat) const + { + glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat3(const std::string &name, const glm::mat3 &mat) const + { + glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat4(const std::string &name, const glm::mat4 &mat) const + { + glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + +private: + // utility function for checking shader compilation/linking errors. + // ------------------------------------------------------------------------ + void checkCompileErrors(GLuint shader, std::string type) + { + GLint success; + GLchar infoLog[1024]; + if(type != "PROGRAM") + { + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + else + { + glGetProgramiv(shader, GL_LINK_STATUS, &success); + if(!success) + { + glGetProgramInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + } +}; +#endif \ No newline at end of file diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 22e7ec3a7..19a45ec88 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -13,7 +13,7 @@ void arrowFunction(Canvas& c) { // doubleArrow->setCenterX(100); // doubleArrow->setRotationPoint(0,0,0); // doubleArrow->setYaw(45); - doubleArrow->setColor(colors); + doubleArrow->setColor(RED); float floatVal = 0.0f; GLfloat delta = 5; while( c.isOpen() ) { diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 38429f1a4..ed63c7f69 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -10,10 +10,10 @@ using namespace tsgl; void cubeFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, ColorFloat(1,0,0,1)); + Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); can.add(testCube); can.add(testCube2); diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index df01f9871..e0007f458 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -14,9 +14,9 @@ void cuboidFunction(Canvas& can) { ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); - // Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 300, 200, 0.0, 0.0, 0.0, colors); + Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); can.add(testCuboid); - // can.add(testCuboid2); + can.add(testCuboid2); float rotation = 0.0f; GLfloat delta = 0.05; bool boolean = false;; @@ -67,6 +67,7 @@ void cuboidFunction(Canvas& can) { } delete testCuboid; + delete testCuboid2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp index a5a29b989..7baf77cb7 100644 --- a/src/tests/testEllipse.cpp +++ b/src/tests/testEllipse.cpp @@ -41,15 +41,15 @@ void ellipseFunction(Canvas& can) { // delta *= -1; // } // ellipse->changeXRadiusBy(delta); - // if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { - // delta *= -1; - // } - // ellipse->changeYRadiusBy(delta); - // if (delta > 0) { - // ellipse->setColor(colors); - // } else { - // ellipse->setColor(RED); - // } + if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { + delta *= -1; + } + ellipse->changeYRadiusBy(delta); + if (delta > 0) { + ellipse->setColor(colors); + } else { + ellipse->setColor(RED); + } floatVal += 1; } diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index bdab44087..18a4ff2e0 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -40,6 +40,10 @@ void imageFunction(Canvas& can) { Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); can.add(image6); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { + image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); + }); + // image->setHeight((GLfloat)image->getPixelHeight()); // image->setWidth((GLfloat)image->getPixelWidth()); diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index da9dd2803..aa17fcf40 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -52,15 +52,15 @@ void prismFunction(Canvas& can) { // testPrism->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // rotation = 0; // } - // if (rotation*45 >= 360) { - // if (boolean) { - // testPrism->setColor(RED); - // } else { - // testPrism->setColor(colors); - // } - // boolean = !boolean; - // rotation = 0; - // } + if (rotation*45 >= 360) { + if (boolean) { + testPrism->setColor(RED); + } else { + testPrism->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } rotation+=0.01; } diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 3ef56e202..23043e7be 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -17,7 +17,7 @@ void pyramidFunction(Canvas& can) { ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); - Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); can.add(testPyramid); can.add(testPyramid2); can.add(testPyramid3); diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index 6c548f875..85d820dbd 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -33,16 +33,16 @@ void rpFunction(Canvas& can) { // rp->setPitch(floatVal); // rp->setRoll(floatVal); // rp->setRadius(sin(floatVal/90)*100 + 300); - // if (rp->getRadius() > 300 || rp->getRadius() < 100) { - // delta *= -1; - // rp->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); - // } - // rp->changeRadiusBy(delta); - // if (delta > 0) { - // rp->setColor(colors); - // } else { - // rp->setColor(RED); - // } + if (rp->getRadius() > 300 || rp->getRadius() < 100) { + delta *= -1; + // rp->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); + } + rp->changeRadiusBy(delta); + if (delta > 0) { + rp->setColor(colors); + } else { + rp->setColor(RED); + } floatVal += 1; } diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index bf421faf2..1b7d3fa3a 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -10,7 +10,7 @@ using namespace tsgl; void squareFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 349ca78b9..601a0290c 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -14,11 +14,11 @@ void starFunction(Canvas& c) { } Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); - // s1->setColor(ColorFloat(1,0,0,1)); + // s1->setColor(RED); c.add(s1); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; while (c.isOpen()) { c.sleep(); // s1->setCenterX(sin(floatVal/90) * 100); @@ -28,16 +28,16 @@ void starFunction(Canvas& c) { // s1->setPitch(floatVal); // s1->setRoll(floatVal); // s1->setRadius(sin(floatVal/90) * 100 + 300); - // if (s1->getRadius() > 300 || s1->getRadius() < 100) { - // delta *= -1; - // // s1->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); - // } - // s1->changeRadiusBy(delta); - // if (delta > 0) { - // s1->setColor(colors); - // } else { - // s1->setColor(RED); - // } + if (s1->getRadius() > 300 || s1->getRadius() < 100) { + delta *= -1; + // s1->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); + } + s1->changeRadiusBy(delta); + if (delta > 0) { + s1->setColor(colors); + } else { + s1->setColor(RED); + } floatVal += 1; } diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index 0ff6fe6ec..f5cc0ad97 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -11,7 +11,6 @@ using namespace tsgl; /*! * \brief Draws some text on a Canvas. * \details - * - We declare some colors to use for drawing. * - We changed it so that now a default text font is loaded if one is not specified. * - We draw a few lines of text in various colors using drawText(). * . @@ -19,22 +18,14 @@ using namespace tsgl; * \param font The font of the text. */ void textFunction(Canvas& can, std::string font) { - ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); - ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); - ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); - - can.setFont(font); - can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - can.drawText("Something extraordinary happened.", 16, 150, 32, RED); - can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - 32, BLUE); - can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * text = new Text(L"Blergh", 0,0, 30, PURPLE); - text->setFont(font); - text->setCenter(can.getWindowWidth()/2, 4*can.getWindowHeight() /5); - text->setRotation(PI/8); + // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); + // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + // 32, BLUE); + // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); + Text * text = new Text(0,0,0,"B", font, 100, 0,0,0, YELLOW); can.add(text); while(can.isOpen()) { can.sleep(); From a170ea34a8151786d7bff9bebbe3bcf38ff519cf Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 22 Jun 2020 18:13:05 -0400 Subject: [PATCH 037/105] Text working. Potentially can be optimized further --- src/TSGL/Text.cpp | 133 ++++++++++++++++++++++-------------- src/TSGL/Text.h | 24 +++---- src/TSGL/TextureHandler.cpp | 62 +++++++---------- src/TSGL/TextureHandler.h | 4 +- src/tests/testText.cpp | 20 +++++- 5 files changed, 137 insertions(+), 106 deletions(-) diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index fdfa04de9..f17d198eb 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -6,11 +6,15 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Text instance. * \details This is the constructor for the Text class. + * \param x The center x coordinate of the text. + * \param y The center y coordinate of the text. + * \param z The center z coordinate of the text. * \param text The string to draw. - * \param loader A reference pointer to the TextureHandler with which to load the font. - * \param x The x coordinate. - * \param y The y coordinate. + * \param fontFilename The path of the filename detailing the font the Text will use. * \param fontsize The size of the text in pixels. + * \param yaw The yaw of the Text in 3D space. + * \param pitch The pitch of the Text in 3D space. + * \param roll The roll of the Text in 3D space. * \param color A reference to the ColorFloat to use. * \return A new Text instance with the specified string, position, and color. */ @@ -21,6 +25,7 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename myFont = fontFilename; myFontSize = fontsize; myColor = color; + myXScale = myYScale = myZScale = 1; // FreeType // -------- @@ -35,34 +40,7 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - // disable byte-alignment restriction - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - myWidth = 0; - myHeight = 0; - - // load first 128 characters of ASCII set - // for (unsigned char c = 0; c < 128; c++) { - std::string::const_iterator c; - for (c = myString.begin(); c != myString.end(); c++) { - // Load character glyph - if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) - { - std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; - continue; - } - // now store character for later use - Character character = { - face->glyph->bitmap.buffer, - glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), - glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), - face->glyph->advance.x - }; - Characters.insert(std::pair(*c, character)); - myWidth += face->glyph->advance.x >> 6; - if (face->glyph->bitmap.rows > myHeight) - myHeight = face->glyph->bitmap.rows; - } + calculateDimensions(); vertices = new float[30]; // Allocate the vertices @@ -74,13 +52,13 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename vertices[22] = 0; vertices[23] = vertices[24] = 1.0f; vertices[27] = 0; vertices[28] = 1.0f; vertices[29] = 0.0f; - printf("%f, %f\n", myWidth, myHeight); init = true; } /*! * \brief Draw the Text. * \details This function actually draws the Text to the Canvas. + * \param shader Pointer to appropriate instance of Shader being used to render the Text. */ void Text::draw(Shader * shader) { glm::mat4 model = glm::mat4(1.0f); @@ -97,13 +75,17 @@ void Text::draw(Shader * shader) { glUniform4f(glGetUniformLocation(shader->ID, "textColor"), myColor.R, myColor.G, myColor.B, myColor.A); glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); float mouseX = -myWidth / 2; float mouseY = -myHeight / 2; std::string::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { - Character ch = Characters[*c]; + // Load character glyph + if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) + { + std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; + continue; + } glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -115,12 +97,12 @@ void Text::draw(Shader * shader) { GL_TEXTURE_2D, 0, GL_RED, - ch.Size.x, - ch.Size.y, + face->glyph->bitmap.width, + face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, - ch.Data + face->glyph->bitmap.buffer ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -129,11 +111,11 @@ void Text::draw(Shader * shader) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // update vertices for each character - float xpos = mouseX + ch.Bearing.x * 1.0f; - float ypos = mouseY - (ch.Size.y - ch.Bearing.y) * 1.0f; + float xpos = mouseX + face->glyph->bitmap_left; + float ypos = mouseY - (face->glyph->bitmap.rows - face->glyph->bitmap_top); - float w = ch.Size.x * 1.0f; - float h = ch.Size.y * 1.0f; + float w = face->glyph->bitmap.width; + float h = face->glyph->bitmap.rows; //triangle 1 vertices[0] = xpos; vertices[1] = ypos + h; @@ -144,15 +126,13 @@ void Text::draw(Shader * shader) { vertices[20] = xpos + w; vertices[21] = ypos; vertices[25] = xpos + w; vertices[26] = ypos + h; - glBindTexture(GL_TEXTURE_2D, texture); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLES, 0, 6); glDeleteTextures(1, &texture); // now advance cursors for next glyph (note that advance is number of 1/64 pixels) - mouseX += (ch.Advance >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) + mouseX += (face->glyph->advance.x >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) } glDisable(GL_TEXTURE_2D); } @@ -161,33 +141,58 @@ void Text::draw(Shader * shader) { * \brief Alter the Text's string * \details This function changes myString to the parameter text * \param text The text to change myString to. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \warning The center of the text will not change despite any differences in rendered string length. */ void Text::setText(std::string text) { - + attribMutex.lock(); + init = false; + myString = text; + calculateDimensions(); + init = true; + attribMutex.unlock(); } /*! * \brief Alter the Text's font size * \details This function changes myFontSize to the parameter fontsize. * \param fontsize The new fontsize. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \warning The center of the text will not change despite any differences in rendered string length. */ -void Text::setFontSize(int fontsize) { +void Text::setFontSize(unsigned int fontsize) { + attribMutex.lock(); + init = false; + myFontSize = fontsize; + + // set size to load glyphs as + FT_Set_Pixel_Sizes(face, 0, myFontSize); + calculateDimensions(); + init = true; + attribMutex.unlock(); } /*! * \brief Alter the Text's font * \details This function changes myLoader's font to the parameter font. * \param filename The new font file name. - * \warning This will also alter the Text's rotation point to the new center if and only if - * the old rotation point was at the Text's old center. + * \warning The center of the text will not change despite any differences in rendered string length. */ void Text::setFont(std::string filename) { + attribMutex.lock(); + init = false; + FT_Done_Face(face); + myFont = filename; + // load font as face + if (FT_New_Face(ft, myFont.c_str(), 0, &face)) + std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; + + // set size to load glyphs as + FT_Set_Pixel_Sizes(face, 0, myFontSize); + + calculateDimensions(); + init = true; + attribMutex.unlock(); } /*! @@ -199,6 +204,30 @@ void Text::setColor(const ColorFloat& color) { myColor = color; } +/*! + * \brief Private helper method for calculating Text dimensions. + * \details This function assigns values to myWidth and myHeight based on + * the glyphs loaded based on myFontSize, myFont, and myString. + */ +void Text::calculateDimensions() { + myWidth = 0; + myHeight = 0; + + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + // Load character glyph + if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) + { + std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; + continue; + } + + myWidth += face->glyph->advance.x >> 6; + if (face->glyph->bitmap.rows > myHeight) + myHeight = face->glyph->bitmap.rows; + } +} + Text::~Text() { // destroy FreeType once we're finished FT_Done_Face(face); diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index 1a1a150d9..af571f3bb 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -1,5 +1,5 @@ /* - * Text.h extends Shape and provides a class for drawing a string of text to the Canvas. + * Text.h extends Drawable and provides a class for drawing a string of text to the Canvas. */ #ifndef TEXT_H_ @@ -7,8 +7,9 @@ #include "Drawable.h" // For extending our Shape object #include -#include -#include "TextureHandler.h" +#include +#include FT_FREETYPE_H +// #include "TextureHandler.h" namespace tsgl { @@ -31,16 +32,7 @@ class Text : public Drawable { FT_Face face; FT_Library ft; - - /// Holds all state information relevant to a character as loaded using FreeType - struct Character { - unsigned char* Data; // ID handle of the glyph data - glm::ivec2 Size; // Size of glyph - glm::ivec2 Bearing; // Offset from baseline to left/top of glyph - unsigned int Advance; // Horizontal offset to advance to next glyph - }; - std::map Characters; - + void calculateDimensions(); public: Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); @@ -48,12 +40,16 @@ class Text : public Drawable { virtual void setText(std::string text); - virtual void setFontSize(int fontsize); + virtual void setFontSize(unsigned int fontsize); virtual void setFont(std::string filename); virtual void setColor(const ColorFloat& color); + std::string getText() { return myString; } + + unsigned int getFontSize() { return myFontSize; } + ~Text(); }; diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index cdadb0bf6..b216befd7 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -212,8 +212,8 @@ void TextureHandler::drawGLtextureFromBuffer(GLubyte* buffer, int x, int y, unsi * \return True if successful, false otherwise. * \bug If the default font cannot be located, TSGL will crash. */ -bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX, int centerY, float rotation) { - const wchar_t* string = text.c_str(); +bool TextureHandler::drawText(std::string text, unsigned int font_size, float* vertices) { + // const wchar_t* string = text.c_str(); if(fontFace == nullptr) { //If no font is set, load up a default one bool found = false; for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { @@ -244,7 +244,7 @@ bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* bool use_kerning = FT_HAS_KERNING(fontFace); for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + current_glyph_index = FT_Get_Char_Index(fontFace, text[i]); if (use_kerning && previous_glyph_index && current_glyph_index) { FT_Vector delta; @@ -285,33 +285,21 @@ bool TextureHandler::drawText(std::wstring text, unsigned int font_size, float* glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - vertices[0] = vertices[16] = penX + glyph->bitmap_left; - vertices[8] = vertices[24] = penX + glyph->bitmap_left + glyph->bitmap.width; - vertices[1] = vertices[9] = penY - glyph->bitmap_top; - vertices[25] = vertices[17] = penY - glyph->bitmap_top + glyph->bitmap.rows; - - - float s = sin(rotation); - float c = cos(rotation); - for(int i = 0; i < 4; i++) { - float x = vertices[8*i]; - float y = vertices[8*i+1]; - x -= centerX; - y -= centerY; - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + centerX; - y = ynew + centerY; - vertices[8*i] = x; - vertices[8*i+1] = y; - } + /* triangles: + bottom left-bottom right-top left + top right-top left-bottom right + */ + + vertices[0] = vertices[10] = vertices[20] = penX + glyph->bitmap_left; // left + vertices[5] = vertices[16] = vertices[25] = penX + glyph->bitmap_left + glyph->bitmap.width; //right + vertices[1] = vertices[6] = vertices[26] = penY - glyph->bitmap_top; // bottom + vertices[15] = vertices[11] = vertices[21] = penY - glyph->bitmap_top + glyph->bitmap.rows; // top penX += glyph->advance.x >> 6; penY += glyph->advance.y >> 6; - glBufferData(GL_ARRAY_BUFFER, 32 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Draw the character + glBufferData(GL_ARRAY_BUFFER, 30 * sizeof(float), vertices, GL_DYNAMIC_DRAW); // Fill the buffer + glDrawArrays(GL_TRIANGLES, 0, 6); // Draw the character glDeleteTextures(1, &texture); } @@ -362,8 +350,8 @@ bool TextureHandler::loadFont(const std::string& filename) { return true; } -void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY) { - const wchar_t* string = text.c_str(); +void TextureHandler::calculateTextDimensions(std::string text, unsigned int font_size, float& width, float& height) { + // const wchar_t* string = text.c_str(); if(fontFace == nullptr) { //If no font is set, load up a default one bool found = false; for (unsigned int i = 0; i < sizeof(DEFAULTFONTPATHS)/sizeof(*DEFAULTFONTPATHS); ++i) { @@ -381,13 +369,13 @@ void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_si } FT_GlyphSlot glyph = fontFace->glyph; FT_UInt current_glyph_index, previous_glyph_index = 0; - int penX = leftX; - int penY = bottomY; + int penX = 0; + int penY = 0; - int minX = leftX; - int minY = bottomY; - int maxX = leftX; - int maxY = bottomY; + int minX = 0; + int minY = 0; + int maxX = 0; + int maxY = 0; int currentRightX, currentTopY, currentBottomY; @@ -400,7 +388,7 @@ void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_si bool use_kerning = FT_HAS_KERNING(fontFace); for (unsigned int i = 0; i < text.size(); i++) { - current_glyph_index = FT_Get_Char_Index(fontFace, string[i]); + current_glyph_index = FT_Get_Char_Index(fontFace, text[i]); if (use_kerning && previous_glyph_index && current_glyph_index) { FT_Vector delta; @@ -433,8 +421,8 @@ void TextureHandler::calculateTextCenter(std::wstring text, unsigned int font_si penY += glyph->advance.y >> 6; } - centerX = (minX + maxX) / 2; - centerY = (minY + maxY) / 2; + width = maxX - minX; + height = maxY - minY; } /*! diff --git a/src/TSGL/TextureHandler.h b/src/TSGL/TextureHandler.h index 2017dbf19..d73335ad6 100644 --- a/src/TSGL/TextureHandler.h +++ b/src/TSGL/TextureHandler.h @@ -71,11 +71,11 @@ class TextureHandler { ~TextureHandler(); - bool drawText(std::wstring text, unsigned int font_size, float* vertices, int centerX = 0, int centerY = 0, float rotation = 0); + bool drawText(std::string text, unsigned int font_size, float* vertices); bool loadFont(const std::string& filename); - void calculateTextCenter(std::wstring text, unsigned int font_size, int leftX, int bottomY, float& centerX, float& centerY); + void calculateTextDimensions(std::string text, unsigned int font_size, float& width, float& height); static void getDimensions(std::string filename, int &width, int &height); diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index f5cc0ad97..6709a174b 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -25,10 +25,28 @@ void textFunction(Canvas& can, std::string font) { // 32, BLUE); // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * text = new Text(0,0,0,"B", font, 100, 0,0,0, YELLOW); + Text * text = new Text(0,0,0,"Blergh", font, 100, 0,0,0, YELLOW); can.add(text); + Rectangle * rec = new Rectangle(0,0,0,360,62,0,0,0, ColorFloat(1,1,1,0.2)); + can.add(rec); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { + // text->setText("Glorgaborg"); + // text->setColor(RED); + // text->setFont("./assets/freefont/FreeSerifItalic.ttf"); + text->setFontSize(50); + }); + + float rotation = 0.0f; while(can.isOpen()) { can.sleep(); + // text->setCenterX(sin(rotation)*200); + // text->setCenterY(cos(rotation)*200); + // text->setCenterZ(sin(rotation)*100); + // text->setYaw(rotation*45); + // text->setPitch(rotation*45); + // text->setRoll(rotation*45); + rotation+=0.01; } delete text; From acad628bfffe84444b30ea12d914042fc476481f Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 24 Jun 2020 13:39:08 -0400 Subject: [PATCH 038/105] Text optimized, legend readded to testPhilosophers --- src/TSGL/Canvas.cpp | 14 +++-- src/TSGL/Text.cpp | 78 ++++++++++++++++++-------- src/TSGL/Text.h | 15 ++++- src/tests/DiningPhilosophers/Table.cpp | 60 ++++++++++++++------ src/tests/DiningPhilosophers/Table.h | 4 +- 5 files changed, 124 insertions(+), 47 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index ed3df0523..7cb5ea258 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -211,7 +211,6 @@ void Canvas::clearObjectBuffer(bool shouldFreeMemory) { void Canvas::draw() { - printf("Entered draw()\n"); glfwMakeContextCurrent(window); // Reset the window glfwSetWindowShouldClose(window, GL_FALSE); @@ -2164,7 +2163,6 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti } void Canvas::initGl() { - printf("Entered initGl.\n"); #ifdef _WIN32 initWindow(); initGlew(); @@ -2199,7 +2197,6 @@ void Canvas::initGl() { hasBackbuffer = ((int)dbuff[0] > 0); glfwMakeContextCurrent(NULL); // Reset the context - printf("Exiting initGl.\n"); } void Canvas::initGlew() { @@ -2253,6 +2250,15 @@ void Canvas::initGlew() { // glm::mat4 view = glm::mat4(1.0f); // view = glm::translate(view, glm::vec3(0.0f, 0.0f, -((winHeight / 2) / tan(glm::pi()/6)))); + char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ + char *res = realpath(".", buf); + if (res) { + printf("This source is at %s.\n", buf); + } else { + perror("realpath"); + exit(EXIT_FAILURE); + } + textShader = new Shader("./assets/shaders/text.vs", "./assets/shaders/text.fs"); // textShader->use(); @@ -2318,7 +2324,6 @@ void Canvas::initGlfw() { } void Canvas::initWindow() { - printf("Entered initWindow.\n"); glfwSetErrorCallback(errorCallback); // Create a Window and the Context @@ -2367,7 +2372,6 @@ void Canvas::initWindow() { // Get info of GPU and supported OpenGL version printf("Renderer: %s\n", glGetString(GL_RENDERER)); printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); - printf("Exiting initWindow.\n"); } void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index f17d198eb..2e9b90b11 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -31,16 +31,16 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename // -------- // All functions return a value different than 0 whenever an error occurred if (FT_Init_FreeType(&ft)) - std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; + TsglErr("ERROR::FREETYPE: Could not init FreeType Library"); // load font as face if (FT_New_Face(ft, fontFilename.c_str(), 0, &face)) - std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; + TsglErr("ERROR::FREETYPE: Failed to load font"); // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - calculateDimensions(); + populateCharacters(); vertices = new float[30]; // Allocate the vertices @@ -80,12 +80,7 @@ void Text::draw(Shader * shader) { float mouseY = -myHeight / 2; std::string::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { - // Load character glyph - if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) - { - std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; - continue; - } + Character ch = Characters[*c]; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -97,12 +92,12 @@ void Text::draw(Shader * shader) { GL_TEXTURE_2D, 0, GL_RED, - face->glyph->bitmap.width, - face->glyph->bitmap.rows, + ch.Bitmap.width, + ch.Bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, - face->glyph->bitmap.buffer + ch.Bitmap.buffer ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -111,11 +106,11 @@ void Text::draw(Shader * shader) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // update vertices for each character - float xpos = mouseX + face->glyph->bitmap_left; - float ypos = mouseY - (face->glyph->bitmap.rows - face->glyph->bitmap_top); + float xpos = mouseX + ch.Bearing.x; + float ypos = mouseY - (ch.Bitmap.rows - ch.Bearing.y); - float w = face->glyph->bitmap.width; - float h = face->glyph->bitmap.rows; + float w = ch.Bitmap.width; + float h = ch.Bitmap.rows; //triangle 1 vertices[0] = xpos; vertices[1] = ypos + h; @@ -126,13 +121,14 @@ void Text::draw(Shader * shader) { vertices[20] = xpos + w; vertices[21] = ypos; vertices[25] = xpos + w; vertices[26] = ypos + h; + // actually draw stuff glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLES, 0, 6); glDeleteTextures(1, &texture); // now advance cursors for next glyph (note that advance is number of 1/64 pixels) - mouseX += (face->glyph->advance.x >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) + mouseX += (ch.Advance >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) } glDisable(GL_TEXTURE_2D); } @@ -146,8 +142,12 @@ void Text::draw(Shader * shader) { void Text::setText(std::string text) { attribMutex.lock(); init = false; + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); + } myString = text; - calculateDimensions(); + populateCharacters(); init = true; attribMutex.unlock(); } @@ -160,13 +160,17 @@ void Text::setText(std::string text) { */ void Text::setFontSize(unsigned int fontsize) { attribMutex.lock(); + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); + } init = false; myFontSize = fontsize; // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - calculateDimensions(); + populateCharacters(); init = true; attribMutex.unlock(); } @@ -180,6 +184,10 @@ void Text::setFontSize(unsigned int fontsize) { void Text::setFont(std::string filename) { attribMutex.lock(); init = false; + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); + } FT_Done_Face(face); myFont = filename; // load font as face @@ -190,7 +198,7 @@ void Text::setFont(std::string filename) { // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - calculateDimensions(); + populateCharacters(); init = true; attribMutex.unlock(); } @@ -201,7 +209,9 @@ void Text::setFont(std::string filename) { * \param color The ColorFloat to change myColor to. */ void Text::setColor(const ColorFloat& color) { + attribMutex.lock(); myColor = color; + attribMutex.unlock(); } /*! @@ -209,27 +219,47 @@ void Text::setColor(const ColorFloat& color) { * \details This function assigns values to myWidth and myHeight based on * the glyphs loaded based on myFontSize, myFont, and myString. */ -void Text::calculateDimensions() { +void Text::populateCharacters() { + // note: this will leak memory if you don't free the bitmaps within first. see most mutators. + Characters.clear(); myWidth = 0; myHeight = 0; - std::string::const_iterator c; - for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap * ftbmps = new FT_Bitmap[myString.size()]; + + for (int i = 0; i < myString.size(); i++) { // Load character glyph - if (FT_Load_Char(face, *c, FT_LOAD_RENDER)) + if (FT_Load_Char(face, myString[i], FT_LOAD_RENDER)) { std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; continue; } + FT_Bitmap_Init(&ftbmps[i]); + FT_Bitmap_Copy(ft, &face->glyph->bitmap, &ftbmps[i]); + + Character character = { + ftbmps[i], + glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), + face->glyph->advance.x + }; + + Characters.insert(std::pair(myString[i], character)); + myWidth += face->glyph->advance.x >> 6; if (face->glyph->bitmap.rows > myHeight) myHeight = face->glyph->bitmap.rows; } + + delete [] ftbmps; } Text::~Text() { // destroy FreeType once we're finished + std::string::const_iterator c; + for (c = myString.begin(); c != myString.end(); c++) { + FT_Bitmap_Done(ft, &Characters[*c].Bitmap); + } FT_Done_Face(face); FT_Done_FreeType(ft); } diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index af571f3bb..eaac8d3f8 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -7,8 +7,10 @@ #include "Drawable.h" // For extending our Shape object #include +#include #include #include FT_FREETYPE_H +#include FT_BITMAP_H // #include "TextureHandler.h" namespace tsgl { @@ -32,7 +34,15 @@ class Text : public Drawable { FT_Face face; FT_Library ft; - void calculateDimensions(); + struct Character { + FT_Bitmap Bitmap; + glm::ivec2 Bearing; // Offset from baseline to left/top of glyph + unsigned int Advance; // Horizontal offset to advance to next glyph + }; + + std::map Characters; + + void populateCharacters(); public: Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); @@ -50,6 +60,9 @@ class Text : public Drawable { unsigned int getFontSize() { return myFontSize; } + GLfloat getWidth() { return myWidth; } + GLfloat getHeight() { return myHeight; } + ~Text(); }; diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 081d53672..79e75931f 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -20,7 +20,7 @@ Table::Table(Canvas& can, int p, PhilMethod m) { forks[i].id = i; forks[i].setCanvas(myCan); } - spaghettis = new Image*[numPhils]; + spaghettis = new Image*[numPhils](); float delta = 2.0f / numPhils * PI; for(int i = 0; i < numPhils; i++) { spaghettis[i] = new Image(120 * cos(i*delta), 140 * sin(i*delta), -0.5, "./assets/pics/spaghet.png", 100, 50, 0,0,0); @@ -48,27 +48,55 @@ Table::Table(Canvas& can, int p, PhilMethod m) { break; } - // myCan2 = new Canvas(0,0,300,300,"Legend"); - // myCan2->start(); - // myCan2->drawText("Method:",16,32,32,BLACK); - // myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); - // myCan2->drawText("Legend:",16,96,24,BLACK); - // myCan2->drawText("Red: Hungry",32,128,24,RED); - // myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); - // myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); - // myCan2->drawText("Green: Eating",32,224,24,GREEN); - // myCan2->drawText("Blue: Thinking",32,256,24,BLUE); - // myCan2->drawText("Meals eaten: ",32,288,24,BROWN); - // myCan2->drawCircle(165,281,3,BROWN); + myCan2 = new Canvas(0,0,300,300,"Legend"); + myCan2->start(); + myCan2->setBackgroundColor(GRAY); + + legendTexts = new Text*[9](); + legendTexts[0] = new Text(-134,128,0,"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); + legendTexts[0]->changeXBy(legendTexts[0]->getWidth() / 2); + myCan2->add(legendTexts[0]); + legendTexts[1] = new Text(-118,96,0,"\"" + methodString + "\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[1]->changeXBy(legendTexts[1]->getWidth() / 2); + myCan2->add(legendTexts[1]); + legendTexts[2] = new Text(-134,64,0,"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[2]->changeXBy(legendTexts[2]->getWidth() / 2); + myCan2->add(legendTexts[2]); + legendTexts[3] = new Text(-118,32,0,"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); + legendTexts[3]->changeXBy(legendTexts[3]->getWidth() / 2); + myCan2->add(legendTexts[3]); + legendTexts[4] = new Text(-118,0,0,"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); + legendTexts[4]->changeXBy(legendTexts[4]->getWidth() / 2); + myCan2->add(legendTexts[4]); + legendTexts[5] = new Text(-118,-32,0,"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); + legendTexts[5]->changeXBy(legendTexts[5]->getWidth() / 2); + myCan2->add(legendTexts[5]); + legendTexts[6] = new Text(-118,-64,0,"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); + legendTexts[6]->changeXBy(legendTexts[6]->getWidth() / 2); + myCan2->add(legendTexts[6]); + legendTexts[7] = new Text(-118,-96,0,"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); + legendTexts[7]->changeXBy(legendTexts[7]->getWidth() / 2); + myCan2->add(legendTexts[7]); + legendTexts[8] = new Text(-118,-121,0,"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); + legendTexts[8]->changeXBy(legendTexts[8]->getWidth() / 2); + myCan2->add(legendTexts[8]); + + exampleMeal = new RegularPolygon(15, -121,0,3,3,0,0,0, BROWN); + myCan2->add(exampleMeal); } /*! * \brief Destructor for Table. */ Table::~Table() { - // if (myCan2->isOpen()) - // myCan2->stop(); - // delete myCan2; + if (myCan2->isOpen()) + myCan2->stop(); + delete myCan2; + for (int i = 0; i < 9; i++) { + delete legendTexts[i]; + } + delete[] legendTexts; + delete exampleMeal; for (int i = 0; i < numPhils; i++) { delete spaghettis[i]; } diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h index ee81d053e..ed961d285 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/tests/DiningPhilosophers/Table.h @@ -25,11 +25,13 @@ class Table { int numPhils; PhilMethod myMethod; std::string methodString; - Canvas *myCan/* , *myCan2 */; + Canvas *myCan, *myCan2; Philosopher *phils; Fork *forks; Circle * myTable; Image ** spaghettis; + Text ** legendTexts; + RegularPolygon * exampleMeal; // TextureHandler loader; public: Table(Canvas& can, int p, PhilMethod m); From a92e7295a60a142bf433d194c84d36343d694594 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 24 Jun 2020 15:27:23 -0400 Subject: [PATCH 039/105] Removed old outline implementation. Updated docs --- src/TSGL/Circle.cpp | 26 +++---- src/TSGL/Circle.h | 4 -- src/TSGL/ConcavePolygon.cpp | 69 +++++++++---------- src/TSGL/Cone.cpp | 12 +--- src/TSGL/ConvexPolygon.cpp | 57 ++++++++------- src/TSGL/Cube.cpp | 6 +- src/TSGL/Cuboid.cpp | 6 +- src/TSGL/Cylinder.cpp | 6 -- src/TSGL/Ellipse.cpp | 26 +++---- src/TSGL/Ellipse.h | 2 - src/TSGL/Ellipsoid.cpp | 8 +-- src/TSGL/Polyline.cpp | 6 -- src/TSGL/Prism.cpp | 6 -- src/TSGL/Pyramid.cpp | 6 -- src/TSGL/Rectangle.cpp | 24 ++++--- src/TSGL/RegularPolygon.cpp | 38 +++++----- src/TSGL/Shape.cpp | 19 +---- src/TSGL/Shape.h | 11 --- src/TSGL/Sphere.cpp | 8 +-- src/TSGL/Square.cpp | 28 ++++---- src/TSGL/Star.cpp | 20 +++--- src/TSGL/Triangle.cpp | 4 +- src/TSGL/TriangleStrip.cpp | 41 ++++++----- src/tests/DiningPhilosophers/Philosopher.cpp | 1 - .../DiningPhilosophers3D/Philosopher3D.cpp | 1 - src/tests/testClock.cpp | 1 - src/tests/testConvexPolygon.cpp | 1 - src/tests/testCylinder.cpp | 1 - src/tests/testDiorama.cpp | 7 -- src/tests/testEllipsoid.cpp | 1 - src/tests/testMergeSort.cpp | 1 - src/tests/testPrism.cpp | 1 - src/tests/testRectangle.cpp | 2 - src/tests/testRegularPolygon.cpp | 1 - src/tests/testShakerSort.cpp | 1 - src/tests/testSolarSystem.cpp | 2 - src/tests/testSphere.cpp | 1 - src/tests/testSquare.cpp | 1 - src/tests/testStar.cpp | 1 - src/tests/testTriangle.cpp | 1 - src/tests/testTriangleStrip.cpp | 1 - 41 files changed, 194 insertions(+), 265 deletions(-) diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index f02b84382..b4cd1a4b7 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -3,14 +3,16 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new monocolored filled or outlined Circle. - * \details This function draws a circle with the given center, radius, color, and outline color. + * \brief Explicitly constructs a new monocolored filled Circle. + * \details This function draws a circle with the given center, radius, 3D rotation, color. * \param x The x coordinate of the circle's center. * \param y The y coordinate of the circle's center. + * \param z The z coordinate of the circle's center. * \param radius The radius of the circle in pixels. - * \param color The color of the circle's fill or outline - * \param filled Whether the circle should be filled - * (set to true by default). + * \param yaw The circle's yaw in 3D space. + * \param pitch The circle's pitch in 3D space. + * \param roll The circle's roll in 3D space. + * \param color The color of the circle's fill */ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(radius + 5) + 1,yaw,pitch,roll) { if (radius <= 0) { @@ -20,7 +22,6 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; - edgesOutlined = false; verticesPerColor = (myRadius + 6) / 8; attribMutex.unlock(); addVertex(0,0,0,color); @@ -31,14 +32,16 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch } /*! - * \brief Explicitly constructs a new multicolored filled or outlined Circle. - * \details This function draws a circle with the given center, radius, color, and outline color. + * \brief Explicitly constructs a new multicolored filled Circle. + * \details This function draws a circle with the given center, radius, roation, and fill color. * \param x The x coordinate of the circle's center. * \param y The y coordinate of the circle's center. + * \param z The z coordinate of the circle's center. * \param radius The radius of the circle in pixels. - * \param color An array of colors for the Circle's fill or outline - * \param filled Whether the circle should be filled - * (set to true by default). + * \param yaw The circle's yaw in 3D space. + * \param pitch The circle's pitch in 3D space. + * \param roll The circle's roll in 3D space. + * \param color An array of colors for the Circle's fill */ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(GLint) (radius + 5) + 1,yaw,pitch,roll) { if (radius <= 0) { @@ -48,7 +51,6 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch attribMutex.lock(); myXScale = myYScale = myRadius = radius; myZScale = 1; - edgesOutlined = false; verticesPerColor = (myRadius + 6) / 8; attribMutex.unlock(); addVertex(0,0,0,color[0]); diff --git a/src/TSGL/Circle.h b/src/TSGL/Circle.h index dd6224486..2cc0353cb 100644 --- a/src/TSGL/Circle.h +++ b/src/TSGL/Circle.h @@ -35,10 +35,6 @@ class Circle : public ConvexPolygon { void setColor(ColorFloat c) { Shape::setColor(c); } void setColor(ColorFloat c[]); - - void displayOutlineEdges(bool b) { } - - }; } diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index c078361bd..c2feb15a0 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -4,41 +4,45 @@ namespace tsgl { /*! * \brief Explicitly constructs a new ConcavePolygon. - * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. + * \details Protected explicit constructor for a ConcavePolygon object. Used as a superclass constructor. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - edgesOutlined = false; geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 7]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } /*! - * \brief Explicitly constructs a new ConcavePolygon with monocolored fill or outline. + * \brief Explicitly constructs a new ConcavePolygon with monocolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConcavePolygon's fill or outline. - * \param filled Whether the ConcavePolygon should be filled - * (set to true by default). + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color A ColorFloat, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - edgesOutlined = false; geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 7]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -47,24 +51,25 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int } /*! - * \brief Explicitly constructs a new ConcavePolygon with multicolored fill or outline. + * \brief Explicitly constructs a new ConcavePolygon with multicolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param numVertices The number of vertices the complete ConcavePolygon will have. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConcavePolygon's fill or outline. - * \param filled Whether the ConcavePolygon should be filled - * (set to true by default). + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); - edgesOutlined = false; geometryType = GL_TRIANGLE_FAN; numberOfVertices = numVertices; - numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; - vertices = new GLfloat[numberOfOutlineVertices * 7]; + vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { @@ -117,13 +122,5 @@ void ConcavePolygon::draw(Shader * shader) { glDrawArrays(geometryType, 0, numberOfVertices); glDisable(GL_STENCIL_TEST); - /* end */ - - // if (edgesOutlined) { - // glVertexPointer(3, GL_FLOAT, outlineStride*sizeof(GLfloat)*3, vertices); - // glColorPointer(4, GL_FLOAT, 0, outlineArray); - - // glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); - // } } } diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index fbcfbfb15..69ec9cb1c 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -18,11 +18,7 @@ namespace tsgl { * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { - outlineStride = 6; - numberOfOutlineVertices = mySides; - outlineGeometryType = GL_LINE_LOOP; -} +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { } /*! * \brief Explicitly constructs a new Cone. @@ -40,11 +36,7 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { - outlineStride = 6; - numberOfOutlineVertices = mySides; - outlineGeometryType = GL_LINE_LOOP; -} +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { } /*! * \brief Destructor for the Cone. diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index ec041ece7..c0137e6fb 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -4,38 +4,44 @@ namespace tsgl { /*! * \brief Explicitly constructs a new ConvexPolygon. - * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the complete ConvexPolygon will have. - * \param filled Whether or not the ConvexPolygon is filled. - * \param outlined Whether or not the ConvexPolygon is outlined. + * \details Protected explicit constructor for a Convex Polygon object. Used as superclass constructor. + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space.. * \return A new ConvexPolygon with a buffer for storing the specified numbered of vertices. */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } /*! - * \brief Explicitly constructs a new ConvexPolygon with monocolored fill or outline. + * \brief Explicitly constructs a new ConvexPolygon with monocolored fill. * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color The color of the ConvexPolygon. - * \param filled Whether or not the ConvexPolygon is filled. - * (set to true by default). + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param x An array of the ConvexPolygon's x vertices. + * \param y An array of the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space. + * \param color A ColorFloat, the ConvexPolygon's fill color. * \return A new ConvexPolygon with the specified vertices and color. */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); @@ -45,21 +51,24 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n } /*! - * \brief Explicitly constructs a new ConvexPolygon with multicolored fill or outline. + * \brief Explicitly constructs a new ConvexPolygon with multicolored fill. * \details Explicit constructor for a Convex Polygon object. - * \param numVertices The number of vertices the ConvexPolygon has. - * \param x An array of x values for the vertices. - * \param y An array of y values for the vertices. - * \param color An array of colors for the ConvexPolygon. - * \param filled Whether or not the ConvexPolygon is filled. - * (set to true by default). + * \param centerX The x coordinate of the ConvexPolygon's center. + * \param centerY The y coordinate of the ConvexPolygon's center. + * \param centerZ The z coordinate of the ConvexPolygon's center. + * \param numVertices The number of vertices that make up the ConvexPolygon. + * \param x An array of the ConvexPolygon's x vertices. + * \param y An array of the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw in 3D space. + * \param pitch The ConvexPolygon's pitch in 3D space. + * \param roll The ConvexPolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConvexPolygon's fill color. * \return A new ConvexPolygon with the specified vertices and color. */ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numberOfOutlineVertices = numVertices; - outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index 12b755223..bcf9338d3 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -27,8 +27,7 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = numberOfOutlineVertices = 36; - outlineGeometryType = GL_LINES; + numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); @@ -99,8 +98,7 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myXScale = sideLength; myYScale = sideLength; myZScale = sideLength; - numberOfVertices = numberOfOutlineVertices = 36; - outlineGeometryType = GL_LINES; + numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index ff0802607..eb875537b 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -31,8 +31,7 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = numberOfOutlineVertices = 36; - outlineGeometryType = GL_LINES; + numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); @@ -107,8 +106,7 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myXScale = width; myYScale = height; myZScale = length; - numberOfVertices = numberOfOutlineVertices = 36; - outlineGeometryType = GL_LINES; + numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index 078912b76..6d666b299 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -19,9 +19,6 @@ namespace tsgl { */ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { - outlineStride = 3; - numberOfOutlineVertices = mySides * 4; - outlineGeometryType = GL_LINES; } /*! @@ -41,9 +38,6 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) : Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { - outlineStride = 3; - numberOfOutlineVertices = mySides * 4; - outlineGeometryType = GL_LINES; } /*! diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index 450ed33c9..df3e2f161 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -3,22 +3,23 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new monocolored filled or outlined Ellipse. - * \details This function draws a Ellipse with the given center, radii, color, and outline color. + * \brief Explicitly constructs a new monocolored Ellipse. + * \details This function draws a Ellipse with the given center, radii, rotation, and color. * \param x The x coordinate of the Ellipse's center. * \param y The y coordinate of the Ellipse's center. + * \param z The z coordinate of the Ellipse's center. * \param xRadius The horizontal radius of the Ellipse in pixels. * \param yRadius The vertical radius of the Ellipse in pixels. - * \param color The color of the Ellipse's fill or outline - * \param filled Whether the Ellipse should be filled - * (set to true by default). + * \param yaw The Ellipse's yaw in 3D space. + * \param pitch The Ellipse's pitch in 3D space. + * \param roll The Ellipse's roll in 3D space. + * \param color The color of the Ellipse's fill. */ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; myZScale = 1; - edgesOutlined = false; verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; attribMutex.unlock(); addVertex(0,0,0,color); @@ -29,22 +30,23 @@ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, fl } /*! - * \brief Explicitly constructs a new multicolored filled or outlined Ellipse. - * \details This function draws a Ellipse with the given center, radii, color, and outline color. + * \brief Explicitly constructs a new multicolored Ellipse. + * \details This function draws a Ellipse with the given center, radii, rotation, and color. * \param x The x coordinate of the Ellipse's center. * \param y The y coordinate of the Ellipse's center. + * \param z The z coordinate of the Ellipse's center. * \param xRadius The horizontal radius of the Ellipse in pixels. * \param yRadius The vertical radius of the Ellipse in pixels. - * \param color An array of colors for the Ellipse's fill or outline - * \param filled Whether the Ellipse should be filled - * (set to true by default). + * \param yaw The Ellipse's yaw in 3D space. + * \param pitch The Ellipse's pitch in 3D space. + * \param roll The Ellipse's roll in 3D space. + * \param color An array of colors for the Ellipse's fill. */ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,(xRadius + yRadius) / 2 + 5 + 1,yaw,pitch,roll) { attribMutex.lock(); myXScale = myXRadius = xRadius; myYScale = myYRadius = yRadius; myZScale = 1; - edgesOutlined = false; verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; attribMutex.unlock(); addVertex(0,0,0,color[0]); diff --git a/src/TSGL/Ellipse.h b/src/TSGL/Ellipse.h index a1adbcb1d..88b6b5c39 100644 --- a/src/TSGL/Ellipse.h +++ b/src/TSGL/Ellipse.h @@ -45,8 +45,6 @@ class Ellipse : public ConvexPolygon { void setColor(ColorFloat c) { Shape::setColor(c); } void setColor(ColorFloat c[]); - - void displayOutlineEdges(bool b) { } }; } diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index d377a8f13..bc967451a 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -26,9 +26,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius geometryType = GL_TRIANGLE_STRIP; verticalSections = 36; horizontalSections = 20; - numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; - outlineGeometryType = GL_LINES; - edgesOutlined = false; + numberOfVertices = verticalSections*horizontalSections*2 + 1; vertices = new GLfloat[numberOfVertices * 7]; myXRadius = xRadius; myYRadius = yRadius; @@ -72,9 +70,7 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius geometryType = GL_TRIANGLE_STRIP; verticalSections = 36; horizontalSections = 20; - numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; - outlineGeometryType = GL_LINES; - edgesOutlined = false; + numberOfVertices = verticalSections*horizontalSections*2 + 1; vertices = new GLfloat[numberOfVertices * 7]; myXRadius = xRadius; myYRadius = yRadius; diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index d7c128ccc..3362685e2 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -20,8 +20,6 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float yaw, float TsglDebug("Cannot have a line with fewer than 2 vertices."); attribMutex.lock(); numberOfVertices = numVertices; - numberOfOutlineVertices = 0; - edgesOutlined = false; myXScale = myYScale = myZScale = 1; vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; @@ -48,8 +46,6 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice TsglDebug("Cannot have a line with fewer than 2 vertices."); attribMutex.lock(); numberOfVertices = numVertices; - numberOfOutlineVertices = 0; - edgesOutlined = false; myXScale = myYScale = myZScale = 1; vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; @@ -79,8 +75,6 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice TsglDebug("Cannot have a line with fewer than 2 vertices."); attribMutex.lock(); numberOfVertices = numVertices; - numberOfOutlineVertices = 0; - edgesOutlined = false; myXScale = myYScale = myZScale = 1; vertices = new GLfloat[numberOfVertices * 7]; geometryType = GL_LINE_STRIP; diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index d3c374cc4..b88afe63e 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -31,9 +31,6 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu mySides = sides; geometryType = GL_TRIANGLES; numberOfVertices = mySides * 12; - outlineStride = 2; - numberOfOutlineVertices = mySides * 6; - outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { @@ -84,9 +81,6 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu mySides = sides; geometryType = GL_TRIANGLES; numberOfVertices = mySides * 12; - outlineStride = 2; - numberOfOutlineVertices = mySides * 6; - outlineGeometryType = GL_LINES; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index aea8419f1..966e6512c 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -35,9 +35,6 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r mySides = sides; geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; - outlineStride = 2; - outlineGeometryType = GL_LINE_LOOP; - numberOfOutlineVertices = mySides * 3; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { @@ -84,9 +81,6 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r mySides = sides; geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; - outlineStride = 2; - outlineGeometryType = GL_LINE_LOOP; - numberOfOutlineVertices = mySides * 3; vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { diff --git a/src/TSGL/Rectangle.cpp b/src/TSGL/Rectangle.cpp index 2fdf74d39..e82282718 100644 --- a/src/TSGL/Rectangle.cpp +++ b/src/TSGL/Rectangle.cpp @@ -3,15 +3,17 @@ namespace tsgl { /*! - * \brief Explicitly constructs a Rectangle with monocolored fill or outline. + * \brief Explicitly constructs a Rectangle with monocolored fill. * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. + * \param x The x coordinate of the Rectangle's center. + * \param y The y coordinate of the Rectangle's center. + * \param z The z coordinate of the Rectangle's center. * \param width The width of the Rectangle. * \param height The height of the Rectangle. + * \param yaw The Rectangle's yaw in 3D space. + * \param pitch The Rectangle's pitch in 3D space. + * \param roll The Rectangle's roll in 3D space. * \param color The color of the Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and color. */ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { @@ -31,15 +33,17 @@ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, f } /*! - * \brief Explicitly constructs a Rectangle with multicolored fill or outline. + * \brief Explicitly constructs a Rectangle with multicolored fill. * \details This is the constructor for the Rectangle class. - * \param x The x coordinate of the Rectangle's left edge. - * \param y The y coordinate of the Rectangle's top edge. + * \param x The x coordinate of the Rectangle's center. + * \param y The y coordinate of the Rectangle's center. + * \param z The z coordinate of the Rectangle's center. * \param width The width of the Rectangle. * \param height The height of the Rectangle. + * \param yaw The Rectangle's yaw in 3D space. + * \param pitch The Rectangle's pitch in 3D space. + * \param roll The Rectangle's roll in 3D space. * \param color An array of colors for the vertices of the Rectangle. - * \param filled Whether the Rectangle should be filled - * (set to true by default). * \return A new Rectangle with the specified top left corner, dimensions, and colors. */ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index 2d42470a0..5311e640b 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -3,16 +3,18 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new RegularPolygon with monocolored fill or outline. - * \details This function draws a regular polygon with the given center, radius, resolution + * \brief Explicitly constructs a new RegularPolygon with monocolored fill. + * \details This function draws a regular polygon with the given center, sides, radius, rotation, and color. * (number of sides), and color. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. - * \param color The color of the regular polygon. - * \param filled Whether the regular polygon should be filled - * (set to true by default). + * \param x The x coordinate of the RegularPolygon's center. + * \param y The y coordinate of the RegularPolygon's center. + * \param z The z coordinate of the RegularPolygon's center. + * \param radius The radius of the RegularPolygon in pixels. + * \param sides The number of sides to use in the RegularPolygon. + * \param yaw The RegularPolygon's yaw in 3D space. + * \param pitch The RegularPolygon's pitch in 3D space. + * \param roll The RegularPolygon's roll in 3D space. + * \param color The color of the RegularPolygon. */ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { attribMutex.lock(); @@ -26,16 +28,18 @@ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int si } /*! - * \brief Explicitly constructs a new RegularPolygon with multicolored fill or outline. - * \details This function draws a regular polygon with the given center, radius, resolution + * \brief Explicitly constructs a new RegularPolygon with multicolored fill. + * \details This function draws a regular polygon with the given center, sides, radius, rotation, and color. * (number of sides), and coloring. - * \param x The x coordinate of the regular polygon's center. - * \param y The y coordinate of the regular polygon's center. - * \param radius The radius of the regular polygon in pixels. - * \param sides The number of sides to use in the regular polygon. + * \param x The x coordinate of the RegularPolygon's center. + * \param y The y coordinate of the RegularPolygon's center. + * \param z The z coordinate of the RegularPolygon's center. + * \param radius The radius of the RegularPolygon in pixels. + * \param sides The number of sides to use in the RegularPolygon. + * \param yaw The RegularPolygon's yaw in 3D space. + * \param pitch The RegularPolygon's pitch in 3D space. + * \param roll The RegularPolygon's roll in 3D space. * \param color An array of colors for the regular polygon's vertices. - * \param filled Whether the regular polygon should be filled - * (set to true by default). */ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int sides, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,sides,yaw,pitch,roll) { attribMutex.lock(); diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index 8c8fb0d12..d01f4cb6a 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -64,14 +64,10 @@ void Shape::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) vertices[currentVertex + 5] = color.B; vertices[currentVertex + 6] = color.A; currentVertex += 7; - attribMutex.unlock(); if (currentVertex == numberOfVertices*7) { - attribMutex.lock(); - // outlineArray = new GLfloat[numberOfOutlineVertices*4]; - // std::fill_n(outlineArray, numberOfOutlineVertices*4, 0.75); init = true; - attribMutex.unlock(); } + attribMutex.unlock(); } /** @@ -102,17 +98,4 @@ void Shape::setColor(ColorFloat c[]) { } } -/** - * \brief Sets the Shape's outline/edges to a new color - * \param c The new ColorFloat. - */ -void Shape::setEdgeColor(ColorFloat c) { - // for (int i = 0; i < numberOfOutlineVertices; i++) { - // outlineArray[4*i] = c.R; - // outlineArray[4*i+1] = c.G; - // outlineArray[4*i+2] = c.B; - // outlineArray[4*i+3] = c.A; - // } -} - } \ No newline at end of file diff --git a/src/TSGL/Shape.h b/src/TSGL/Shape.h index f855beb4c..b10fb9052 100755 --- a/src/TSGL/Shape.h +++ b/src/TSGL/Shape.h @@ -28,13 +28,9 @@ namespace tsgl { */ class Shape : public Drawable { protected: - bool edgesOutlined = true; int numberOfVertices; - int numberOfOutlineVertices; - GLsizei outlineStride = 0; int currentVertex = 0; GLenum geometryType; - GLenum outlineGeometryType; virtual void addVertex(float x, float y, float z, const ColorFloat &color = WHITE); public: @@ -44,13 +40,6 @@ class Shape : public Drawable { virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); - virtual void setEdgeColor(ColorFloat c); - - /* - * \brief Mutator that determines if the edges of the Shape should be highlighted. - * \details Updates the value of the edgesOutlined instance variable. Defaults to true. - */ - virtual void displayOutlineEdges(bool on=true) { edgesOutlined=on; } }; } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 788d0f7e8..289688185 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -25,9 +25,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch geometryType = GL_TRIANGLE_STRIP; verticalSections = 36; horizontalSections = 20; - numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2+1; - outlineGeometryType = GL_LINES; - edgesOutlined = false; + numberOfVertices = verticalSections*horizontalSections*2+1; vertices = new GLfloat[numberOfVertices * 7]; myRadius = radius; myXScale = radius; @@ -67,9 +65,7 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch geometryType = GL_TRIANGLE_STRIP; verticalSections = 36; horizontalSections = 20; - numberOfVertices = numberOfOutlineVertices = verticalSections*horizontalSections*2 + 1; - outlineGeometryType = GL_LINES; - edgesOutlined = false; + numberOfVertices = verticalSections*horizontalSections*2 + 1; vertices = new GLfloat[numberOfVertices * 7]; myRadius = radius; myXScale = radius; diff --git a/src/TSGL/Square.cpp b/src/TSGL/Square.cpp index a0ef6e290..ea678ace0 100644 --- a/src/TSGL/Square.cpp +++ b/src/TSGL/Square.cpp @@ -3,14 +3,16 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Square with monocolored fill or outline. - * \details This function draws a Square with the given upper left corner, sidelength, and color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. + * \brief Explicitly constructs a new Square with monocolored fill. + * \details This function draws a Square with the given center, sidelength, rotation, and color. + * \param x The x coordinate of the Square's center. + * \param y The y coordinate of the Square's center. + * \param z The z coordinate of the Square's center. * \param sideLength The side length of the Square in pixels. + * \param yaw The Square's yaw in 3D space. + * \param pitch The Square's pitch in 3D space. + * \param roll The Square's roll in 3D space. * \param color The color of the Square. - * \param filled Whether the Square should be filled - * (set to true by default). */ Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { attribMutex.lock(); @@ -24,14 +26,16 @@ Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float p } /*! - * \brief Explicitly constructs a new Square with multicolored fill or outline. - * \details This function draws a Square with the given upper left corner, sidelength, and color. - * \param x The x coordinate of the Square's left edge. - * \param y The y coordinate of the Square's top edge. + * \brief Explicitly constructs a new Square with multicolored fill. + * \details This function draws a Square with the given center, sidelength, rotation, and color. + * \param x The x coordinate of the Square's center. + * \param y The y coordinate of the Square's center. + * \param z The z coordinate of the Square's center. * \param sideLength The side length of the Square in pixels. + * \param yaw The Square's yaw in 3D space. + * \param pitch The Square's pitch in 3D space. + * \param roll The Square's roll in 3D space. * \param color An array of colors for the Square's vertices. - * \param filled Whether the Square should be filled - * (set to true by default). */ Square::Square(float x, float y, float z, GLfloat sideLength, float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(x,y,z,4,yaw,pitch,roll) { attribMutex.lock(); diff --git a/src/TSGL/Star.cpp b/src/TSGL/Star.cpp index cd7e1473c..3a2cc88a6 100644 --- a/src/TSGL/Star.cpp +++ b/src/TSGL/Star.cpp @@ -3,16 +3,18 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Star with monocolored fill or outline. + * \brief Explicitly constructs a new Star with monocolored fill. * \details This function draws a star with the given center, - * radius, points, and color. + * radius, points, rotation, and color. * \param x The x coordinate of the star's center. * \param y The y coordinate of the star's center. + * \param z The z coordinate of the star's center. * \param radius The radius of the star in pixels. + * \param yaw The star's yaw in 3D space. + * \param pitch The star's pitch in 3D space. + * \param roll The star's roll in 3D space. * \param points The number of points to use in the star. * \param color The color of the star. - * \param filled Whether the star should be filled - * (set to true by default). * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ @@ -40,16 +42,18 @@ Star::Star(float x, float y, float z, GLfloat radius, int points, float yaw, flo } /*! - * \brief Explicitly constructs a new Star with multicolored fill or outline. + * \brief Explicitly constructs a new Star with multicolored fill. * \details This function draws a star with the given center, - * radius, points, and color. + * radius, points, rotation, and color. * \param x The x coordinate of the star's center. * \param y The y coordinate of the star's center. + * \param z The z coordinate of the star's center. * \param radius The radius of the star in pixels. + * \param yaw The star's yaw in 3D space. + * \param pitch The star's pitch in 3D space. + * \param roll The star's roll in 3D space. * \param points The number of points to use in the star. * \param color An array of colors for the star. - * \param filled Whether the star should be filled - * (set to true by default). * \param ninja The ninja setting of the star, making the star points spin differently if true * (set to false by default). */ diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index 7cbd1e727..9e1317c13 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -3,7 +3,7 @@ namespace tsgl { /*! - * \brief Explicitly constructs a new Triangle with monocolored fill or outline. + * \brief Explicitly constructs a new Triangle with monocolored fill. * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. @@ -31,7 +31,7 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f } /*! - * \brief Explicitly constructs a new Triangle with multicolored fill or outline. + * \brief Explicitly constructs a new Triangle with multicolored fill. * \details This is the constructor for the Triangle class. * \param x1 The x coordinate of the first endpoint. * \param y1 The y coordinate of the first endpoint. diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index c4dfcf12c..96a5fb3d0 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -3,21 +3,24 @@ namespace tsgl { /*! - * \brief Explicitly construct a new TriangleStrip with monocolored fill or outline. + * \brief Explicitly construct a new TriangleStrip with monocolored fill. * \details Explicit constructor for a TriangleStrip object. - * \param x - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param color The color of the TriangleStrip - * \param filled Whether the TriangleStrip should be filled - * (set to true by default). + * \param centerX The x coordinate of the center of the TriangleStrip. + * \param centerY The y coordinate of the center of the TriangleStrip. + * \param centerZ The z coordinate of the center of the TriangleStrip. + * \param numVertices The number of vertices. + * \param x An array of numVertices x parameters for the vertices of the TriangleStrip. + * \param y An array of numVertices y parameters for the vertices of the TriangleStrip. + * \param z An array of numVertices z parameters for the vertices of the TriangleStrip. + * \param yaw The TriangleStrip's yaw. + * \param pitch The TriangleStrip's pitch. + * \param roll The TriangleStrip's roll. + * \param color The color of the TriangleStrip * \return A new TriangleStrip with the specified vertices and color. */ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_STRIP; - outlineGeometryType = GL_LINE_STRIP; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], z[i], color); @@ -25,20 +28,24 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu } /*! - * \brief Explicitly construct a new TriangleStrip with multicolored fill or outline. + * \brief Explicitly construct a new TriangleStrip with multicolored fill. * \details Explicit constructor for a TriangleStrip object. - * \param numVertices The number of vertices. - * \param x An array of x parameters for the vertices - * \param y An array of y parameters for the vertices - * \param color An array of colors for the TriangleStrip - * \param filled Whether the TriangleStrip should be filled - * (set to true by default). + * \param centerX The x coordinate of the center of the TriangleStrip. + * \param centerY The y coordinate of the center of the TriangleStrip. + * \param centerZ The z coordinate of the center of the TriangleStrip. + * \param numVertices The number of vertices. + * \param x An array of numVertices x parameters for the vertices of the TriangleStrip. + * \param y An array of numVertices y parameters for the vertices of the TriangleStrip. + * \param z An array of numVertices z parameters for the vertices of the TriangleStrip. + * \param yaw The TriangleStrip's yaw. + * \param pitch The TriangleStrip's pitch. + * \param roll The TriangleStrip's roll. + * \param color An array of colors for the TriangleStrip * \return A new TriangleStrip with the specified vertices and color. */ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_STRIP; - outlineGeometryType = GL_LINE_STRIP; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], z[i], color[i]); diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp index 3f5c01eed..2e7dc6432 100644 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ b/src/tests/DiningPhilosophers/Philosopher.cpp @@ -54,7 +54,6 @@ void Philosopher::refreshColor() { void Philosopher::addMeal(float x, float y, float z) { numMeals++; meals.push_back(new RegularPolygon(x,y,z,3,3,0,0,0,ColorFloat(0.5,0.3,0,1))); - meals.back()->displayOutlineEdges(false); } RegularPolygon * Philosopher::getLastMeal() { diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp index f1bc198a8..b7e9c0b92 100644 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp +++ b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp @@ -62,7 +62,6 @@ void Philosopher3D::refreshColor() { void Philosopher3D::addMeal(float x, float y, float z) { numMeals++; meals.push_back(new Pyramid(x,y,z,3,8,4,0,0,90,ColorFloat(0.5,0.3,0,1))); - meals.back()->displayOutlineEdges(false); } Pyramid * Philosopher3D::getLastMeal() { diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp index 14c54e479..08feb2ce9 100644 --- a/src/tests/testClock.cpp +++ b/src/tests/testClock.cpp @@ -47,7 +47,6 @@ void clockFunction(Canvas& can) { Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); cord->setRotationPoint(0,80,10); - cord->displayOutlineEdges(false); can.add(cord); time_t t = time(NULL); diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp index 3ded434de..258a49e4a 100644 --- a/src/tests/testConvexPolygon.cpp +++ b/src/tests/testConvexPolygon.cpp @@ -39,7 +39,6 @@ void convexPolygonFunction(Canvas& can) { // cp->setColor(RED); // if (floatVal > 400) { // floatVal = 0; - // cp->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // } floatVal += 1; diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp index 4b4f4ff1b..6e8075e45 100644 --- a/src/tests/testCylinder.cpp +++ b/src/tests/testCylinder.cpp @@ -47,7 +47,6 @@ void cylinderFunction(Canvas& can) { // } // testCylinder->changeRadiusBy(delta); // if (rotation*45 >= 360) { - // testCylinder->displayOutlineEdges(boolean); // boolean = !boolean; // rotation = 0; // } diff --git a/src/tests/testDiorama.cpp b/src/tests/testDiorama.cpp index b66dbd515..01dffe79b 100644 --- a/src/tests/testDiorama.cpp +++ b/src/tests/testDiorama.cpp @@ -11,31 +11,24 @@ using namespace tsgl; void dioramaFunction(Canvas& can) { Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); - blankCanvas->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(blankCanvas); Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - emptyDioramaLeft->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaLeft); Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - emptyDioramaRight->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaRight); Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - emptyDioramaTop->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaTop); Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - emptyDioramaBottom->setEdgeColor(ColorFloat(0.1,0.1,0.1,1)); // can.add(emptyDioramaBottom); Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); - trunk->displayOutlineEdges(false); // can.add(trunk); Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); // can.add(leaves); Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); - trunkFlat->displayOutlineEdges(false); // can.add(trunkFlat); Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 8b02e5500..a8c2ac7d8 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -67,7 +67,6 @@ void ellipsoidFunction(Canvas& can) { // } // testEllipsoid->changeZRadiusBy(delta); // if (rotation*45 >= 360) { - // testEllipsoid->displayOutlineEdges(boolean); // boolean = !boolean; // rotation = 0; // } diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp index 8fd7bdee9..04e95382f 100644 --- a/src/tests/testMergeSort.cpp +++ b/src/tests/testMergeSort.cpp @@ -118,7 +118,6 @@ void mergeSortFunction(Canvas& can, int threads, int size) { for (int i = 0; i < size; i++) { numbers[i] = saferand(1,can.getWindowHeight()); rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); - rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); } diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index aa17fcf40..4ce152783 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -49,7 +49,6 @@ void prismFunction(Canvas& can) { // } // testPrism->changeRadiusBy(delta); // if (rotation*45 >= 360) { - // testPrism->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // rotation = 0; // } if (rotation*45 >= 360) { diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp index 6e8bfb499..756ef63ab 100644 --- a/src/tests/testRectangle.cpp +++ b/src/tests/testRectangle.cpp @@ -36,12 +36,10 @@ void rectangleFunction(Canvas& can) { // rectangle->setHeight(sin(floatVal/90) *100 + 200); // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // rectangle->changeWidthBy(delta); // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { // delta *= -1; - // // rectangle->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // rectangle->changeHeightBy(delta); // if (delta > 0) { diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index 85d820dbd..06514d9ca 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -35,7 +35,6 @@ void rpFunction(Canvas& can) { // rp->setRadius(sin(floatVal/90)*100 + 300); if (rp->getRadius() > 300 || rp->getRadius() < 100) { delta *= -1; - // rp->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); } rp->changeRadiusBy(delta); if (delta > 0) { diff --git a/src/tests/testShakerSort.cpp b/src/tests/testShakerSort.cpp index f25ef31d3..bef6a0f43 100644 --- a/src/tests/testShakerSort.cpp +++ b/src/tests/testShakerSort.cpp @@ -50,7 +50,6 @@ void shakerSortFunction(Canvas& can) { for (int i = 0; i < SIZE; i++) { rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, saferand(1,can.getWindowHeight()*.9), 0, 0, 0, RED); numbers[i] = rectangles[i]->getHeight(); - rectangles[i]->displayOutlineEdges(false); can.add(rectangles[i]); } can.setBackgroundColor(GRAY); diff --git a/src/tests/testSolarSystem.cpp b/src/tests/testSolarSystem.cpp index 3f4dd6551..c35dc459f 100644 --- a/src/tests/testSolarSystem.cpp +++ b/src/tests/testSolarSystem.cpp @@ -21,8 +21,6 @@ void ssFunction(Canvas& can) { Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); - saturnRings->displayOutlineEdges(false); - mercury->setRotationPoint(0,0,0); venus->setRotationPoint(0,0,0); earth->setRotationPoint(0,0,0); diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index da8ee2aba..45768119a 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -40,7 +40,6 @@ void sphereFunction(Canvas& can) { // } // testSphere->changeRadiusBy(delta); // if (rotation*45 >= 360) { - // testSphere->displayOutlineEdges(boolean); // boolean = !boolean; // rotation = 0; // } diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 1b7d3fa3a..9c1b8e0e2 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -35,7 +35,6 @@ void squareFunction(Canvas& can) { // square->setSideLength(sin(floatVal/90) * 100 + 300); // if (square->getSideLength() > 300 || square->getSideLength() < 100) { // delta *= -1; - // // square->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); // } // square->changeSideLengthBy(delta); // if (delta > 0) { diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 601a0290c..41cd91165 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -30,7 +30,6 @@ void starFunction(Canvas& c) { // s1->setRadius(sin(floatVal/90) * 100 + 300); if (s1->getRadius() > 300 || s1->getRadius() < 100) { delta *= -1; - // s1->setEdgeColor(ColorFloat(randfloat(), randfloat(), randfloat(), 1)); } s1->changeRadiusBy(delta); if (delta > 0) { diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp index a939f922b..d02b870a8 100644 --- a/src/tests/testTriangle.cpp +++ b/src/tests/testTriangle.cpp @@ -38,7 +38,6 @@ void triangleFunction(Canvas& can) { triangle->setColor(RED); if (floatVal > 400) { floatVal = 0; - triangle->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); } } floatVal += 1; diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp index 62ca425bc..248717e6b 100644 --- a/src/tests/testTriangleStrip.cpp +++ b/src/tests/testTriangleStrip.cpp @@ -41,7 +41,6 @@ void triangleStripFunction(Canvas& can) { // ts->setColor(RED); // if (floatVal > 400) { // floatVal = 0; - // ts->setEdgeColor(ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1)); // } // } floatVal += 1; From 520005b425a81db7cde8a009d18b79e2ff9639c4 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 24 Jun 2020 16:54:54 -0400 Subject: [PATCH 040/105] Shaders now don't require filepath. New text bug --- assets/shaders/shape.fs | 3 - assets/shaders/texture_simple.fs | 1 - src/TSGL/Canvas.cpp | 116 +++++++++++++++++++------------ src/TSGL/Text.cpp | 7 +- src/TSGL/Text.h | 1 + src/TSGL/shader_s.h | 68 ++++-------------- src/tests/testText.cpp | 16 +++-- 7 files changed, 102 insertions(+), 110 deletions(-) diff --git a/assets/shaders/shape.fs b/assets/shaders/shape.fs index 957caa68c..d435a46e9 100644 --- a/assets/shaders/shape.fs +++ b/assets/shaders/shape.fs @@ -3,9 +3,6 @@ out vec4 FragColor; in vec4 color; -// texture samplers -// uniform sampler2D texture1; - void main() { FragColor = color; diff --git a/assets/shaders/texture_simple.fs b/assets/shaders/texture_simple.fs index 44224d03a..ce447ac3e 100644 --- a/assets/shaders/texture_simple.fs +++ b/assets/shaders/texture_simple.fs @@ -3,7 +3,6 @@ out vec4 FragColor; in vec2 TexCoords; -// texture sampler uniform sampler2D texture1; void main() diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 7cb5ea258..63b60aacc 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -11,49 +11,73 @@ namespace tsgl { // Shader sources -// static const GLchar* vertexSource = -// "#version 150 core\n" -// "in vec3 position;" -// "in vec4 color;" -// "out vec4 Color;" -// "uniform mat4 model;" -// "uniform mat4 view;" -// "uniform mat4 proj;" -// "void main() {" -// " Color = color;" -// " gl_Position = proj * view * model * vec4(position, 1.0);" -// "}"; -// static const GLchar* fragmentSource = -// "#version 150\n" -// "in vec4 Color;" -// "out vec4 outColor;" -// "void main() {" -// " outColor = vec4(Color);" -// "}"; -// static const GLchar* textureVertexSource = -// "#version 150 core\n" -// "in vec3 position;" -// "in vec4 color;" -// "in vec2 texcoord;" -// "out vec4 Color;" -// "out vec2 Texcoord;" -// "uniform mat4 model;" -// "uniform mat4 view;" -// "uniform mat4 proj;" -// "void main() {" -// " Texcoord = texcoord;" -// " Color = color;" -// " gl_Position = proj * view * model * vec4(position, 1.0);" -// "}"; -// static const GLchar* textureFragmentSource = -// "#version 150\n" -// "in vec4 Color;" -// "in vec2 Texcoord;" -// "out vec4 outColor;" -// "uniform sampler2D tex;" -// "void main() {" -// " outColor = texture(tex, Texcoord) * vec4(Color);" -// "}"; + +static const GLchar* shapeVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec4 aColor;" + "out vec4 color;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * vec4(aPos, 1.0);" + "color = aColor;" + "}"; + +static const GLchar* shapeFragmentShader = + "#version 330 core\n" + "out vec4 FragColor;" + "in vec4 color;" + "void main() {" + "FragColor = color;" + "}"; + +static const GLchar* textVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec2 aTexCoord;" + "out vec2 TexCoords;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * vec4(aPos, 1.0);" + "TexCoords = vec2(aTexCoord.x, aTexCoord.y);" + "}"; + +static const GLchar* textFragmentShader = + "#version 330 core\n" + "in vec2 TexCoords;" + "out vec4 FragColor;" + "uniform sampler2D text;" + "uniform vec4 textColor;" + "void main() {" + "vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);" + "FragColor = textColor * sampled;" + "}"; + +static const GLchar* imageVertexShader = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;" + "layout (location = 1) in vec2 aTexCoord;" + "out vec2 TexCoords;" + "uniform mat4 projection;" + "uniform mat4 view;" + "uniform mat4 model;" + "void main() {" + "gl_Position = projection * view * model * vec4(aPos, 1.0);" + "TexCoords = vec2(aTexCoord.x, aTexCoord.y);" + "}"; + +static const GLchar* imageFragmentShader = + "#version 330 core\n" + "out vec4 FragColor;" + "in vec2 TexCoords;" + "uniform sampler2D texture1;" + "void main() {" + "FragColor = texture(texture1, TexCoords);" + "}"; int Canvas::drawBuffer = GL_FRONT_LEFT; bool Canvas::glfwIsReady = false; @@ -2259,21 +2283,21 @@ void Canvas::initGlew() { exit(EXIT_FAILURE); } - textShader = new Shader("./assets/shaders/text.vs", "./assets/shaders/text.fs"); + textShader = new Shader(textVertexShader, textFragmentShader); // textShader->use(); // glUniformMatrix4fv(glGetUniformLocation(textShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // unsigned int viewLoc = glGetUniformLocation(textShader->ID, "view"); // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); - shapeShader = new Shader("./assets/shaders/shape.vs", "./assets/shaders/shape.fs"); + shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); // shapeShader->use(); // glUniformMatrix4fv(glGetUniformLocation(shapeShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // viewLoc = glGetUniformLocation(shapeShader->ID, "view"); // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); - imageShader = new Shader("./assets/shaders/texture_simple.vs", "./assets/shaders/texture_simple.fs"); + imageShader = new Shader(imageVertexShader, imageFragmentShader); // imageShader->use(); // glUniformMatrix4fv(glGetUniformLocation(imageShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 2e9b90b11..839545986 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -40,6 +40,8 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); + FT_Select_Charmap(face , FT_ENCODING_UNICODE); + populateCharacters(); vertices = new float[30]; // Allocate the vertices @@ -198,6 +200,8 @@ void Text::setFont(std::string filename) { // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); + FT_Select_Charmap(face , FT_ENCODING_UNICODE); + populateCharacters(); init = true; attribMutex.unlock(); @@ -229,7 +233,8 @@ void Text::populateCharacters() { for (int i = 0; i < myString.size(); i++) { // Load character glyph - if (FT_Load_Char(face, myString[i], FT_LOAD_RENDER)) + unsigned long index = FT_Get_Char_Index(face, myString[i]); + if (FT_Load_Glyph(face, index, FT_LOAD_RENDER)) { std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; continue; diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index eaac8d3f8..f53f2480c 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -11,6 +11,7 @@ #include #include FT_FREETYPE_H #include FT_BITMAP_H +#include FT_GLYPH_H // #include "TextureHandler.h" namespace tsgl { diff --git a/src/TSGL/shader_s.h b/src/TSGL/shader_s.h index 5d3241d5f..97631e3de 100644 --- a/src/TSGL/shader_s.h +++ b/src/TSGL/shader_s.h @@ -15,76 +15,34 @@ class Shader unsigned int ID; // constructor generates the shader on the fly // ------------------------------------------------------------------------ - Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) + Shader(const char* vertexShader, const char* fragmentShader, const char* geometryShader = nullptr) { - // 1. retrieve the vertex/fragment source code from filePath - std::string vertexCode; - std::string fragmentCode; - std::string geometryCode; - std::ifstream vShaderFile; - std::ifstream fShaderFile; - std::ifstream gShaderFile; - // ensure ifstream objects can throw exceptions: - vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); - fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); - gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); - try - { - GLenum err = glewInit(); - if (err != GLEW_OK) - exit(1); // or handle the error in a nicer way - if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. - exit(1); // or handle the error in a nicer way - // open files - vShaderFile.open(vertexPath); - fShaderFile.open(fragmentPath); - std::stringstream vShaderStream, fShaderStream; - // read file's buffer contents into streams - vShaderStream << vShaderFile.rdbuf(); - fShaderStream << fShaderFile.rdbuf(); - // close file handlers - vShaderFile.close(); - fShaderFile.close(); - // convert stream into string - vertexCode = vShaderStream.str(); - fragmentCode = fShaderStream.str(); - // if geometry shader path is present, also load a geometry shader - if(geometryPath != nullptr) - { - gShaderFile.open(geometryPath); - std::stringstream gShaderStream; - gShaderStream << gShaderFile.rdbuf(); - gShaderFile.close(); - geometryCode = gShaderStream.str(); - } - } - catch (std::ifstream::failure& e) - { - std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; - } - const char* vShaderCode = vertexCode.c_str(); - const char * fShaderCode = fragmentCode.c_str(); + + GLenum err = glewInit(); + if (err != GLEW_OK) + exit(1); // or handle the error in a nicer way + if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. + exit(1); // or handle the error in a nicer way // 2. compile shaders unsigned int vertex, fragment; // vertex shader vertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex, 1, &vShaderCode, NULL); + glShaderSource(vertex, 1, &vertexShader, NULL); glCompileShader(vertex); checkCompileErrors(vertex, "VERTEX"); // fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment, 1, &fShaderCode, NULL); + glShaderSource(fragment, 1, &fragmentShader, NULL); glCompileShader(fragment); checkCompileErrors(fragment, "FRAGMENT"); // if geometry shader is given, compile geometry shader unsigned int geometry; - if(geometryPath != nullptr) + if(geometryShader != nullptr) { - const char * gShaderCode = geometryCode.c_str(); geometry = glCreateShader(GL_GEOMETRY_SHADER); - glShaderSource(geometry, 1, &gShaderCode, NULL); + glShaderSource(geometry, 1, &geometryShader, NULL); glCompileShader(geometry); checkCompileErrors(geometry, "GEOMETRY"); } @@ -92,14 +50,14 @@ class Shader ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); - if(geometryPath != nullptr) + if(geometryShader != nullptr) glAttachShader(ID, geometry); glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM"); // delete the shaders as they're linked into our program now and no longer necessery glDeleteShader(vertex); glDeleteShader(fragment); - if(geometryPath != nullptr) + if(geometryShader != nullptr) glDeleteShader(geometry); } diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index 6709a174b..f164c9fe3 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -25,10 +25,18 @@ void textFunction(Canvas& can, std::string font) { // 32, BLUE); // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * text = new Text(0,0,0,"Blergh", font, 100, 0,0,0, YELLOW); - can.add(text); - Rectangle * rec = new Rectangle(0,0,0,360,62,0,0,0, ColorFloat(1,1,1,0.2)); - can.add(rec); + Text * text = new Text(0,0,0,"C[i] = B[i] + A[i]", font, 100, 0,0,0, YELLOW); + // can.add(text); + // Rectangle * rec = new Rectangle(0,0,0,360,62,0,0,0, ColorFloat(1,1,1,0.2)); + // can.add(rec); + Text * lowercase = new Text(0,100,0,"abcdefghijklmnopqrstuvwxyz", font, 25, 0,0,0,WHITE); + can.add(lowercase); + Text * uppercase = new Text(0,50,0,"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 25, 0,0,0,WHITE); + can.add(uppercase); + Text * random = new Text(0,0,0,"!@#$%^&*()_-+=~`", font, 25, 0,0,0,WHITE); + can.add(random); + Text * random2 = new Text(0,-50,0,"{[ }] |\\';:<>,./?", font, 25, 0,0,0,WHITE); + can.add(random2); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { // text->setText("Glorgaborg"); From 4d5f36bdf99b042574a56400728773950e13ed7a Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 26 Jun 2020 09:52:25 -0400 Subject: [PATCH 041/105] Unicode is broken. Committing to test versions --- src/TSGL/Text.cpp | 62 +++++++++++++++----------- src/TSGL/Text.h | 11 +++-- src/tests/DiningPhilosophers/Table.cpp | 28 ++++++------ src/tests/DiningPhilosophers/Table.h | 2 +- src/tests/testStar.cpp | 1 - src/tests/testText.cpp | 34 +++++++------- 6 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 839545986..9aa3942f9 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -18,7 +18,7 @@ namespace tsgl { * \param color A reference to the ColorFloat to use. * \return A new Text instance with the specified string, position, and color. */ -Text::Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color) +Text::Text(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color) : Drawable(x,y,z,yaw,pitch,roll) { shaderType = TEXT_SHADER_TYPE; myString = text; @@ -37,11 +37,12 @@ Text::Text(float x, float y, float z, std::string text, std::string fontFilename if (FT_New_Face(ft, fontFilename.c_str(), 0, &face)) TsglErr("ERROR::FREETYPE: Failed to load font"); + // if(FT_Select_Charmap(face , ft_encoding_unicode)) + // TsglErr("ERROR::FREETYPE: Charmap selection"); + // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - FT_Select_Charmap(face , FT_ENCODING_UNICODE); - populateCharacters(); vertices = new float[30]; // Allocate the vertices @@ -80,9 +81,10 @@ void Text::draw(Shader * shader) { float mouseX = -myWidth / 2; float mouseY = -myHeight / 2; - std::string::const_iterator c; - for (c = myString.begin(); c != myString.end(); c++) { - Character ch = Characters[*c]; + const wchar_t* wideText = myString.c_str(); + // std::wstring::const_iterator c; + for (unsigned int i = 0; i < myString.size(); i++) { + Character ch = Characters[wideText[i]]; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -141,10 +143,10 @@ void Text::draw(Shader * shader) { * \param text The text to change myString to. * \warning The center of the text will not change despite any differences in rendered string length. */ -void Text::setText(std::string text) { +void Text::setText(std::wstring text) { attribMutex.lock(); init = false; - std::string::const_iterator c; + std::wstring::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } @@ -162,7 +164,7 @@ void Text::setText(std::string text) { */ void Text::setFontSize(unsigned int fontsize) { attribMutex.lock(); - std::string::const_iterator c; + std::wstring::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } @@ -186,7 +188,7 @@ void Text::setFontSize(unsigned int fontsize) { void Text::setFont(std::string filename) { attribMutex.lock(); init = false; - std::string::const_iterator c; + std::wstring::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } @@ -195,13 +197,13 @@ void Text::setFont(std::string filename) { // load font as face if (FT_New_Face(ft, myFont.c_str(), 0, &face)) - std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; + TsglErr("ERROR::FREETYPE: Failed to load font"); + + FT_Select_Charmap(face , ft_encoding_unicode); // set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, myFontSize); - FT_Select_Charmap(face , FT_ENCODING_UNICODE); - populateCharacters(); init = true; attribMutex.unlock(); @@ -219,41 +221,47 @@ void Text::setColor(const ColorFloat& color) { } /*! - * \brief Private helper method for calculating Text dimensions. + * \brief Private helper method for populating Characters with characters based on myString * \details This function assigns values to myWidth and myHeight based on * the glyphs loaded based on myFontSize, myFont, and myString. */ void Text::populateCharacters() { - // note: this will leak memory if you don't free the bitmaps within first. see most mutators. - Characters.clear(); + const wchar_t* wideChar = myString.c_str(); + Characters.clear(); // note: this will leak memory if you don't free the bitmaps within first. see most mutators. myWidth = 0; myHeight = 0; FT_Bitmap * ftbmps = new FT_Bitmap[myString.size()]; - for (int i = 0; i < myString.size(); i++) { + // if(FT_Select_Charmap(face , ft_encoding_unicode)) + // TsglErr("ERROR::FREETYPE: Charmap selection"); + + FT_GlyphSlot glyph = face->glyph; + FT_UInt index; + + for (unsigned int i = 0; i < myString.size(); i++) { // Load character glyph - unsigned long index = FT_Get_Char_Index(face, myString[i]); + index = FT_Get_Char_Index(face, wideChar[i]); if (FT_Load_Glyph(face, index, FT_LOAD_RENDER)) { - std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; + TsglErr("ERROR::FREETYTPE: Failed to load Glyph"); continue; } FT_Bitmap_Init(&ftbmps[i]); - FT_Bitmap_Copy(ft, &face->glyph->bitmap, &ftbmps[i]); + FT_Bitmap_Copy(ft, &glyph->bitmap, &ftbmps[i]); Character character = { ftbmps[i], - glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), - face->glyph->advance.x + glm::ivec2(glyph->bitmap_left, glyph->bitmap_top), + glyph->advance.x }; - Characters.insert(std::pair(myString[i], character)); + Characters.insert(std::pair(wideChar[i], character)); - myWidth += face->glyph->advance.x >> 6; - if (face->glyph->bitmap.rows > myHeight) - myHeight = face->glyph->bitmap.rows; + myWidth += glyph->advance.x >> 6; + if (glyph->bitmap.rows > myHeight) + myHeight = glyph->bitmap.rows; } delete [] ftbmps; @@ -261,7 +269,7 @@ void Text::populateCharacters() { Text::~Text() { // destroy FreeType once we're finished - std::string::const_iterator c; + std::wstring::const_iterator c; for (c = myString.begin(); c != myString.end(); c++) { FT_Bitmap_Done(ft, &Characters[*c].Bitmap); } diff --git a/src/TSGL/Text.h b/src/TSGL/Text.h index f53f2480c..a30c6494a 100755 --- a/src/TSGL/Text.h +++ b/src/TSGL/Text.h @@ -11,7 +11,6 @@ #include #include FT_FREETYPE_H #include FT_BITMAP_H -#include FT_GLYPH_H // #include "TextureHandler.h" namespace tsgl { @@ -24,7 +23,7 @@ namespace tsgl { */ class Text : public Drawable { private: - std::string myString; + std::wstring myString; unsigned int myFontSize; std::string myFont; ColorFloat myColor; @@ -41,15 +40,15 @@ class Text : public Drawable { unsigned int Advance; // Horizontal offset to advance to next glyph }; - std::map Characters; + std::map Characters; void populateCharacters(); public: - Text(float x, float y, float z, std::string text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); + Text(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); virtual void draw(Shader * shader); - virtual void setText(std::string text); + virtual void setText(std::wstring text); virtual void setFontSize(unsigned int fontsize); @@ -57,7 +56,7 @@ class Text : public Drawable { virtual void setColor(const ColorFloat& color); - std::string getText() { return myString; } + std::wstring getText() { return myString; } unsigned int getFontSize() { return myFontSize; } diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp index 79e75931f..9bd781750 100644 --- a/src/tests/DiningPhilosophers/Table.cpp +++ b/src/tests/DiningPhilosophers/Table.cpp @@ -30,19 +30,19 @@ Table::Table(Canvas& can, int p, PhilMethod m) { myMethod = m; switch(myMethod) { case forfeitWhenBlocked: - methodString = "forfeit when blocked"; + methodString = L"forfeit when blocked"; break; case waitWhenBlocked: - methodString = "wait when blocked"; + methodString = L"wait when blocked"; break; case nFrameRelease: - methodString = "release on nth frame"; + methodString = L"release on nth frame"; break; case resourceHierarchy: - methodString = "hierarchical resources"; + methodString = L"hierarchical resources"; break; case oddEven: - methodString = "odd-even check"; + methodString = L"odd-even check"; break; default: break; @@ -53,31 +53,31 @@ Table::Table(Canvas& can, int p, PhilMethod m) { myCan2->setBackgroundColor(GRAY); legendTexts = new Text*[9](); - legendTexts[0] = new Text(-134,128,0,"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); + legendTexts[0] = new Text(-134,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); legendTexts[0]->changeXBy(legendTexts[0]->getWidth() / 2); myCan2->add(legendTexts[0]); - legendTexts[1] = new Text(-118,96,0,"\"" + methodString + "\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[1] = new Text(-118,96,0,L"\"" + methodString + L"\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); legendTexts[1]->changeXBy(legendTexts[1]->getWidth() / 2); myCan2->add(legendTexts[1]); - legendTexts[2] = new Text(-134,64,0,"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[2] = new Text(-134,64,0,L"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); legendTexts[2]->changeXBy(legendTexts[2]->getWidth() / 2); myCan2->add(legendTexts[2]); - legendTexts[3] = new Text(-118,32,0,"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); + legendTexts[3] = new Text(-118,32,0,L"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); legendTexts[3]->changeXBy(legendTexts[3]->getWidth() / 2); myCan2->add(legendTexts[3]); - legendTexts[4] = new Text(-118,0,0,"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); + legendTexts[4] = new Text(-118,0,0,L"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); legendTexts[4]->changeXBy(legendTexts[4]->getWidth() / 2); myCan2->add(legendTexts[4]); - legendTexts[5] = new Text(-118,-32,0,"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); + legendTexts[5] = new Text(-118,-32,0,L"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); legendTexts[5]->changeXBy(legendTexts[5]->getWidth() / 2); myCan2->add(legendTexts[5]); - legendTexts[6] = new Text(-118,-64,0,"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); + legendTexts[6] = new Text(-118,-64,0,L"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); legendTexts[6]->changeXBy(legendTexts[6]->getWidth() / 2); myCan2->add(legendTexts[6]); - legendTexts[7] = new Text(-118,-96,0,"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); + legendTexts[7] = new Text(-118,-96,0,L"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); legendTexts[7]->changeXBy(legendTexts[7]->getWidth() / 2); myCan2->add(legendTexts[7]); - legendTexts[8] = new Text(-118,-121,0,"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); + legendTexts[8] = new Text(-118,-121,0,L"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); legendTexts[8]->changeXBy(legendTexts[8]->getWidth() / 2); myCan2->add(legendTexts[8]); diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h index ed961d285..c6ec53f5e 100644 --- a/src/tests/DiningPhilosophers/Table.h +++ b/src/tests/DiningPhilosophers/Table.h @@ -24,7 +24,7 @@ class Table { private: int numPhils; PhilMethod myMethod; - std::string methodString; + std::wstring methodString; Canvas *myCan, *myCan2; Philosopher *phils; Fork *forks; diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp index 41cd91165..14afe96c6 100644 --- a/src/tests/testStar.cpp +++ b/src/tests/testStar.cpp @@ -42,7 +42,6 @@ void starFunction(Canvas& c) { delete[] colors; // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. - return 0; } int main(int argc, char* argv[]) { diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index f164c9fe3..0721c26bd 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -25,25 +25,25 @@ void textFunction(Canvas& can, std::string font) { // 32, BLUE); // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * text = new Text(0,0,0,"C[i] = B[i] + A[i]", font, 100, 0,0,0, YELLOW); + // Text * text = new Text(0,0,0,L"C[i] = B[i] + A[i]", font, 100, 0,0,0, YELLOW); // can.add(text); // Rectangle * rec = new Rectangle(0,0,0,360,62,0,0,0, ColorFloat(1,1,1,0.2)); // can.add(rec); - Text * lowercase = new Text(0,100,0,"abcdefghijklmnopqrstuvwxyz", font, 25, 0,0,0,WHITE); - can.add(lowercase); - Text * uppercase = new Text(0,50,0,"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 25, 0,0,0,WHITE); - can.add(uppercase); - Text * random = new Text(0,0,0,"!@#$%^&*()_-+=~`", font, 25, 0,0,0,WHITE); + // Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 25, 0,0,0,WHITE); + // can.add(lowercase); + // Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 25, 0,0,0,WHITE); + // can.add(uppercase); + Text * random = new Text(0,0,0,L"bad*?<>~^letters!=", font, 48, 0,0,0,WHITE); can.add(random); - Text * random2 = new Text(0,-50,0,"{[ }] |\\';:<>,./?", font, 25, 0,0,0,WHITE); - can.add(random2); + // Text * random2 = new Text(0,-50,0,L"{[ }] |\\';:<>,./?", font, 25, 0,0,0,WHITE); + // can.add(random2); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { - // text->setText("Glorgaborg"); - // text->setColor(RED); - // text->setFont("./assets/freefont/FreeSerifItalic.ttf"); - text->setFontSize(50); - }); + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { + // // text->setText("Glorgaborg"); + // // text->setColor(RED); + // // text->setFont("./assets/freefont/FreeSerifItalic.ttf"); + // text->setFontSize(50); + // }); float rotation = 0.0f; while(can.isOpen()) { @@ -56,7 +56,11 @@ void textFunction(Canvas& can, std::string font) { // text->setRoll(rotation*45); rotation+=0.01; } - delete text; + // delete text; + // delete lowercase; + // delete uppercase; + delete random; + // delete random2; } From 42b017b5185096a5be9f8a1daefcddb08e51390b Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 30 Jun 2020 12:22:04 -0400 Subject: [PATCH 042/105] Outline functionality added to Shape --- src/TSGL/Arrow.cpp | 34 +++++++++++ src/TSGL/Canvas.cpp | 3 +- src/TSGL/Circle.cpp | 4 ++ src/TSGL/ConcavePolygon.cpp | 53 ++++++++++++------ src/TSGL/Cone.cpp | 8 ++- src/TSGL/ConvexPolygon.cpp | 14 ++++- src/TSGL/Cube.cpp | 62 ++++++++++++++++++++- src/TSGL/Cuboid.cpp | 60 ++++++++++++++++++++ src/TSGL/Cylinder.cpp | 2 + src/TSGL/Ellipse.cpp | 4 ++ src/TSGL/Ellipsoid.cpp | 70 +++++++++++++++++++---- src/TSGL/Polyline.cpp | 96 +++++++++++++++++++++++++++++--- src/TSGL/Polyline.h | 13 ++++- src/TSGL/Prism.cpp | 34 +++++++++++ src/TSGL/Pyramid.cpp | 26 +++++++++ src/TSGL/Rectangle.cpp | 10 ++++ src/TSGL/RegularPolygon.cpp | 2 + src/TSGL/Shape.cpp | 57 ++++++++++++++++++- src/TSGL/Shape.h | 31 ++++++++++- src/TSGL/Sphere.cpp | 70 +++++++++++++++++++---- src/TSGL/Square.cpp | 10 ++++ src/TSGL/Star.cpp | 16 ++++-- src/TSGL/Text.cpp | 10 ++-- src/TSGL/Triangle.cpp | 6 ++ src/TSGL/TriangleStrip.cpp | 8 +++ src/tests/testArrows.cpp | 10 +++- src/tests/testCircle.cpp | 2 +- src/tests/testClock.cpp | 1 + src/tests/testCone.cpp | 5 +- src/tests/testConvexPolygon.cpp | 2 +- src/tests/testCube.cpp | 24 +++++--- src/tests/testEllipse.cpp | 2 +- src/tests/testEllipsoid.cpp | 19 +++++-- src/tests/testRegularPolygon.cpp | 2 +- src/tests/testSphere.cpp | 7 ++- src/tests/testSquare.cpp | 5 +- src/tests/testText.cpp | 14 ++--- src/tests/testTriangle.cpp | 5 +- src/tests/testTriangleStrip.cpp | 3 +- 39 files changed, 703 insertions(+), 101 deletions(-) diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index eac36bc25..a2229ddca 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -27,6 +27,7 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw myYScale = width; myWidth = width; isDoubleArrow = doubleArrow; + isOutlined = false; attribMutex.unlock(); addVertex(-0.4, 0.4, 0, color); addVertex(-0.4, 1, 0, color); @@ -34,15 +35,30 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw addVertex(-0.4, -1, 0, color); addVertex(-0.4, -0.4, 0, color); + addOutlineVertex(-0.4, 0.4, 0, GRAY); + addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.5, 0, 0, GRAY); + addOutlineVertex(-0.4, -1, 0, GRAY); + addOutlineVertex(-0.4, -0.4, 0, GRAY); + if( isDoubleArrow ) { addVertex(0.4, -0.4, 0, color); addVertex(0.4, -1, 0, color); addVertex(0.5, 0, 0, color); addVertex(0.4, 1, 0, color); addVertex(0.4, 0.4, 0, color); + + addOutlineVertex(0.4, -0.4, 0, GRAY); + addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.5, 0, 0, GRAY); + addOutlineVertex(0.4, 1, 0, GRAY); + addOutlineVertex(0.4, 0.4, 0, GRAY); } else { addVertex(0.5, -.4, 0, color); addVertex(0.5, .4, 0, color); + + addOutlineVertex(0.5, -.4, 0, GRAY); + addOutlineVertex(0.5, .4, 0, GRAY); } } @@ -71,6 +87,7 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw myYScale = width; myWidth = width; isDoubleArrow = doubleArrow; + isOutlined = false; attribMutex.unlock(); addVertex(-0.4, 0.4, 0, color[0]); addVertex(-0.4, 1, 0, color[0]); @@ -78,15 +95,30 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw addVertex(-0.4, -1, 0, color[0]); addVertex(-0.4, -0.4, 0, color[0]); + addOutlineVertex(-0.4, 0.4, 0, GRAY); + addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.5, 0, 0, GRAY); + addOutlineVertex(-0.4, -1, 0, GRAY); + addOutlineVertex(-0.4, -0.4, 0, GRAY); + if( isDoubleArrow ) { addVertex(0.4, -0.4, 0, color[1]); addVertex(0.4, -1, 0, color[1]); addVertex(0.5, 0, 0, color[1]); addVertex(0.4, 1, 0, color[1]); addVertex(0.4, 0.4, 0, color[1]); + + addOutlineVertex(0.4, -0.4, 0, GRAY); + addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.5, 0, 0, GRAY); + addOutlineVertex(0.4, 1, 0, GRAY); + addOutlineVertex(0.4, 0.4, 0, GRAY); } else { addVertex(0.5, -0.4, 0, color[1]); addVertex(0.5, 0.4, 0, color[1]); + + addOutlineVertex(0.5, -.4, 0, GRAY); + addOutlineVertex(0.5, .4, 0, GRAY); } } @@ -140,6 +172,7 @@ void Arrow::changeWidthBy(GLfloat delta) { * \note Overrides Shape::setColor(ColorFloat c[]). */ void Arrow::setColor(ColorFloat c[]) { + attribMutex.lock(); for(int i = 0; i < 7; i++) { vertices[i*7 + 3] = c[i/5].R; vertices[i*7 + 4] = c[i/5].G; @@ -154,6 +187,7 @@ void Arrow::setColor(ColorFloat c[]) { vertices[i*7 + 6] = c[1].A; } } + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 63b60aacc..3d1c7637d 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -2203,7 +2203,7 @@ void Canvas::initGl() { glEnable(GL_DEPTH_TEST); // Depth Testing glDepthFunc(GL_LEQUAL); glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); + // glCullFace(GL_BACK); glEnable(GL_BLEND); // Enable blending glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Set blending mode to standard alpha blending @@ -2363,7 +2363,6 @@ void Canvas::initWindow() { #endif // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer - // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index b4cd1a4b7..065496a9e 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -23,11 +23,13 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch myXScale = myYScale = myRadius = radius; myZScale = 1; verticesPerColor = (myRadius + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; attribMutex.unlock(); addVertex(0,0,0,color); float delta = 2.0f / (numberOfVertices - 2) * PI; for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } @@ -52,11 +54,13 @@ Circle::Circle(float x, float y, float z, GLfloat radius, float yaw, float pitch myXScale = myYScale = myRadius = radius; myZScale = 1; verticesPerColor = (myRadius + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; attribMutex.unlock(); addVertex(0,0,0,color[0]); float delta = 2.0f / (numberOfVertices - 2) * PI; for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index c2feb15a0..4e1d3128a 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -17,8 +17,10 @@ namespace tsgl { ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } @@ -44,9 +46,13 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; + outlineGeometryType = GL_LINE_LOOP; + numberOfOutlineVertices = numVertices; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], 0, color); + addOutlineVertex(x[i], y[i], 0, GRAY); } } @@ -71,9 +77,13 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numberOfVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; myXScale = myYScale = myZScale = 1; + outlineGeometryType = GL_LINE_LOOP; + numberOfOutlineVertices = numVertices; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], 0, color[i]); + addOutlineVertex(x[i], y[i], 0, GRAY); } } @@ -101,26 +111,33 @@ void ConcavePolygon::draw(Shader * shader) { unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - /* extra stencil buffer stuff, because it's concave */ - glClearStencil(0); - glEnable(GL_STENCIL_TEST); - glDisable(GL_CULL_FACE); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glStencilFunc(GL_NEVER, 0, 1); - glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); - /* end */ + if (isFilled) { + /* extra stencil buffer stuff, because it's concave */ + glClearStencil(0); + glEnable(GL_STENCIL_TEST); + glDisable(GL_CULL_FACE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_NEVER, 0, 1); + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + /* end */ + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); + /* extra stencil buffer stuff, because it's concave */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - /* extra stencil buffer stuff, because it's concave */ - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, 1); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); + glDisable(GL_STENCIL_TEST); + } - glDisable(GL_STENCIL_TEST); + if (isOutlined) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfOutlineVertices * 7, outlineVertices, GL_DYNAMIC_DRAW); + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); + } } } diff --git a/src/TSGL/Cone.cpp b/src/TSGL/Cone.cpp index 69ec9cb1c..2886ca755 100644 --- a/src/TSGL/Cone.cpp +++ b/src/TSGL/Cone.cpp @@ -18,7 +18,9 @@ namespace tsgl { * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c) -: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { } +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices /= 2; +} /*! * \brief Explicitly constructs a new Cone. @@ -36,7 +38,9 @@ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, flo * \return A new Cone with a buffer for storing the specified numbered of vertices. */ Cone::Cone(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) -: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { } +: Pyramid(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices /= 2; +} /*! * \brief Destructor for the Cone. diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index c0137e6fb..8c1933f6a 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -17,8 +17,10 @@ namespace tsgl { ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float yaw, float pitch, float roll) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); } @@ -41,12 +43,15 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], 0, color); + addOutlineVertex(x[i], y[i], 0, GRAY); } } @@ -68,12 +73,15 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, GLfloat x[], GLfloat y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_FAN; - numberOfVertices = numVertices; + outlineGeometryType = GL_LINE_LOOP; + numberOfVertices = numberOfOutlineVertices = numVertices; vertices = new GLfloat[numberOfVertices * 7]; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], 0, color[i]); + addOutlineVertex(x[i], y[i], 0, GRAY); } } diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index bcf9338d3..f58c7157e 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -28,7 +28,10 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myYScale = sideLength; myZScale = sideLength; numberOfVertices = 36; - vertices = new GLfloat[numberOfVertices * 7]; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); @@ -71,6 +74,33 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); } /*! @@ -100,6 +130,9 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch myZScale = sideLength; numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); @@ -142,6 +175,33 @@ Cube::Cube(float x, float y, float z, GLfloat sideLength, float yaw, float pitch addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, -0.5, 0.5, c[5]); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); } /** diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index eb875537b..4667089fc 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -33,6 +33,9 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myZScale = length; numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c); addVertex(-0.5, -0.5, 0.5, c); @@ -75,6 +78,33 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat addVertex(-0.5, -0.5, 0.5, c); addVertex(0.5, 0.5, 0.5, c); addVertex(0.5, -0.5, 0.5, c); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); } /*! @@ -108,6 +138,9 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat myZScale = length; numberOfVertices = 36; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = 24; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); addVertex(-0.5, -0.5, -0.5, c[0]); addVertex(-0.5, -0.5, 0.5, c[1]); @@ -150,6 +183,33 @@ Cuboid::Cuboid(float x, float y, float z, GLfloat width, GLfloat height, GLfloat addVertex(-0.5, -0.5, 0.5, c[1]); addVertex(0.5, 0.5, 0.5, c[6]); addVertex(0.5, -0.5, 0.5, c[5]); + + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + + addOutlineVertex(-0.5, 0.5, 0.5, GRAY); + addOutlineVertex( 0.5, 0.5, 0.5, GRAY); + addOutlineVertex(-0.5, 0.5, -0.5, GRAY); + addOutlineVertex( 0.5, 0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, -0.5, GRAY); + addOutlineVertex( 0.5, -0.5, -0.5, GRAY); + addOutlineVertex(-0.5, -0.5, 0.5, GRAY); + addOutlineVertex( 0.5, -0.5, 0.5, GRAY); } /** diff --git a/src/TSGL/Cylinder.cpp b/src/TSGL/Cylinder.cpp index 6d666b299..c901726a5 100644 --- a/src/TSGL/Cylinder.cpp +++ b/src/TSGL/Cylinder.cpp @@ -19,6 +19,7 @@ namespace tsgl { */ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, float yaw, float pitch, float roll, ColorFloat c) : Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices = numberOfOutlineVertices * 2 / 3; } /*! @@ -38,6 +39,7 @@ Cylinder::Cylinder(float x, float y, float z, GLfloat height, GLfloat radius, fl */ Cylinder::Cylinder(float x, float y, float z, float height, float radius, float yaw, float pitch, float roll, ColorFloat c[]) : Prism(x, y, z, 40, height, radius, yaw, pitch, roll, c) { + numberOfOutlineVertices = numberOfOutlineVertices * 2 / 3; } /*! diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index df3e2f161..fb334b8c3 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -21,11 +21,13 @@ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, fl myYScale = myYRadius = yRadius; myZScale = 1; verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; attribMutex.unlock(); addVertex(0,0,0,color); float delta = 2.0f / (numberOfVertices - 2) * PI; for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } @@ -48,11 +50,13 @@ Ellipse::Ellipse(float x, float y, float z, GLfloat xRadius, GLfloat yRadius, fl myYScale = myYRadius = yRadius; myZScale = 1; verticesPerColor = ((xRadius + yRadius) / 2 + 6) / 8; + numberOfOutlineVertices = numberOfVertices - 1; attribMutex.unlock(); addVertex(0,0,0,color[0]); float delta = 2.0f / (numberOfVertices - 2) * PI; for (int i = 0; i < numberOfVertices - 1; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color[(int) ((float) i / verticesPerColor + 1)]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index bc967451a..190589a55 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -23,17 +23,21 @@ Ellipsoid::Ellipsoid(float x, float y, float z, GLfloat xRadius, GLfloat yRadius TsglDebug("Cannot have an Ellipsoid with any radius less than or equal to 0."); } attribMutex.lock(); - geometryType = GL_TRIANGLE_STRIP; - verticalSections = 36; - horizontalSections = 20; - numberOfVertices = verticalSections*horizontalSections*2 + 1; - vertices = new GLfloat[numberOfVertices * 7]; myXRadius = xRadius; myYRadius = yRadius; myZRadius = zRadius; myXScale = xRadius; myYScale = yRadius; myZScale = zRadius; + verticalSections = 36; + horizontalSections = 20; + geometryType = GL_TRIANGLE_STRIP; + numberOfVertices = verticalSections*horizontalSections*2 + 1; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = verticalSections*horizontalSections*4 + 1; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + isOutlined = false; attribMutex.unlock(); for(float b=0;bID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_LINE_STRIP, 0, numberOfVertices); +} + + /*! + * \brief Adds another vertex to a Polyline. + * \details This function initializes the next vertex in the Polyline and adds it to a Polyline buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Polyline::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { + if (init) { + TsglDebug("Cannot add anymore vertices."); + return; + } + attribMutex.lock(); + vertices[currentVertex] = x; + vertices[currentVertex + 1] = y; + vertices[currentVertex + 2] = z; + vertices[currentVertex + 3] = color.R; + vertices[currentVertex + 4] = color.G; + vertices[currentVertex + 5] = color.B; + vertices[currentVertex + 6] = color.A; + currentVertex += 7; + if (currentVertex == numberOfVertices*7) { + init = true; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Polyline to a new color. + * \param c The new ColorFloat. + */ +void Polyline::setColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c.R; + vertices[i*7 + 4] = c.G; + vertices[i*7 + 5] = c.B; + vertices[i*7 + 6] = c.A; + } + attribMutex.unlock(); +} + +/** + * \brief Sets the Polyline to a new array of colors. + * \param c The new array of ColorFloats. + */ +void Polyline::setColor(ColorFloat c[]) { + for(int i = 0; i < numberOfVertices; i++) { + vertices[i*7 + 3] = c[i].R; + vertices[i*7 + 4] = c[i].G; + vertices[i*7 + 5] = c[i].B; + vertices[i*7 + 6] = c[i].A; + } +} + /*! * \brief Overrides isProcessed() in Drawable.h * \details Overrides Drawable::isProcessed() to include invariant. diff --git a/src/TSGL/Polyline.h b/src/TSGL/Polyline.h index f8729bd64..79684c81f 100755 --- a/src/TSGL/Polyline.h +++ b/src/TSGL/Polyline.h @@ -5,7 +5,7 @@ #ifndef POLYLINE_H_ #define POLYLINE_H_ -#include "Shape.h" // For extending our Shape object +#include "Drawable.h" // For extending our Drawable object namespace tsgl { @@ -18,8 +18,12 @@ namespace tsgl { * \note Calling addVertex() after all vertices have been added will do nothing. * \note Calling Drawable::draw() before all vertices have been added will do nothing. */ -class Polyline : public Shape { +class Polyline : public Drawable { protected: + int numberOfVertices; + int currentVertex = 0; + virtual void addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + Polyline(float x, float y, float z, int numVertices, float yaw, float pitch, float roll); public: @@ -27,6 +31,11 @@ class Polyline : public Shape { Polyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]); + virtual void draw(Shader * shader); + + virtual void setColor(ColorFloat c); + virtual void setColor(ColorFloat c[]); + bool isProcessed(); }; diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index b88afe63e..1654d567d 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -32,6 +32,9 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu geometryType = GL_TRIANGLES; numberOfVertices = mySides * 12; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 6; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c); @@ -50,6 +53,20 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); addVertex(0,-0.5,0, c); } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 * 2 / 3; + } } /*! @@ -82,6 +99,9 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu geometryType = GL_TRIANGLES; numberOfVertices = mySides * 12; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 6; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), c[1]); @@ -100,6 +120,20 @@ Prism::Prism(float x, float y, float z, int sides, GLfloat height, GLfloat radiu addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[3]); addVertex(0,-0.5,0, c[4]); } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), 0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 3 - 14; + + addOutlineVertex(cos(TWOPI * i / mySides), 0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 * 2 / 3; + } } /** diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index 966e6512c..242b46edd 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -36,6 +36,9 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 4; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c); @@ -46,6 +49,16 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r addVertex(0,0.5,0, ColorFloat(c.R*.5,c.G*.5,c.B*.5,c.A)); addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c); } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 2 - 14; + + addOutlineVertex(0, 0.5, 0, GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 / 2; + } } /*! @@ -82,6 +95,9 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r geometryType = GL_TRIANGLES; numberOfVertices = mySides * 6; vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = mySides * 4; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < mySides; i++) { addVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), c[i+1]); @@ -92,6 +108,16 @@ Pyramid::Pyramid(float x, float y, float z, int sides, GLfloat height, GLfloat r addVertex(0,0.5,0, c[0]); addVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), c[(i+1) % mySides + 1]); } + + for (int i = 0; i < mySides; i++) { + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + addOutlineVertex(cos(TWOPI * (i + 1) / mySides), -0.5, sin(TWOPI * (i + 1) / mySides), GRAY); + currentOutlineVertex += numberOfOutlineVertices * 7 / 2 - 14; + + addOutlineVertex(0, 0.5, 0, GRAY); + addOutlineVertex(cos(TWOPI * i / mySides), -0.5, sin(TWOPI * i / mySides), GRAY); + currentOutlineVertex -= numberOfOutlineVertices * 7 / 2; + } } /** diff --git a/src/TSGL/Rectangle.cpp b/src/TSGL/Rectangle.cpp index e82282718..9788c7c07 100644 --- a/src/TSGL/Rectangle.cpp +++ b/src/TSGL/Rectangle.cpp @@ -30,6 +30,11 @@ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, f addVertex(-0.5, -0.5, 0, color); addVertex(0.5, -0.5, 0, color); addVertex(0.5, 0.5, 0, color); + + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); } /*! @@ -60,6 +65,11 @@ Rectangle::Rectangle(float x, float y, float z, GLfloat width, GLfloat height, f addVertex(-0.5, -0.5, 0, color[1]); addVertex(0.5, -0.5, 0, color[2]); addVertex(0.5, 0.5, 0, color[3]); + + addOutlineVertex(-0.5, 0.5, 0, GRAY); + addOutlineVertex(-0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, -0.5, 0, GRAY); + addOutlineVertex(0.5, 0.5, 0, GRAY); } /** diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index 5311e640b..86d9d0b03 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -24,6 +24,7 @@ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int si float delta = 2.0f / sides * PI; for (int i = 0; i < sides; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } @@ -50,6 +51,7 @@ RegularPolygon::RegularPolygon(float x, float y, float z, GLfloat radius, int si float delta = 2.0f / sides * PI; for (int i = 0; i < sides; ++i) { addVertex(cos(i*delta), sin(i*delta), 0, color[i % (mySides - 1)]); + addOutlineVertex(cos(i*delta), sin(i*delta), 0, GRAY); } } diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index d01f4cb6a..63c9d7ff1 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -36,8 +36,15 @@ void Shape::draw(Shader * shader) { unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(geometryType, 0, numberOfVertices); + if (isFilled) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfVertices * 7, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(geometryType, 0, numberOfVertices); + } + + if (isOutlined) { + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfOutlineVertices * 7, outlineVertices, GL_DYNAMIC_DRAW); + glDrawArrays(outlineGeometryType, 0, numberOfOutlineVertices); + } } /*! @@ -70,6 +77,37 @@ void Shape::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) attribMutex.unlock(); } + /*! + * \brief Adds another outline vertex to a Shape. + * \details This function initializes the next vertex in the Shape and adds it to a Shape buffer. + * \param x The x position of the vertex. + * \param y The y position of the vertex. + * \param z The z position of the vertex. + * \param color The reference variable of the color of the vertex. + * \note This function does nothing if the vertex buffer is already full. + * \note A message is given indicating that the vertex buffer is full. + */ +void Shape::addOutlineVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) { + if (outlineInit) { + TsglDebug("Cannot add anymore vertices."); + printf("added enough already tbh\n"); + return; + } + attribMutex.lock(); + outlineVertices[currentOutlineVertex] = x; + outlineVertices[currentOutlineVertex + 1] = y; + outlineVertices[currentOutlineVertex + 2] = z; + outlineVertices[currentOutlineVertex + 3] = color.R; + outlineVertices[currentOutlineVertex + 4] = color.G; + outlineVertices[currentOutlineVertex + 5] = color.B; + outlineVertices[currentOutlineVertex + 6] = color.A; + currentOutlineVertex += 7; + if (currentOutlineVertex == numberOfOutlineVertices*7) { + outlineInit = true; + } + attribMutex.unlock(); +} + /** * \brief Sets the Shape to a new color. * \param c The new ColorFloat. @@ -98,4 +136,19 @@ void Shape::setColor(ColorFloat c[]) { } } +/** + * \brief Sets the Shape's outline to a new color. + * \param c The new ColorFloat. + */ +void Shape::setOutlineColor(ColorFloat c) { + attribMutex.lock(); + for(int i = 0; i < numberOfOutlineVertices; i++) { + outlineVertices[i*7 + 3] = c.R; + outlineVertices[i*7 + 4] = c.G; + outlineVertices[i*7 + 5] = c.B; + outlineVertices[i*7 + 6] = c.A; + } + attribMutex.unlock(); +} + } \ No newline at end of file diff --git a/src/TSGL/Shape.h b/src/TSGL/Shape.h index b10fb9052..5bf140df0 100755 --- a/src/TSGL/Shape.h +++ b/src/TSGL/Shape.h @@ -31,7 +31,17 @@ class Shape : public Drawable { int numberOfVertices; int currentVertex = 0; GLenum geometryType; - virtual void addVertex(float x, float y, float z, const ColorFloat &color = WHITE); + virtual void addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + bool isFilled = true; + + int numberOfOutlineVertices; + int currentOutlineVertex = 0; + GLenum outlineGeometryType; + virtual void addOutlineVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color = WHITE); + GLfloat * outlineVertices; + bool isOutlined = true; + + bool outlineInit = false; public: Shape(float x, float y, float z, float yaw, float pitch, float roll); @@ -40,6 +50,25 @@ class Shape : public Drawable { virtual void setColor(ColorFloat c); virtual void setColor(ColorFloat c[]); + virtual void setOutlineColor(ColorFloat c); + + virtual bool isProcessed() { return outlineInit && init; } + + /*! \brief Set whether or not the Shape will be filled. + * \details Sets the isFilled instance variable to the value of the parameter. + * \param status Boolean value to which isFilled will be set equivalent. + * \warning Disabling fill on some 3D Shapes, like Cone and Cylinder, can be awkward visually. + */ + virtual void setIsFilled(bool status) { isFilled = status; } + + /*! \brief Set whether or not the Shape will be outlined. + * \details Sets the isOutlined instance variable to the value of the parameter. + * \param status Boolean value to which isOutlined will be set equivalent. + * \warning Disabling outlines on monocolored 3D Shapes can be awkward visually. + */ + virtual void setIsOutlined(bool status) { isOutlined = status; } + + ~Shape() { /* delete [] vertices; */ } }; } diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 289688185..0d6e3ea82 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -22,15 +22,19 @@ Sphere::Sphere(float x, float y, float z, GLfloat radius, float yaw, float pitch TsglDebug("Cannot have a Sphere with radius less than or equal to 0."); } attribMutex.lock(); - geometryType = GL_TRIANGLE_STRIP; - verticalSections = 36; - horizontalSections = 20; - numberOfVertices = verticalSections*horizontalSections*2+1; - vertices = new GLfloat[numberOfVertices * 7]; myRadius = radius; myXScale = radius; myYScale = radius; myZScale = radius; + verticalSections = 36; + horizontalSections = 20; + geometryType = GL_TRIANGLE_STRIP; + numberOfVertices = verticalSections*horizontalSections*2 + 1; + vertices = new GLfloat[numberOfVertices * 7]; + outlineGeometryType = GL_LINES; + numberOfOutlineVertices = verticalSections*horizontalSections*4 + 1; + outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; + isOutlined = false; attribMutex.unlock(); for(float b=0;bglyph; FT_UInt index; diff --git a/src/TSGL/Triangle.cpp b/src/TSGL/Triangle.cpp index 9e1317c13..c7808c7ee 100644 --- a/src/TSGL/Triangle.cpp +++ b/src/TSGL/Triangle.cpp @@ -27,6 +27,9 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color); addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color); addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color); + addOutlineVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, GRAY); + addOutlineVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, GRAY); + addOutlineVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, GRAY); geometryType = GL_TRIANGLES; } @@ -55,6 +58,9 @@ Triangle::Triangle(float x1, float y1, float z1, float x2, float y2, float z2, f addVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, color[0]); addVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, color[1]); addVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, color[2]); + addOutlineVertex(x1 - xAverage, y1 - yAverage, z1 - zAverage, GRAY); + addOutlineVertex(x2 - xAverage, y2 - yAverage, z2 - zAverage, GRAY); + addOutlineVertex(x3 - xAverage, y3 - yAverage, z3 - zAverage, GRAY); geometryType = GL_TRIANGLES; } } diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index 96a5fb3d0..825d733f8 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -21,9 +21,13 @@ namespace tsgl { TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], z[i], color); + addOutlineVertex(x[i], y[i], z[i], GRAY); } } @@ -46,9 +50,13 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[]) : ConvexPolygon(centerX,centerY,centerZ,numVertices,yaw,pitch,roll) { attribMutex.lock(); geometryType = GL_TRIANGLE_STRIP; + outlineGeometryType = GL_LINE_STRIP; + numberOfOutlineVertices = numVertices; + isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { addVertex(x[i], y[i], z[i], color[i]); + addOutlineVertex(x[i], y[i], z[i], GRAY); } } } diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp index 19a45ec88..9d7d4d8b3 100644 --- a/src/tests/testArrows.cpp +++ b/src/tests/testArrows.cpp @@ -7,15 +7,16 @@ using namespace tsgl; void arrowFunction(Canvas& c) { ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1) }; Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); + Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); c.add(doubleArrow); - c.add(arrow2); + c.add(arrow2); // doubleArrow->setCenterX(100); // doubleArrow->setRotationPoint(0,0,0); // doubleArrow->setYaw(45); - doubleArrow->setColor(RED); + // doubleArrow->setColor(RED); float floatVal = 0.0f; GLfloat delta = 5; + bool boolean = true; while( c.isOpen() ) { c.sleep(); // doubleArrow->setCenterX(sin(floatVal/90)); @@ -27,6 +28,9 @@ void arrowFunction(Canvas& c) { // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { delta *= -1; + arrow2->setIsOutlined(boolean); + arrow2->setIsFilled(!boolean); + boolean = !boolean; } doubleArrow->changeLengthBy(delta); floatVal += 1; diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp index 1de042d6d..fdbc4b3e1 100644 --- a/src/tests/testCircle.cpp +++ b/src/tests/testCircle.cpp @@ -21,7 +21,7 @@ void circleFunction(Canvas& can) { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Circle * circle = new Circle(0,0,0,100,0,0,0,colors/* ColorFloat(1,0,0,1) */); + Circle * circle = new Circle(0,0,0,100,0,0,0,colors); // circle->setCenterX(200); // circle->setRotationPoint(0,0,0); can.add(circle); diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp index 08feb2ce9..d2fccf8b6 100644 --- a/src/tests/testClock.cpp +++ b/src/tests/testClock.cpp @@ -46,6 +46,7 @@ void clockFunction(Canvas& can) { can.add(pendulum); Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); + cord->setIsOutlined(false); cord->setRotationPoint(0,80,10); can.add(cord); diff --git a/src/tests/testCone.cpp b/src/tests/testCone.cpp index 5832a3608..bcb7f9cab 100644 --- a/src/tests/testCone.cpp +++ b/src/tests/testCone.cpp @@ -32,9 +32,9 @@ void coneFunction(Canvas& can) { ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); - // Cone * testCone2 = new Cone(-3.0, 0.0, 0.0, 2, 0.0, 45.0, 45.0, colors); + Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); can.add(testCone); - // can.add(testCone2); + can.add(testCone2); float rotation = 0.0f; GLfloat delta = 0.05; bool boolean = false; @@ -75,6 +75,7 @@ void coneFunction(Canvas& can) { } delete testCone; + delete testCone2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp index 258a49e4a..8e7b77932 100644 --- a/src/tests/testConvexPolygon.cpp +++ b/src/tests/testConvexPolygon.cpp @@ -20,7 +20,7 @@ void convexPolygonFunction(Canvas& can) { ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; float x[] = { -50,-50, 0,25,50, 50, 25 }; float y[] = { -50, 25,50,40,10,-10,-50 }; - ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors/* ColorFloat(1,0,0,1) */); + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); // cp->setCenterX(2); // cp->setRotationPoint(0,0,0); can.add(cp); diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index ed63c7f69..bf428faa9 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -20,6 +20,12 @@ void cubeFunction(Canvas& can) { float rotation = 0.0f; GLfloat delta = 0.05; bool boolean = false; + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { + testCube->setIsOutlined(boolean); + boolean = !boolean; + }); + while (can.isOpen()) { can.sleep(); // testCube->setCenterX(sin(rotation)*200); @@ -37,15 +43,15 @@ void cubeFunction(Canvas& can) { // } // testCube->changeSideLengthBy(delta); //testCube2->setRoll(rotation); - if (rotation*45 >= 360) { - if (boolean) { - testCube->setColor(RED); - } else { - testCube->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } + // if (rotation*45 >= 360) { + // if (boolean) { + // testCube->setColor(RED); + // } else { + // testCube->setColor(colors); + // } + // boolean = !boolean; + // rotation = 0; + // } rotation+=0.01; } diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp index 7baf77cb7..017f7bc1b 100644 --- a/src/tests/testEllipse.cpp +++ b/src/tests/testEllipse.cpp @@ -21,7 +21,7 @@ void ellipseFunction(Canvas& can) { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); // ellipse->setCenterX(200); // ellipse->setRotationPoint(0,0,0); can.add(ellipse); diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index a8c2ac7d8..7d2fe1957 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -18,13 +18,23 @@ void ellipsoidFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(0.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors/* ColorFloat(1,0,0,1) */); - // Ellipsoid * testEllipsoid2 = new Ellipsoid(-2.0, 0.0, 0.0, 150, 150, 150, 0.0, 0.0, 0.0, colors); + Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); + // testEllipsoid->setIsFilled(false); + Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); + testEllipsoid2->setOutlineColor(BLUE); can.add(testEllipsoid); - // can.add(testEllipsoid2); + can.add(testEllipsoid2); float rotation = 0.0f; // GLfloat delta = 0.05; bool boolean = true; + bool b2 = true; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { + testEllipsoid->setIsOutlined(b2); + testEllipsoid2->setIsOutlined(b2); + b2 = !b2; + }); + // testEllipsoid->setXRadius(150); // testEllipsoid->setYRadius(150); // testEllipsoid->setZRadius(150); @@ -38,7 +48,8 @@ void ellipsoidFunction(Canvas& can) { // testEllipsoid->setCenterZ(sin(rotation)); // testEllipsoid->setYaw(rotation*45); testEllipsoid->setPitch(rotation*45); - // testEllipsoid2->setPitch(rotation*45); + testEllipsoid2->setPitch(rotation*45); + // if(boolean) // testEllipsoid->setRoll(rotation*45); // testEllipsoid->setXRadius(cos(rotation) * 100 +101); // testEllipsoid->setYRadius(sin(rotation) * 100 +201); diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index 06514d9ca..aabf35597 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -18,7 +18,7 @@ void rpFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors/* ColorFloat(1,0,0,1) */); + RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); // rp->setCenterX(200); // rp->setRotationPoint(0,0,0); can.add(rp); diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index 45768119a..d94a33285 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -18,8 +18,12 @@ void sphereFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(0.0, 0.0, 0.0, 250, 0.0, 0.0, 0.0, colors); + Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); + Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); + testSphere->setIsOutlined(true); + testSphere2->setIsOutlined(true); can.add(testSphere); + can.add(testSphere2); float rotation = 0.0f; // GLfloat delta = 5; bool boolean = true; @@ -58,6 +62,7 @@ void sphereFunction(Canvas& can) { } delete testSphere; + delete testSphere2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 9c1b8e0e2..666c9999b 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -18,10 +18,12 @@ void squareFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,200,0,0,0,colors/* RED */); + Square * square = new Square(0,0,0,200,0,0,0,colors); + Square * square2 = new Square(-250,0,0,200,0,0,0,RED); // square->setCenterX(200); // square->setRotationPoint(0,0,0); can.add(square); + can.add(square2); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { @@ -46,6 +48,7 @@ void squareFunction(Canvas& can) { } delete square; + delete square2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index 0721c26bd..ac660bade 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -33,10 +33,10 @@ void textFunction(Canvas& can, std::string font) { // can.add(lowercase); // Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 25, 0,0,0,WHITE); // can.add(uppercase); - Text * random = new Text(0,0,0,L"bad*?<>~^letters!=", font, 48, 0,0,0,WHITE); - can.add(random); - // Text * random2 = new Text(0,-50,0,L"{[ }] |\\';:<>,./?", font, 25, 0,0,0,WHITE); - // can.add(random2); + // Text * random = new Text(0,0,0,L"Όȳ", font, 50, 0,0,0,WHITE); + // can.add(random); + Text * random2 = new Text(0,-50,0,L"{:<>,./?+=+^c", font, 25, 0,0,0,WHITE); + can.add(random2); // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { // // text->setText("Glorgaborg"); @@ -59,8 +59,8 @@ void textFunction(Canvas& can, std::string font) { // delete text; // delete lowercase; // delete uppercase; - delete random; - // delete random2; + // delete random; + delete random2; } @@ -69,7 +69,7 @@ void textFunction(Canvas& can, std::string font) { int main(int argc, char * argv[]) { int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; - std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; + std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.otf"; if(w <= 0 || h <= 0) { //Check validity of width and height w = 1.2f*Canvas::getDisplayHeight(); h = 0.75f*w; diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp index d02b870a8..af80c2314 100644 --- a/src/tests/testTriangle.cpp +++ b/src/tests/testTriangle.cpp @@ -18,10 +18,12 @@ void triangleFunction(Canvas& can) { ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors/* ColorFloat(1,0,0,1) */); + Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); + Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); // triangle->setCenterX(200); // triangle->setRotationPoint(0,0,0); can.add(triangle); + can.add(triangle2); float floatVal = 0.0f; GLfloat delta = 0.05; while (can.isOpen()) { @@ -44,6 +46,7 @@ void triangleFunction(Canvas& can) { } delete triangle; + delete triangle2; } int main(int argc, char* argv[]) { diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp index 248717e6b..ab27b3838 100644 --- a/src/tests/testTriangleStrip.cpp +++ b/src/tests/testTriangleStrip.cpp @@ -21,7 +21,8 @@ void triangleStripFunction(Canvas& can) { float x[] = { 0,-50,50,-50,50,0 }; float y[] = { -100,-50,-50,50,50,100 }; float z[] = { 0,50,50,50,50,0 }; - TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors/* RED */); + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); + // ts->setIsOutlined(true); // ts->setCenterX(2); ts->setRotationPoint(0,0,0); can.add(ts); From ec4e61252ccfe1e1b1a30237cc9e5b01d25b1b6e Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 1 Jul 2020 11:36:50 -0400 Subject: [PATCH 043/105] All characters of Text rendering, finally. --- src/TSGL/Text.cpp | 10 +++++++--- src/tests/testText.cpp | 40 ++++++++++++++++------------------------ 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 81f94bab4..805d945b6 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -70,7 +70,7 @@ void Text::draw(Shader * shader) { model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); - model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + // model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); @@ -111,7 +111,7 @@ void Text::draw(Shader * shader) { // update vertices for each character float xpos = mouseX + ch.Bearing.x; - float ypos = mouseY - (ch.Bitmap.rows - ch.Bearing.y); + float ypos = mouseY - ( (float) ch.Bitmap.rows - ch.Bearing.y); float w = ch.Bitmap.width; float h = ch.Bitmap.rows; @@ -247,7 +247,11 @@ void Text::populateCharacters() { } FT_Bitmap_Init(&ftbmps[i]); - FT_Bitmap_Copy(ft, &glyph->bitmap, &ftbmps[i]); + + if (FT_Bitmap_Copy(ft, &glyph->bitmap, &ftbmps[i])) { + TsglErr("ERROR::FREETYTPE: Failed to copy Bitmap"); + continue; + } Character character = { ftbmps[i], diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index ac660bade..3c0f59272 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -25,25 +25,19 @@ void textFunction(Canvas& can, std::string font) { // 32, BLUE); // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - // Text * text = new Text(0,0,0,L"C[i] = B[i] + A[i]", font, 100, 0,0,0, YELLOW); - // can.add(text); - // Rectangle * rec = new Rectangle(0,0,0,360,62,0,0,0, ColorFloat(1,1,1,0.2)); - // can.add(rec); - // Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 25, 0,0,0,WHITE); - // can.add(lowercase); - // Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 25, 0,0,0,WHITE); - // can.add(uppercase); - // Text * random = new Text(0,0,0,L"Όȳ", font, 50, 0,0,0,WHITE); - // can.add(random); - Text * random2 = new Text(0,-50,0,L"{:<>,./?+=+^c", font, 25, 0,0,0,WHITE); - can.add(random2); + Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); + can.add(lowercase); + Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); + can.add(uppercase); + Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); + can.add(random); - // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&text]() { - // // text->setText("Glorgaborg"); - // // text->setColor(RED); - // // text->setFont("./assets/freefont/FreeSerifItalic.ttf"); - // text->setFontSize(50); - // }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { + random->setText(L"Glorgaborg"); + // random->setColor(RED); + // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); + // random->setFontSize(100); + }); float rotation = 0.0f; while(can.isOpen()) { @@ -56,11 +50,9 @@ void textFunction(Canvas& can, std::string font) { // text->setRoll(rotation*45); rotation+=0.01; } - // delete text; - // delete lowercase; - // delete uppercase; - // delete random; - delete random2; + delete lowercase; + delete uppercase; + delete random; } @@ -69,7 +61,7 @@ void textFunction(Canvas& can, std::string font) { int main(int argc, char * argv[]) { int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; - std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.otf"; + std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; if(w <= 0 || h <= 0) { //Check validity of width and height w = 1.2f*Canvas::getDisplayHeight(); h = 0.75f*w; From 81936a2c19183d11585e52790e837449ab888fec Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 2 Jul 2020 10:16:16 -0400 Subject: [PATCH 044/105] Transparency sorting added. Not perfect, but good --- Makefile | 1 + src/TSGL/Arrow.cpp | 4 ++++ src/TSGL/Canvas.cpp | 17 +++++++++++++---- src/TSGL/Circle.cpp | 6 ++++++ src/TSGL/Cube.cpp | 2 ++ src/TSGL/Cuboid.cpp | 1 + src/TSGL/Drawable.h | 11 +++++++++++ src/TSGL/Ellipse.cpp | 6 ++++++ src/TSGL/Ellipsoid.cpp | 5 +++++ src/TSGL/Image.cpp | 30 ++++++++++++++++++++++++++++++ src/TSGL/Image.h | 2 ++ src/TSGL/Polyline.cpp | 8 ++++++++ src/TSGL/Prism.cpp | 4 ++++ src/TSGL/Pyramid.cpp | 5 +++++ src/TSGL/RegularPolygon.cpp | 5 +++++ src/TSGL/Shape.cpp | 8 ++++++++ src/TSGL/Sphere.cpp | 5 +++++ src/TSGL/Text.cpp | 2 ++ src/tests/testArrows.cpp | 8 ++++++-- src/tests/testCircle.cpp | 6 ++++++ src/tests/testConcavePolygon.cpp | 9 ++++++--- src/tests/testCube.cpp | 6 ++++++ src/tests/testCuboid.cpp | 5 +++++ src/tests/testEllipse.cpp | 5 +++++ src/tests/testEllipsoid.cpp | 6 ++++++ src/tests/testImage.cpp | 5 +++-- src/tests/testLines.cpp | 15 +++++++++------ src/tests/testPrism.cpp | 6 ++++++ src/tests/testPyramid.cpp | 5 +++++ src/tests/testRectangle.cpp | 9 +++++++-- src/tests/testRegularPolygon.cpp | 5 +++++ src/tests/testSphere.cpp | 5 +++++ src/tests/testText.cpp | 14 ++++++++------ src/tests/testTransparency.cpp | 32 ++++++++++++++++++++++++++++++++ 34 files changed, 238 insertions(+), 25 deletions(-) create mode 100644 src/tests/testTransparency.cpp diff --git a/Makefile b/Makefile index 35943c034..e2fe32310 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,7 @@ BINARIES= \ bin/testSquare \ bin/testStar \ bin/testText \ + bin/testTransparency \ bin/testTriangle \ bin/testTriangleStrip \ # bin/test_specs \ diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index a2229ddca..b8eae72c9 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -120,6 +120,9 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw addOutlineVertex(0.5, -.4, 0, GRAY); addOutlineVertex(0.5, .4, 0, GRAY); } + attribMutex.lock(); + myAlpha = (color[0].A + color[1].A) / 2; + attribMutex.unlock(); } void Arrow::setLength(GLfloat length) { @@ -173,6 +176,7 @@ void Arrow::changeWidthBy(GLfloat delta) { */ void Arrow::setColor(ColorFloat c[]) { attribMutex.lock(); + myAlpha = (c[0].A + c[1].A) / 2; for(int i = 0; i < 7; i++) { vertices[i*7 + 3] = c[i/5].R; vertices[i*7 + 4] = c[i/5].G; diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 3d1c7637d..014bfa9ef 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -52,8 +52,10 @@ static const GLchar* textFragmentShader = "out vec4 FragColor;" "uniform sampler2D text;" "uniform vec4 textColor;" - "void main() {" + "void main() {" "vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);" + "if(sampled.a < 0.5)" + "discard;" "FragColor = textColor * sampled;" "}"; @@ -197,9 +199,6 @@ void Canvas::add(Drawable * shapePtr) { objectMutex.lock(); objectBuffer.push_back(shapePtr); objectBufferEmpty = false; - std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { - return (a->getCenterZ() < b->getCenterZ()); // true if A's layer is higher than B's layer - }); objectMutex.unlock(); } @@ -284,6 +283,16 @@ void Canvas::draw() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (objectBuffer.size() > 0) { + // sort between opaques and transparents and then sort by center z. not perfect, but pretty good. + // depth buffer takes care of the rest. + std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { + if (a->getAlpha() == 1.0 && b->getAlpha() != 1.0) + return true; + else if (a->getAlpha() != 1.0 && b->getAlpha() == 1.0) + return false; + else + return (a->getCenterZ() < b->getCenterZ()); + }); for (unsigned int i = 0; i < objectBuffer.size(); i++) { Drawable* d = objectBuffer[i]; if(d->isProcessed()) { diff --git a/src/TSGL/Circle.cpp b/src/TSGL/Circle.cpp index 065496a9e..6596e96fc 100644 --- a/src/TSGL/Circle.cpp +++ b/src/TSGL/Circle.cpp @@ -100,10 +100,13 @@ void Circle::changeRadiusBy(GLfloat delta) { * \param c An array of the new ColorFloats. */ void Circle::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0f; vertices[3] = c[0].R; vertices[4] = c[0].G; vertices[5] = c[0].B; vertices[6] = c[0].A; + myAlpha += c[0].A; int colorIndex; for (int i = 1; i < numberOfVertices; ++i) { colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); @@ -111,7 +114,10 @@ void Circle::setColor(ColorFloat c[]) { vertices[i*7 + 4] = c[colorIndex].G; vertices[i*7 + 5] = c[colorIndex].B; vertices[i*7 + 6] = c[colorIndex].A; + myAlpha += c[colorIndex].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/Cube.cpp b/src/TSGL/Cube.cpp index f58c7157e..aaf551b8b 100644 --- a/src/TSGL/Cube.cpp +++ b/src/TSGL/Cube.cpp @@ -284,6 +284,8 @@ void Cube::setColor(ColorFloat c[]) { vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; + + myAlpha = (c[0].A + c[1].A + c[2].A + c[3].A + c[4].A + c[5].A + c[6].A + c[7].A) / 8; attribMutex.unlock(); } diff --git a/src/TSGL/Cuboid.cpp b/src/TSGL/Cuboid.cpp index 4667089fc..643b05582 100644 --- a/src/TSGL/Cuboid.cpp +++ b/src/TSGL/Cuboid.cpp @@ -348,6 +348,7 @@ void Cuboid::setColor(ColorFloat c[]) { vertices[81] = vertices[130] = vertices[151] = vertices[186] = vertices[200] = c[7].G; vertices[82] = vertices[131] = vertices[152] = vertices[187] = vertices[201] = c[7].B; vertices[83] = vertices[132] = vertices[153] = vertices[188] = vertices[202] = c[7].A; + myAlpha = (c[0].A + c[1].A + c[2].A + c[3].A + c[4].A + c[5].A + c[6].A + c[7].A) / 8; attribMutex.unlock(); } diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 9eb71dafa..c4114974d 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -37,6 +37,7 @@ class Drawable { float myCenterX, myCenterY, myCenterZ; bool init = false; unsigned int shaderType = SHAPE_SHADER_TYPE; + float myAlpha = 0.0; /*! * \brief Protected helper method that determines if the Drawable's center matches its rotation point. * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ @@ -123,7 +124,17 @@ class Drawable { */ virtual bool isProcessed() { return init; } + /*! + * \brief Accessor that returns a value corresponding to a certain shader in Canvas. + * \details This function returns the value of the shaderType instance variable. + */ virtual unsigned int getShaderType() { return shaderType; } + + /*! + * \brief Accessor that returns Drawable's alpha value. + * \details Principally designed to be used within Canvas for transparency sorting. + */ + virtual float getAlpha() { return myAlpha; } }; } diff --git a/src/TSGL/Ellipse.cpp b/src/TSGL/Ellipse.cpp index fb334b8c3..f122de6f4 100644 --- a/src/TSGL/Ellipse.cpp +++ b/src/TSGL/Ellipse.cpp @@ -125,10 +125,13 @@ void Ellipse::changeYRadiusBy(GLfloat delta) { * \param c An array of the new ColorFloats. */ void Ellipse::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0f; vertices[3] = c[0].R; vertices[4] = c[0].G; vertices[5] = c[0].B; vertices[6] = c[0].A; + myAlpha += c[0].A; int colorIndex; for (int i = 1; i < numberOfVertices; ++i) { colorIndex = (int) ((float) (i - 1) / verticesPerColor + 1); @@ -136,7 +139,10 @@ void Ellipse::setColor(ColorFloat c[]) { vertices[i*7 + 4] = c[colorIndex].G; vertices[i*7 + 5] = c[colorIndex].B; vertices[i*7 + 6] = c[colorIndex].A; + myAlpha += c[colorIndex].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } diff --git a/src/TSGL/Ellipsoid.cpp b/src/TSGL/Ellipsoid.cpp index 190589a55..fe21454db 100644 --- a/src/TSGL/Ellipsoid.cpp +++ b/src/TSGL/Ellipsoid.cpp @@ -236,6 +236,7 @@ void Ellipsoid::changeZRadiusBy(GLfloat delta) { */ void Ellipsoid::setColor(ColorFloat c) { attribMutex.lock(); + myAlpha = c.A; for(int b=0;b 1.0) { + TsglDebug("Cannot have an Image with alpha not between 0.0 and 1.0."); + return; + } + attribMutex.lock(); shaderType = IMAGE_SHADER_TYPE; myWidth = width; myHeight = height; myXScale = width; myYScale = height; @@ -32,8 +37,12 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); tsglAssert(data, "stbi_load(filename) failed."); + attribMutex.unlock(); glEnable(GL_TEXTURE_2D); + myAlpha = alpha; + setAlpha(myAlpha); + // vertex allocation and assignment vertices = new GLfloat[30]; @@ -176,10 +185,31 @@ void Image::changeFile(std::string filename) { stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); tsglAssert(data, "stbi_load(filename) failed."); + setAlpha(myAlpha); init = true; attribMutex.unlock(); } +/** + * \brief Alters the Image's transparency + * \param delta The Image's new alpha value. + * \note If parameter not 0.0 < alpha < 1.0 then this method will have no effect. + */ +void Image::setAlpha(float alpha) { + if (alpha < 0.0 || alpha > 1.0) { + TsglDebug("Cannot have an Image with alpha not between 0.0 and 1.0."); + return; + } + attribMutex.lock(); + myAlpha = alpha; + for (int i = 0; i < pixelHeight; i++) { + for (int j = 0; j < pixelWidth; j++) { + data[i * pixelWidth * 4 + j * 4 + 3] = (int) (alpha * 255); + } + } + attribMutex.unlock(); +} + Image::~Image() { glDeleteTextures(1, &myTexture); stbi_image_free(data); diff --git a/src/TSGL/Image.h b/src/TSGL/Image.h index 6bdd36a5c..07a518864 100755 --- a/src/TSGL/Image.h +++ b/src/TSGL/Image.h @@ -58,6 +58,8 @@ class Image : public Drawable { void changeFile(std::string filename); + void setAlpha(float newAlpha); + GLint getPixelHeight() { return pixelHeight; } GLint getPixelWidth() { return pixelWidth; } diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index 7635f6ab7..a08e6e9fb 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -132,7 +132,9 @@ void Polyline::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &colo vertices[currentVertex + 5] = color.B; vertices[currentVertex + 6] = color.A; currentVertex += 7; + myAlpha += color.A; if (currentVertex == numberOfVertices*7) { + myAlpha /= numberOfVertices; init = true; } attribMutex.unlock(); @@ -150,6 +152,7 @@ void Polyline::setColor(ColorFloat c) { vertices[i*7 + 5] = c.B; vertices[i*7 + 6] = c.A; } + myAlpha = c.A; attribMutex.unlock(); } @@ -158,12 +161,17 @@ void Polyline::setColor(ColorFloat c) { * \param c The new array of ColorFloats. */ void Polyline::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; for(int i = 0; i < numberOfVertices; i++) { vertices[i*7 + 3] = c[i].R; vertices[i*7 + 4] = c[i].G; vertices[i*7 + 5] = c[i].B; vertices[i*7 + 6] = c[i].A; + myAlpha += c[i].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } /*! diff --git a/src/TSGL/Prism.cpp b/src/TSGL/Prism.cpp index 1654d567d..fd12a6f17 100644 --- a/src/TSGL/Prism.cpp +++ b/src/TSGL/Prism.cpp @@ -205,6 +205,7 @@ void Prism::changeRadiusBy(GLfloat delta) { */ void Prism::setColor(ColorFloat c[]) { attribMutex.lock(); + myAlpha = 0.0; for (int i = 0; i < mySides; i++) { vertices[i*84+3] = c[1].R; vertices[i*84+4] = c[1].G; @@ -235,7 +236,10 @@ void Prism::setColor(ColorFloat c[]) { vertices[i*84+81] = c[4].G; vertices[i*84+82] = c[4].B; vertices[i*84+83] = c[4].A; + + myAlpha += c[0].A + c[1].A * 2 + c[2].A * 6 + c[3].A * 2 + c[4].A; } + myAlpha /= numberOfVertices; attribMutex.unlock(); } diff --git a/src/TSGL/Pyramid.cpp b/src/TSGL/Pyramid.cpp index 242b46edd..f9c27e594 100644 --- a/src/TSGL/Pyramid.cpp +++ b/src/TSGL/Pyramid.cpp @@ -190,6 +190,7 @@ void Pyramid::changeHeightBy(float delta) { */ void Pyramid::setColor(ColorFloat c) { attribMutex.lock(); + myAlpha = c.A; for(int i = 0; i < mySides; i++) { vertices[i*42 + 3] = vertices[i*42 + 10] = vertices[i*42 + 17] = vertices[i*42 + 24] = vertices[i*42 + 38] = c.R; vertices[i*42 + 4] = vertices[i*42 + 11] = vertices[i*42 + 18] = vertices[i*42 + 25] = vertices[i*42 + 39] = c.G; @@ -211,6 +212,7 @@ void Pyramid::setColor(ColorFloat c) { */ void Pyramid::setColor(ColorFloat c[]) { attribMutex.lock(); + myAlpha = 0.0; for(int i = 0; i < mySides; i++) { vertices[i*42 + 3] = c[i+1].R; vertices[i*42 + 4] = c[i+1].G; @@ -241,7 +243,10 @@ void Pyramid::setColor(ColorFloat c[]) { vertices[i*42 + 39] = c[(i+1) % mySides + 1].G; vertices[i*42 + 40] = c[(i+1) % mySides + 1].B; vertices[i*42 + 41] = c[(i+1) % mySides + 1].A; + + myAlpha += c[i+1].A * 2 + c[0].A + c[(i+1) % mySides + 1].A * 2 + c[mySides+2].A; } + myAlpha /= numberOfVertices; attribMutex.unlock(); } diff --git a/src/TSGL/RegularPolygon.cpp b/src/TSGL/RegularPolygon.cpp index 86d9d0b03..1e1aa37c3 100644 --- a/src/TSGL/RegularPolygon.cpp +++ b/src/TSGL/RegularPolygon.cpp @@ -88,12 +88,17 @@ void RegularPolygon::changeRadiusBy(GLfloat delta) { } void RegularPolygon::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; for(int i = 0; i < numberOfVertices; i++) { vertices[i*7 + 3] = c[i % (mySides - 1)].R; vertices[i*7 + 4] = c[i % (mySides - 1)].G; vertices[i*7 + 5] = c[i % (mySides - 1)].B; vertices[i*7 + 6] = c[i % (mySides - 1)].A; + myAlpha += c[i % (mySides - 1)].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } } \ No newline at end of file diff --git a/src/TSGL/Shape.cpp b/src/TSGL/Shape.cpp index 63c9d7ff1..8eb61545b 100644 --- a/src/TSGL/Shape.cpp +++ b/src/TSGL/Shape.cpp @@ -71,7 +71,9 @@ void Shape::addVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat &color) vertices[currentVertex + 5] = color.B; vertices[currentVertex + 6] = color.A; currentVertex += 7; + myAlpha += color.A; if (currentVertex == numberOfVertices*7) { + myAlpha /= numberOfVertices; init = true; } attribMutex.unlock(); @@ -114,6 +116,7 @@ void Shape::addOutlineVertex(GLfloat x, GLfloat y, GLfloat z, const ColorFloat & */ void Shape::setColor(ColorFloat c) { attribMutex.lock(); + myAlpha = c.A; for(int i = 0; i < numberOfVertices; i++) { vertices[i*7 + 3] = c.R; vertices[i*7 + 4] = c.G; @@ -128,12 +131,17 @@ void Shape::setColor(ColorFloat c) { * \param c The new array of ColorFloats. */ void Shape::setColor(ColorFloat c[]) { + attribMutex.lock(); + myAlpha = 0.0; for(int i = 0; i < numberOfVertices; i++) { vertices[i*7 + 3] = c[i].R; vertices[i*7 + 4] = c[i].G; vertices[i*7 + 5] = c[i].B; vertices[i*7 + 6] = c[i].A; + myAlpha += c[i].A; } + myAlpha /= numberOfVertices; + attribMutex.unlock(); } /** diff --git a/src/TSGL/Sphere.cpp b/src/TSGL/Sphere.cpp index 0d6e3ea82..78ca9cf2b 100644 --- a/src/TSGL/Sphere.cpp +++ b/src/TSGL/Sphere.cpp @@ -173,6 +173,7 @@ void Sphere::changeRadiusBy(float delta) { */ void Sphere::setColor(ColorFloat c) { attribMutex.lock(); + myAlpha = c.A; for(int b=0;bsetCenterX(100); // doubleArrow->setRotationPoint(0,0,0); // doubleArrow->setYaw(45); - // doubleArrow->setColor(RED); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(colors); + // printf("%f\n", doubleArrow->getAlpha()); float floatVal = 0.0f; GLfloat delta = 5; bool boolean = true; diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp index fdbc4b3e1..3017ff708 100644 --- a/src/tests/testCircle.cpp +++ b/src/tests/testCircle.cpp @@ -22,6 +22,12 @@ void circleFunction(Canvas& can) { ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; Circle * circle = new Circle(0,0,0,100,0,0,0,colors); + + // printf("%f\n", circle->getAlpha()); + // circle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", circle->getAlpha()); + // circle->setColor(colors); + // printf("%f\n", circle->getAlpha()); // circle->setCenterX(200); // circle->setRotationPoint(0,0,0); can.add(circle); diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp index eaaa5e45f..547c07364 100644 --- a/src/tests/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon.cpp @@ -31,7 +31,7 @@ void concavePolygonFunction(Canvas& can) { float yy[PSIZE]; ColorFloat color[PSIZE]; for (unsigned i = 0; i < PSIZE; ++i) - color[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), 1); + color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); color[1] = color[PSIZE-1]; @@ -58,8 +58,11 @@ void concavePolygonFunction(Canvas& can) { // } ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); - // c2->setColor(color); - // c2->setColor(RED); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(color); + // printf("%f\n", c2->getAlpha()); can.add(c2); float floatVal = 0.0f; diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index bf428faa9..44907768b 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -16,6 +16,12 @@ void cubeFunction(Canvas& can) { Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); can.add(testCube); + + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(colors); + // printf("%f\n", testCube2->getAlpha()); can.add(testCube2); float rotation = 0.0f; GLfloat delta = 0.05; diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp index e0007f458..b5893b27a 100644 --- a/src/tests/testCuboid.cpp +++ b/src/tests/testCuboid.cpp @@ -15,6 +15,11 @@ void cuboidFunction(Canvas& can) { ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(colors); + // printf("%f\n", testCuboid2->getAlpha()); can.add(testCuboid); can.add(testCuboid2); float rotation = 0.0f; diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp index 017f7bc1b..b64990098 100644 --- a/src/tests/testEllipse.cpp +++ b/src/tests/testEllipse.cpp @@ -24,6 +24,11 @@ void ellipseFunction(Canvas& can) { Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); // ellipse->setCenterX(200); // ellipse->setRotationPoint(0,0,0); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(colors); + // printf("%f\n", ellipse->getAlpha()); can.add(ellipse); float floatVal = 0.0f; GLfloat delta = 5; diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp index 7d2fe1957..d317b523d 100644 --- a/src/tests/testEllipsoid.cpp +++ b/src/tests/testEllipsoid.cpp @@ -22,6 +22,12 @@ void ellipsoidFunction(Canvas& can) { // testEllipsoid->setIsFilled(false); Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); testEllipsoid2->setOutlineColor(BLUE); + + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(colors); + // printf("%f\n", testEllipsoid->getAlpha()); can.add(testEllipsoid); can.add(testEllipsoid2); float rotation = 0.0f; diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 18a4ff2e0..117fb772f 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -52,11 +52,12 @@ void imageFunction(Canvas& can) { bool ss = false; while (can.isOpen()) { can.sleep(); + image->setAlpha((sin(floatVal) + 1) / 2); // image->setCenterX(sin(floatVal/90) * 100); // image->setCenterY(sin(floatVal/90) * 100); // image->setCenterZ(sin(floatVal/90) * 100); // image->setYaw(floatVal); - image->setPitch(floatVal); + image->setPitch(floatVal * 100); // image->setRoll(floatVal); // image->setWidth(sin(floatVal/90) * 100 + 400); // image->setHeight(sin(floatVal/90) * 100 + 400); @@ -75,7 +76,7 @@ void imageFunction(Canvas& can) { // } // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); - floatVal += 1; + floatVal += 0.01; } // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay diff --git a/src/tests/testLines.cpp b/src/tests/testLines.cpp index 79d9d1015..625f32b79 100644 --- a/src/tests/testLines.cpp +++ b/src/tests/testLines.cpp @@ -5,11 +5,11 @@ using namespace tsgl; void lineFunction(Canvas& c) { - ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,1), - ColorFloat(0,0,1,1), ColorFloat(1,0,1,1), - ColorFloat(1,1,0,1), ColorFloat(0,1,1,1), - ColorFloat(0,0,1,1) }; - Line * l = new Line(0,0,0,200,0,0,0,RED); + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), + ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), + ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), + ColorFloat(0,0,1,0.7) }; + Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); // l->setColor(RED); l->setColor(colors); @@ -22,7 +22,10 @@ void lineFunction(Canvas& c) { 100,-100,100, 150,-100,-100 }; - Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,BLUE); + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); + + // printf("Line: %f\n", l->getAlpha()); + // printf("Pline: %f\n", p->getAlpha()); // p->setColor(BLUE); p->setColor(colors); diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp index 4ce152783..a07561a59 100644 --- a/src/tests/testPrism.cpp +++ b/src/tests/testPrism.cpp @@ -18,6 +18,12 @@ void prismFunction(Canvas& can) { Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); + + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(colors); + // printf("%f\n", testPrism2->getAlpha()); can.add(testPrism); can.add(testPrism2); can.add(testPrism3); diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp index 23043e7be..ac0db8692 100644 --- a/src/tests/testPyramid.cpp +++ b/src/tests/testPyramid.cpp @@ -18,6 +18,11 @@ void pyramidFunction(Canvas& can) { Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(colors); + // printf("%f\n", testPyramid2->getAlpha()); can.add(testPyramid); can.add(testPyramid2); can.add(testPyramid3); diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp index 756ef63ab..89a6a9e46 100644 --- a/src/tests/testRectangle.cpp +++ b/src/tests/testRectangle.cpp @@ -10,8 +10,8 @@ using namespace tsgl; void rectangleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), + ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), @@ -21,6 +21,11 @@ void rectangleFunction(Canvas& can) { Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); // rectangle->setCenterX(200); // rectangle->setRotationPoint(0,0,0); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(colors); + // printf("%f\n", rectangle->getAlpha()); can.add(rectangle); float floatVal = 0.0f; GLfloat delta = 0.05; diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp index aabf35597..d3b7f54ef 100644 --- a/src/tests/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon.cpp @@ -21,6 +21,11 @@ void rpFunction(Canvas& can) { RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); // rp->setCenterX(200); // rp->setRotationPoint(0,0,0); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(colors); + // printf("%f\n", rp->getAlpha()); can.add(rp); float floatVal = 0.0f; GLfloat delta = 5; diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp index d94a33285..e2e9a8600 100644 --- a/src/tests/testSphere.cpp +++ b/src/tests/testSphere.cpp @@ -22,6 +22,11 @@ void sphereFunction(Canvas& can) { Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); testSphere->setIsOutlined(true); testSphere2->setIsOutlined(true); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(colors); + // printf("%f\n", testSphere->getAlpha()); can.add(testSphere); can.add(testSphere2); float rotation = 0.0f; diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index 3c0f59272..7be03beb7 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -30,7 +30,9 @@ void textFunction(Canvas& can, std::string font) { Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); can.add(uppercase); Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); + Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); can.add(random); + can.add(rec); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { random->setText(L"Glorgaborg"); @@ -42,12 +44,12 @@ void textFunction(Canvas& can, std::string font) { float rotation = 0.0f; while(can.isOpen()) { can.sleep(); - // text->setCenterX(sin(rotation)*200); - // text->setCenterY(cos(rotation)*200); - // text->setCenterZ(sin(rotation)*100); - // text->setYaw(rotation*45); - // text->setPitch(rotation*45); - // text->setRoll(rotation*45); + // random->setCenterX(sin(rotation)*200); + // random->setCenterY(cos(rotation)*200); + // random->setCenterZ(sin(rotation)*100); + // random->setYaw(rotation*45); + random->setPitch(rotation*45); + // random->setRoll(rotation*45); rotation+=0.01; } delete lowercase; diff --git a/src/tests/testTransparency.cpp b/src/tests/testTransparency.cpp new file mode 100644 index 000000000..c852b3e20 --- /dev/null +++ b/src/tests/testTransparency.cpp @@ -0,0 +1,32 @@ +/* + * testTransparency.cpp + * + * Usage: ./testTransparency + */ + +#include +#include + +using namespace tsgl; + +void transparencyFunction(Canvas& can) { + Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); + Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); + Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); + can.add(cube2); + can.add(cube); + can.add(rec); + + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + cube2->setCenterZ(150 * cos(rotation)); + rotation += 0.1; + } +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Transparency"); + c.setBackgroundColor(BLACK); + c.run(transparencyFunction); +} \ No newline at end of file From 2091b9e08d8c8e5948084054b85c21aa04ff5110 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 6 Jul 2020 18:57:21 -0400 Subject: [PATCH 045/105] Initial Background added, image alpha improved. --- Makefile | 2 +- src/TSGL/Background.cpp | 142 ++++++++++++++++++++++++++++++++++ src/TSGL/Background.h | 47 +++++++++++ src/TSGL/Canvas.cpp | 104 +++++++++++-------------- src/TSGL/Canvas.h | 5 +- src/TSGL/Cube.h | 6 +- src/TSGL/Drawable.h | 2 +- src/TSGL/Image.cpp | 22 ++---- src/TSGL/Util.h | 2 +- src/tests/testBackground.cpp | 110 ++++++++++++++++++++++++++ src/tests/testColorPoints.cpp | 68 ---------------- src/tests/testImage.cpp | 5 +- 12 files changed, 365 insertions(+), 150 deletions(-) create mode 100644 src/TSGL/Background.cpp create mode 100644 src/TSGL/Background.h create mode 100644 src/tests/testBackground.cpp delete mode 100644 src/tests/testColorPoints.cpp diff --git a/Makefile b/Makefile index e2fe32310..64d245c80 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,7 @@ BINARIES= \ bin/test3DRotation \ bin/test3DPhilosophers \ bin/testArrows \ + bin/testBackground \ bin/testBallroom \ bin/testCircle \ bin/testClock \ @@ -106,7 +107,6 @@ BINARIES= \ # bin/testAura \ # bin/testBlurImage \ # bin/testCalcPi \ -# bin/testColorPoints \ # bin/testColorWheel \ # bin/testConstructors \ # bin/testConway \ diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp new file mode 100644 index 000000000..bb0b74c31 --- /dev/null +++ b/src/TSGL/Background.cpp @@ -0,0 +1,142 @@ +#include "Background.h" + +namespace tsgl { + + /*! + * \brief Explicitly constructs a new Background. + * \details Explicit constructor for a Background object. + * \param x The x coordinate of the center of the Background. + * \param y The y coordinate of the center of the Background. + * \param z The z coordinate of the center of the Background. + * \param width Background's width in pixels. + * \param yaw The Background's yaw, in degrees. + * \param pitch The Background's pitch, in degrees. + * \param roll The Background's roll, in degrees. + * \param c A ColorFloat for the Background's original color. + * \warning An invariant is held where if width or height isn't positive then an error message is given. + * \return A new Background with a buffer for storing the specified numbered of vertices. + */ +Background::Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c) +: Drawable(x, y, z, yaw, pitch, roll) { + if (width <= 0 || height <= 0) { + TsglDebug("Cannot have a Background with non-positive width or height."); + } + attribMutex.lock(); + shaderType = TEXTURE_SHADER_TYPE; + myXScale = myWidth = width; + myYScale = myHeight = height; + vertices = new GLfloat[30]; + buffer = new uint8_t[myWidth * myHeight * 4]; + vertices[0] = vertices[1] = vertices[6] = vertices[10] = vertices[16] = vertices[20] = -0.5; // x + y + vertices[5] = vertices[11] = vertices[15] = vertices[21] = vertices[25] = vertices[26] = 0.5; // x + y + vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = 0; // z + vertices[3] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[29] = 0.0; // texture coord x + y + vertices[4] = vertices[8] = vertices[9] = vertices[18] = vertices[19] = vertices[28] = 1.0; // texture coord x + y + + // make original background monocolor + for (int j = 0; j < myHeight; j++) + for (int i = 0; i < myWidth; i++) { + buffer[i * myHeight * 4 + j * 4] = (int) (c.R * 255); + buffer[i * myHeight * 4 + j * 4 + 1] = (int) (c.G * 255); + buffer[i * myHeight * 4 + j * 4 + 2] = (int) (c.B * 255); + buffer[i * myHeight * 4 + j * 4 + 3] = (int) (c.A * 255); + } + + init = true; + attribMutex.unlock(); +} + + /*! + * \brief Draw the Background. + * \details This function actually draws the Background to the Canvas. + */ +void Background::draw(Shader * shader) { + if (!init) { + TsglDebug("Vertex buffer is not full."); + return; + } + + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); + model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); + model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); + model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); + model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); + + unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + unsigned int alphaLoc = glGetUniformLocation(shader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &myTexture); + // enable textures and bind the texture id + glBindTexture(GL_TEXTURE_2D, myTexture); + + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glGenerateMipmap(GL_TEXTURE_2D); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDeleteTextures(1, &myTexture); + + glDisable(GL_TEXTURE_2D); +} + + /*! + * \brief Gets the color of the pixel drawn on the current Background at the given row and column. + * \note (0,0) signifies the top-left of the Background's texture. + * \param row The row (y-position) of the pixel to grab. + * \param col The column (x-position) of the pixel to grab. + * \return A ColorInt containing the color of the pixel at (col,row). + */ +ColorInt Background::getPixel(int row, int col) { + ColorInt c; + attribMutex.lock(); + c = ColorInt(buffer[(row * myWidth + col) * 4], + buffer[(row * myWidth + col) * 4 + 1], + buffer[(row * myWidth + col) * 4 + 2], + buffer[(row * myWidth + col) * 4 + 3]); + attribMutex.unlock(); + return c; +} + + /*! + * \brief Draws a single pixel, specified in row,column format. + * \details This function alters the value at the specified row, column offset within the Background's buffer variable. + * \note (0,0) signifies the top-left of the Background. + * \param row The row (y-position) of the pixel. + * \param col The column (x-position) of the pixel. + * \param color The color of the point. + */ +void Background::drawPixel(int row, int col, ColorInt c) { + attribMutex.lock(); + buffer[(row * myWidth + col) * 4] = c.R; + buffer[(row * myWidth + col) * 4 + 1] = c.G; + buffer[(row * myWidth + col) * 4 + 2] = c.B; + buffer[(row * myWidth + col) * 4 + 3] = c.A; + attribMutex.unlock(); +} + +/*! +* \brief Destructor for the Background. +*/ +Background::~Background() { + delete [] buffer; +} + +} \ No newline at end of file diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h new file mode 100644 index 000000000..bb3edb3f9 --- /dev/null +++ b/src/TSGL/Background.h @@ -0,0 +1,47 @@ +/* + * Background.h extends Drawable and provides a class for drawing a background. + */ + +#ifndef BACKGROUND_H_ +#define BACKGROUND_H_ + +#include "Drawable.h" // For extending our Shape object + +namespace tsgl { + +/*! \class Background + * \brief Draw a Background for the Canvas with colored pixels. + * \details Background is a class for holding colored pixel data. + */ +class Background : public Drawable { +protected: + GLint myWidth, myHeight; + GLuint myTexture; + uint8_t * buffer; +public: + Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c = WHITE); + + virtual void draw(Shader * shader); + + /*! + * \brief Accessor for the width of the Background. + * \details Returns the value of the myWidth private variable, a GLint. + */ + virtual GLint getWidth() { return myWidth; } + + /*! + * \brief Accessor for the height of the Background. + * \details Returns the value of the myHeight private variable, a GLint. + */ + virtual GLint getHeight() { return myHeight; } + + virtual ColorInt getPixel(int row, int col); + + virtual void drawPixel(int row, int col, ColorInt c); + + virtual ~Background(); +}; + +} + +#endif /* BACKGROUND_H_ */ \ No newline at end of file diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 014bfa9ef..adf044cea 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -59,7 +59,7 @@ static const GLchar* textFragmentShader = "FragColor = textColor * sampled;" "}"; -static const GLchar* imageVertexShader = +static const GLchar* textureVertexShader = "#version 330 core\n" "layout (location = 0) in vec3 aPos;" "layout (location = 1) in vec2 aTexCoord;" @@ -72,13 +72,14 @@ static const GLchar* imageVertexShader = "TexCoords = vec2(aTexCoord.x, aTexCoord.y);" "}"; -static const GLchar* imageFragmentShader = +static const GLchar* textureFragmentShader = "#version 330 core\n" "out vec4 FragColor;" "in vec2 TexCoords;" "uniform sampler2D texture1;" + "uniform float alpha;" "void main() {" - "FragColor = texture(texture1, TexCoords);" + "FragColor = texture(texture1, TexCoords) * vec4(1.0,1.0,1.0,alpha);" "}"; int Canvas::drawBuffer = GL_FRONT_LEFT; @@ -296,11 +297,11 @@ void Canvas::draw() for (unsigned int i = 0; i < objectBuffer.size(); i++) { Drawable* d = objectBuffer[i]; if(d->isProcessed()) { - textureShaders(d->getShaderType()); + selectShaders(d->getShaderType()); if (d->getShaderType() == SHAPE_SHADER_TYPE) { d->draw(shapeShader); - } else if (d->getShaderType() == IMAGE_SHADER_TYPE) { - d->draw(imageShader); + } else if (d->getShaderType() == TEXTURE_SHADER_TYPE) { + d->draw(textureShader); } else if (d->getShaderType() == TEXT_SHADER_TYPE) { d->draw(textShader); } @@ -332,7 +333,7 @@ void Canvas::draw() // glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); // glDrawBuffer(drawBuffer); - // textureShaders(true); + // selectShaders(true); // const float vertices[36] = { // 0, 0, 0,1,1,1,1,0,1, // winWidth,0, 0,1,1,1,1,1,1, @@ -352,7 +353,7 @@ void Canvas::draw() // glFlush(); // Flush buffer data to the actual draw buffer // glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - // textureShaders(false); + // selectShaders(false); // Update Screen glfwSwapBuffers(window); @@ -442,9 +443,9 @@ void Canvas::draw() if (frame == 0 || !objectBufferEmpty) { glClear(GL_COLOR_BUFFER_BIT); if(frame > 1) { - textureShaders(true); + selectShaders(true); loader.drawGLtextureFromBuffer(proceduralBuffer, leftWindowIndex, 0, winWidth, winHeight, GL_RGB); - textureShaders(false); + selectShaders(false); } } @@ -456,9 +457,9 @@ void Canvas::draw() if (!d->getIsTextured()) { d->draw(); } else { - textureShaders(true); + selectShaders(true); d->draw(); - textureShaders(false); + selectShaders(false); } } } @@ -499,9 +500,9 @@ void Canvas::draw() if (!d->getIsTextured()) { d->draw(); } else { - textureShaders(true); + selectShaders(true); d->draw(); - textureShaders(false); + selectShaders(false); } } } @@ -535,7 +536,7 @@ void Canvas::draw() // apparently not very vital at all glDrawBuffer(drawBuffer); - textureShaders(true); + selectShaders(true); const float vertices[32] = { 0, 0, 1,1,1,1,0,1, winWidth,0, 1,1,1,1,1,1, @@ -555,7 +556,7 @@ void Canvas::draw() glFlush(); // Flush buffer data to the actual draw buffer glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - textureShaders(false); + selectShaders(false); #ifndef __APPLE__ glfwPollEvents(); // Handle any I/O @@ -2096,7 +2097,7 @@ void Canvas::glDestroy() { // glDeleteProgram(textureShaderProgram); delete textShader; delete shapeShader; - delete imageShader; + delete textureShader; glDeleteBuffers(1, &VBO); glDeleteVertexArrays(1, &VAO); } @@ -2279,10 +2280,6 @@ void Canvas::initGlew() { glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - // glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)winWidth/(float)winHeight, 0.1f, 1000.0f); - // glm::mat4 view = glm::mat4(1.0f); - // view = glm::translate(view, glm::vec3(0.0f, 0.0f, -((winHeight / 2) / tan(glm::pi()/6)))); - char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ char *res = realpath(".", buf); if (res) { @@ -2294,26 +2291,9 @@ void Canvas::initGlew() { textShader = new Shader(textVertexShader, textFragmentShader); - // textShader->use(); - // glUniformMatrix4fv(glGetUniformLocation(textShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - // unsigned int viewLoc = glGetUniformLocation(textShader->ID, "view"); - // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); - - shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); - - // shapeShader->use(); - // glUniformMatrix4fv(glGetUniformLocation(shapeShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - // viewLoc = glGetUniformLocation(shapeShader->ID, "view"); - // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); - - imageShader = new Shader(imageVertexShader, imageFragmentShader); - - // imageShader->use(); - // glUniformMatrix4fv(glGetUniformLocation(imageShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - // viewLoc = glGetUniformLocation(imageShader->ID, "view"); - // glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]); - + shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); + textureShader = new Shader(textureVertexShader, textureFragmentShader); /****** NEW ******/ // Create a framebuffer @@ -2401,6 +2381,14 @@ void Canvas::initWindow() { glfwSetMouseButtonCallback(window, buttonCallback); glfwSetKeyCallback(window, keyCallback); glfwSetScrollCallback(window, scrollCallback); + + // Scale to window size + GLint windowWidth, windowHeight; + glfwGetWindowSize(window, &windowWidth, &windowHeight); + glViewport(0, 0, windowWidth, windowHeight); + winWidth = windowWidth; + winHeight = windowHeight; + // Get info of GPU and supported OpenGL version printf("Renderer: %s\n", glGetString(GL_RENDERER)); printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); @@ -2644,21 +2632,21 @@ void Canvas::setShowFPS(bool b) { } void Canvas::setupCamera() { - // Set up camera positioning - // Note: (winWidth-1) is a dark voodoo magic fix for some camera issues - float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, - -(winWidth-1) / 2.0f, (winHeight) / 2.0f, -(winHeight) / 2.0f, 1 }; -// float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, -// -(winWidth-1) / 2.0f, (winHeight+0.5f) / 2.0f, -(winHeight-0.5f) / 2.0f, 1 }; - glUniformMatrix4fv(uniView, 1, GL_FALSE, &viewF[0]); +// // Set up camera positioning +// // Note: (winWidth-1) is a dark voodoo magic fix for some camera issues +// float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, +// -(winWidth-1) / 2.0f, (winHeight) / 2.0f, -(winHeight) / 2.0f, 1 }; +// // float viewF[] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, +// // -(winWidth-1) / 2.0f, (winHeight+0.5f) / 2.0f, -(winHeight-0.5f) / 2.0f, 1 }; +// glUniformMatrix4fv(uniView, 1, GL_FALSE, &viewF[0]); - // Set up camera zooming - float projF[] = { 1.0f / aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1.0f, -1, 0, 0, -0.02f, 0 }; - glUniformMatrix4fv(uniProj, 1, GL_FALSE, &projF[0]); +// // Set up camera zooming +// float projF[] = { 1.0f / aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1.0f, -1, 0, 0, -0.02f, 0 }; +// glUniformMatrix4fv(uniProj, 1, GL_FALSE, &projF[0]); - // Set up camera transformation - float modelF[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; - glUniformMatrix4fv(uniModel, 1, GL_FALSE, &modelF[0]); +// // Set up camera transformation +// float modelF[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; +// glUniformMatrix4fv(uniModel, 1, GL_FALSE, &modelF[0]); } /*! @@ -2752,7 +2740,7 @@ void Canvas::takeScreenShot() { if (toRecord == 0) toRecord = 1; } -void Canvas::textureShaders(unsigned int sType) { +void Canvas::selectShaders(unsigned int sType) { Shader * program; if (sType == TEXT_SHADER_TYPE) { program = textShader; @@ -2774,13 +2762,13 @@ void Canvas::textureShaders(unsigned int sType) { GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); glEnableVertexAttribArray(colAttrib); glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); - } else if (sType == IMAGE_SHADER_TYPE) { - program = imageShader; - GLint posAttrib = glGetAttribLocation(imageShader->ID, "aPos"); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); glEnableVertexAttribArray(posAttrib); glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); // texture coord attribute - GLint texAttrib = glGetAttribLocation(imageShader->ID, "aTexCoord"); + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); glEnableVertexAttribArray(texAttrib); glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index c7d6b6261..619476c80 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -37,6 +37,7 @@ #include "Text.h" // Our own class for drawing text #include "Timer.h" // Our own timer for steady FPS #include "Triangle.h" // Our own class for drawing triangles +#include "Background.h" // Our own class for drawing a background #include "TextureHandler.h" // Currently used for screenshots, might change this #include "Util.h" // Needed constants and has cmath for performing math operations @@ -131,7 +132,7 @@ class Canvas { // shaderVertex; // Address of the vertex shader Shader * textShader; Shader * shapeShader; - Shader * imageShader; + Shader * textureShader; std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting @@ -187,7 +188,7 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void textureShaders(unsigned int choice); // Turn textures on or off + void selectShaders(unsigned int choice); // Turn textures on or off // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works // static bool testLine(Canvas& can); // Unit tester for lines static bool testAccessors(Canvas& can); // Unit tester for accessor methods diff --git a/src/TSGL/Cube.h b/src/TSGL/Cube.h index 44f422f50..00a033231 100644 --- a/src/TSGL/Cube.h +++ b/src/TSGL/Cube.h @@ -1,5 +1,5 @@ /* - * Cube.h extends Prism and provides a class for drawing a Cube. + * Cube.h extends Shape and provides a class for drawing a Cube. */ #ifndef CUBE_H_ @@ -28,8 +28,8 @@ class Cube : public Shape { virtual void changeSideLengthBy(float delta); /*! - * \brief Accessor for the radius of the Prism. - * \details Returns the value of the myRadius private variable, a GLfloat. + * \brief Accessor for the side length of the Cube. + * \details Returns the value of the mySideLength private variable, a GLfloat. */ virtual GLfloat getSideLength() { return mySideLength; } diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index c4114974d..3193f4efa 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -37,7 +37,7 @@ class Drawable { float myCenterX, myCenterY, myCenterZ; bool init = false; unsigned int shaderType = SHAPE_SHADER_TYPE; - float myAlpha = 0.0; + GLfloat myAlpha = 0.0; /*! * \brief Protected helper method that determines if the Drawable's center matches its rotation point. * \details Checks to see if myCenterX == myRotationPointX, myCenterY == myRotationPointY, myCenterZ == myRotationPointZ diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index 84e97c285..f2d1fd87e 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -28,21 +28,17 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf return; } attribMutex.lock(); - shaderType = IMAGE_SHADER_TYPE; + shaderType = TEXTURE_SHADER_TYPE; myWidth = width; myHeight = height; myXScale = width; myYScale = height; myFile = filename; + myAlpha = alpha; // Load the image. stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); tsglAssert(data, "stbi_load(filename) failed."); - attribMutex.unlock(); glEnable(GL_TEXTURE_2D); - - myAlpha = alpha; - setAlpha(myAlpha); - // vertex allocation and assignment vertices = new GLfloat[30]; @@ -60,6 +56,7 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf vertices[3] = vertices[4] = vertices[8] = vertices[18] = vertices[19] = vertices[29] = 1.0; // texture coord x + y vertices[9] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[28] = 0.0; // texture coord x + y init = true; + attribMutex.unlock(); } /*! @@ -83,6 +80,9 @@ void Image::draw(Shader * shader) { unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + unsigned int alphaLoc = glGetUniformLocation(shader->ID, "alpha"); + glUniform1f(alphaLoc, myAlpha); + glEnable(GL_TEXTURE_2D); glGenTextures(1, &myTexture); // enable textures and bind the texture id @@ -185,7 +185,6 @@ void Image::changeFile(std::string filename) { stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); tsglAssert(data, "stbi_load(filename) failed."); - setAlpha(myAlpha); init = true; attribMutex.unlock(); } @@ -193,20 +192,15 @@ void Image::changeFile(std::string filename) { /** * \brief Alters the Image's transparency * \param delta The Image's new alpha value. - * \note If parameter not 0.0 < alpha < 1.0 then this method will have no effect. + * \note If parameter not 0.0 <= alpha <= 1.0 then this method will have no effect. */ void Image::setAlpha(float alpha) { if (alpha < 0.0 || alpha > 1.0) { - TsglDebug("Cannot have an Image with alpha not between 0.0 and 1.0."); + TsglDebug("Cannot have an Image with alpha not 0.0 <= alpha <= 1.0."); return; } attribMutex.lock(); myAlpha = alpha; - for (int i = 0; i < pixelHeight; i++) { - for (int j = 0; j < pixelWidth; j++) { - data[i * pixelWidth * 4 + j * 4 + 3] = (int) (alpha * 255); - } - } attribMutex.unlock(); } diff --git a/src/TSGL/Util.h b/src/TSGL/Util.h index 7817f54d4..90ebace7a 100644 --- a/src/TSGL/Util.h +++ b/src/TSGL/Util.h @@ -28,7 +28,7 @@ const float FRAME = 1.0f/FPS; // Number of seconds between frames const unsigned int TEXT_SHADER_TYPE = 0; const unsigned int SHAPE_SHADER_TYPE = 1; -const unsigned int IMAGE_SHADER_TYPE = 2; +const unsigned int TEXTURE_SHADER_TYPE = 2; /*! * \var typedef long double Decimal diff --git a/src/tests/testBackground.cpp b/src/tests/testBackground.cpp new file mode 100644 index 000000000..3839b6a79 --- /dev/null +++ b/src/tests/testBackground.cpp @@ -0,0 +1,110 @@ +/* + * testColorPoints.cpp + * + * Usage: ./testColorPoints + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line + * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. + * - The actual number of threads created is stored in: \b nthreads . + * - The number of lines per thread is calculated and stored in: \b myPart . + * - The starting position of each given thread is calculated and stored in: \b myStart . + * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. + * - The color for a thread is calculated. + * - If the point's coordinate is even: + * - Draw a point on the Canvas in the thread's color. + * - Else: + * - Draw the point normally. + * . + * - The function breaks from the outer for loop if the Canvas is closed. + * . + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Number of threads to use. + */ +void colorPointsFunction(Canvas& can, int numberOfThreads) { + Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); + can.add(background); + + /* this is the part of the test for drawPixel */ + #pragma omp parallel num_threads(numberOfThreads) + { + int nthreads = omp_get_num_threads(); //Actual number of threads to use + // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. + // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. + int myPart = can.getWindowHeight() / nthreads; + int myStart = myPart * omp_get_thread_num(); + for (int i = myStart; i < myStart + myPart; i++) { + for (int j = 0; j < can.getWindowWidth(); j++) { + // int id = omp_get_thread_num(); + if (i % 2 == 0) { + background->drawPixel(i, j, BLACK); + } else { + background->drawPixel(i, j, ColorInt(i % 255, j % 255, (i*j) % 255)); + } + } + if (!can.isOpen()) break; + } + } + /* end drawPixel. while loop only contains can.sleep() */ + + /* the getPixel portion of the test */ + // bool print = false; + // int mouseX = 0; + // int mouseY = 0; + + // ColorInt colors[] = { ColorInt(255,255,255,255), + // ColorInt(255,0,0,255), ColorInt(0,255,0,255), + // ColorInt(0,0,255,255), ColorInt(255,255,0,255), + // ColorInt(255,0,255,255), ColorInt(0,255,255,255), + // ColorInt(0,0,0,255)}; + // for (int k = 0; k < 8; k++) + // for (int j = k * background->getHeight() / 8; j < (k+1) * background->getHeight() / 8; j++) + // for (int i = 0; i < background->getWidth(); i++) + // if (k * background->getWidth() / 8 <= i && i < (k+1) * background->getWidth() / 8) + // background->drawPixel(j, i, ColorInt(123,123,123,255)); + // else + // background->drawPixel(j, i, colors[k]); + + + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { + // print = true; + // }); + + // ColorInt c; + /* end getPixel(). uncomment entirety of while loop */ + + while (can.isOpen()) { + can.sleep(); + // mouseX = can.getMouseX(); + // mouseY = can.getMouseY(); + // if (print) { + // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. + // printf("%d, %d; ", mouseY, mouseX); + // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); + // print = false; + // } + } + delete background; +} + +//Takes in command line arguments for the window width and height as well +//as for the number of threads to use +int main(int argc, char* argv[]) { + int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); + int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Dithered Points"); + c.run(colorPointsFunction,t); +} diff --git a/src/tests/testColorPoints.cpp b/src/tests/testColorPoints.cpp deleted file mode 100644 index 668445bc9..000000000 --- a/src/tests/testColorPoints.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * testColorPoints.cpp - * - * Usage: ./testColorPoints - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a neat pattern of points to a Canvas using OMP and takes in a command line - * argument for the number of threads to use. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. - * - The actual number of threads created is stored in: \b nthreads . - * - The number of lines per thread is calculated and stored in: \b myPart . - * - The starting position of each given thread is calculated and stored in: \b myStart . - * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. - * - The color for a thread is calculated. - * - If the point's coordinate is even: - * - Draw a point on the Canvas in the thread's color. - * - Else: - * - Draw the point normally. - * . - * - The function breaks from the outer for loop if the Canvas is closed. - * . - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Number of threads to use. - */ -void colorPointsFunction(Canvas& can, int numberOfThreads) { - Rectangle *rec = new Rectangle(1,1,1,1,BLUE); - can.add(rec); - #pragma omp parallel num_threads(numberOfThreads) - { - int nthreads = omp_get_num_threads(); //Actual number of threads to use - int myPart = can.getWindowHeight() / nthreads + 1; - int myStart = myPart * omp_get_thread_num(); - for (int i = myStart; i < myStart + myPart; i++) { - for (int j = 0; j < can.getWindowWidth(); j++) { - // int id = omp_get_thread_num(); - if (i % 2 == 0) { - can.drawPoint(i, j, BLACK); - } else { - can.drawPoint(i, j, ColorInt(i % 255, j % 255, (i*j) % 255)); - } - } - if (!can.isOpen()) break; - } - } - can.remove(rec); - delete rec; -} - -//Takes in command line arguments for the window width and height as well -//as for the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Dithered Points"); - c.run(colorPointsFunction,t); -} diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index 117fb772f..ecf4a22c0 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -27,7 +27,7 @@ void imageFunction(Canvas& can) { // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); // can.add(image); - Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); can.add(image); Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); can.add(image2); @@ -57,7 +57,7 @@ void imageFunction(Canvas& can) { // image->setCenterY(sin(floatVal/90) * 100); // image->setCenterZ(sin(floatVal/90) * 100); // image->setYaw(floatVal); - image->setPitch(floatVal * 100); + // image->setPitch(floatVal * 100); // image->setRoll(floatVal); // image->setWidth(sin(floatVal/90) * 100 + 400); // image->setHeight(sin(floatVal/90) * 100 + 400); @@ -97,5 +97,6 @@ int main(int argc, char * argv[]) { w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; } Canvas c(-1, -1, w, h ,"Images"); + c.setBackgroundColor(WHITE); c.run(imageFunction); } From 9577f9d65b63ce3cd7bdcf1810ab4bdf69bd6272 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Fri, 10 Jul 2020 11:41:05 -0400 Subject: [PATCH 046/105] Basic framebuffer created (needs anti-aliasing) --- Makefile | 1 + src/TSGL/Background.cpp | 170 +++++++++++++++++++++++++---------- src/TSGL/Background.h | 16 +++- src/TSGL/Canvas.cpp | 171 ++++++++++++++++-------------------- src/TSGL/Canvas.h | 17 ++-- src/TSGL/Image.cpp | 4 - src/TSGL/Text.cpp | 3 - src/TSGL/TextureHandler.cpp | 1 - src/tests/testBG.cpp | 37 ++++++++ src/tests/testCube.cpp | 5 ++ src/tests/testImage.cpp | 2 +- src/tests/testSquare.cpp | 5 ++ src/tests/testText.cpp | 9 +- 13 files changed, 279 insertions(+), 162 deletions(-) create mode 100644 src/tests/testBG.cpp diff --git a/Makefile b/Makefile index 64d245c80..104c60aaa 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ BINARIES= \ bin/test3DPhilosophers \ bin/testArrows \ bin/testBackground \ + bin/testBG \ bin/testBallroom \ bin/testCircle \ bin/testClock \ diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp index bb0b74c31..9d4ef5b44 100644 --- a/src/TSGL/Background.cpp +++ b/src/TSGL/Background.cpp @@ -26,21 +26,17 @@ Background::Background(float x, float y, float z, GLint width, GLint height, flo myXScale = myWidth = width; myYScale = myHeight = height; vertices = new GLfloat[30]; - buffer = new uint8_t[myWidth * myHeight * 4]; vertices[0] = vertices[1] = vertices[6] = vertices[10] = vertices[16] = vertices[20] = -0.5; // x + y vertices[5] = vertices[11] = vertices[15] = vertices[21] = vertices[25] = vertices[26] = 0.5; // x + y vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = 0; // z vertices[3] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[29] = 0.0; // texture coord x + y vertices[4] = vertices[8] = vertices[9] = vertices[18] = vertices[19] = vertices[28] = 1.0; // texture coord x + y - // make original background monocolor - for (int j = 0; j < myHeight; j++) - for (int i = 0; i < myWidth; i++) { - buffer[i * myHeight * 4 + j * 4] = (int) (c.R * 255); - buffer[i * myHeight * 4 + j * 4 + 1] = (int) (c.G * 255); - buffer[i * myHeight * 4 + j * 4 + 2] = (int) (c.B * 255); - buffer[i * myHeight * 4 + j * 4 + 3] = (int) (c.A * 255); - } + myDrawables = new Array(myWidth * myHeight * 2); + + myAlpha = 1.0; + + // glBindFramebuffer(GL_FRAMEBUFFER, 0); init = true; attribMutex.unlock(); @@ -56,6 +52,55 @@ void Background::draw(Shader * shader) { return; } + // gen framebuffer + glGenFramebuffers(1, &myFramebuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFramebuffer); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + glViewport(0,0,myWidth,myHeight); + + // gen texture, attach to framebuffer + glGenTextures(1, &myTexture); + glBindTexture(GL_TEXTURE_2D, myTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, myWidth, myHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, myTexture, 0); + + // render buffer object + // glGenRenderbuffers(1, &myRenderbufferObject); + // glBindRenderbuffer(GL_RENDERBUFFER, myRenderbufferObject); + // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, myRenderbufferObject); // now actually attach it + + GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("ERROR::FRAMEBUFFER:: Framebuffer is not complete!"); + glClearColor(1,0,0,1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) + + for (unsigned int i = 0; i < myDrawables->size(); i++) + { + Drawable* d = (*myDrawables)[i]; + if(d->isProcessed()) { + selectShaders(d->getShaderType()); + if (d->getShaderType() == SHAPE_SHADER_TYPE) { + d->draw(shapeShader); + } else if (d->getShaderType() == TEXTURE_SHADER_TYPE) { + d->draw(textureShader); + } else if (d->getShaderType() == TEXT_SHADER_TYPE) { + d->draw(textShader); + } + } + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + selectShaders(TEXTURE_SHADER_TYPE); + glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); @@ -67,34 +112,20 @@ void Background::draw(Shader * shader) { unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - unsigned int alphaLoc = glGetUniformLocation(shader->ID, "alpha"); - glUniform1f(alphaLoc, 1.0f); - - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &myTexture); - // enable textures and bind the texture id - glBindTexture(GL_TEXTURE_2D, myTexture); - - // Set texture parameters for wrapping. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - // Set texture parameters for filtering. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // actually generate the texture + mipmaps - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, buffer); - glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, myTexture); // use the color attachment texture as the texture of the quad plane + glPixelStorei(GL_UNPACK_ALIGNMENT,4); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLES, 0, 6); + glFlush(); // Flush buffer data to the actual draw buffer - glDeleteTextures(1, &myTexture); - glDisable(GL_TEXTURE_2D); + glDeleteTextures(1, &myTexture); + glDeleteFramebuffers(1, &myFramebuffer); } /*! @@ -105,14 +136,7 @@ void Background::draw(Shader * shader) { * \return A ColorInt containing the color of the pixel at (col,row). */ ColorInt Background::getPixel(int row, int col) { - ColorInt c; - attribMutex.lock(); - c = ColorInt(buffer[(row * myWidth + col) * 4], - buffer[(row * myWidth + col) * 4 + 1], - buffer[(row * myWidth + col) * 4 + 2], - buffer[(row * myWidth + col) * 4 + 3]); - attribMutex.unlock(); - return c; + return ColorInt(0,0,0,255); } /*! @@ -125,18 +149,74 @@ ColorInt Background::getPixel(int row, int col) { */ void Background::drawPixel(int row, int col, ColorInt c) { attribMutex.lock(); - buffer[(row * myWidth + col) * 4] = c.R; - buffer[(row * myWidth + col) * 4 + 1] = c.G; - buffer[(row * myWidth + col) * 4 + 2] = c.B; - buffer[(row * myWidth + col) * 4 + 3] = c.A; + + attribMutex.unlock(); +} + +void Background::selectShaders(unsigned int sType) { + Shader * program = 0; + if (sType == TEXT_SHADER_TYPE) { + program = textShader; + // position attribute + GLint posAttrib = glGetAttribLocation(textShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } else if (sType == SHAPE_SHADER_TYPE) { + program = shapeShader; + // position attribute + GLint posAttrib = glGetAttribLocation(shapeShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + // texture coord attribute + GLint colAttrib = glGetAttribLocation(shapeShader->ID, "aColor"); + glEnableVertexAttribArray(colAttrib); + glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + } else if (sType == TEXTURE_SHADER_TYPE) { + program = textureShader; + GLint posAttrib = glGetAttribLocation(textureShader->ID, "aPos"); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + // texture coord attribute + GLint texAttrib = glGetAttribLocation(textureShader->ID, "aTexCoord"); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } + + program->use(); + + glm::mat4 projection = glm::perspective(glm::radians(60.0f), (float)myWidth/(float)myHeight, 0.1f, 1000.0f); + glm::mat4 view = glm::mat4(1.0f); + view = glm::translate(view, glm::vec3(0.0f, 0.0f, -((myHeight / 2) / tan(glm::pi()/6)))); + glm::mat4 model = glm::mat4(1.0f); + + glUniformMatrix4fv(glGetUniformLocation(program->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "view"), 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); +} + +void Background::defineShaders(Shader * shapeS, Shader * textS, Shader * textureS) { + attribMutex.lock(); + shapeShader = shapeS; + textShader = textS; + textureShader = textureS; attribMutex.unlock(); } +void Background::drawSquare(float z) { + Square * s = new Square(0,0,z,200,0,0,0,BLUE); + myDrawables->push(s); // Push it onto our drawing buffer +} + /*! * \brief Destructor for the Background. */ Background::~Background() { - delete [] buffer; + myDrawables->clear(); + delete myDrawables; } } \ No newline at end of file diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h index bb3edb3f9..2f9086369 100644 --- a/src/TSGL/Background.h +++ b/src/TSGL/Background.h @@ -6,6 +6,9 @@ #define BACKGROUND_H_ #include "Drawable.h" // For extending our Shape object +#include "Array.h" // Our own array for buffering drawing operations +#include "Square.h" +#include "Util.h" // Needed constants and has cmath for performing math operations namespace tsgl { @@ -17,7 +20,12 @@ class Background : public Drawable { protected: GLint myWidth, myHeight; GLuint myTexture; - uint8_t * buffer; + GLuint myFramebuffer; + GLuint myRenderbufferObject; + Array * myDrawables; + Shader * textShader; + Shader * shapeShader; + Shader * textureShader; public: Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c = WHITE); @@ -39,6 +47,12 @@ class Background : public Drawable { virtual void drawPixel(int row, int col, ColorInt c); + virtual void selectShaders(unsigned int sType); + + virtual void defineShaders(Shader * shapeS, Shader * textS, Shader * textureS); + + virtual void drawSquare(float z); + virtual ~Background(); }; diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index adf044cea..2a25ecca5 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -241,15 +241,19 @@ void Canvas::draw() // Get actual framebuffer size and adjust scaling accordingly // NOTE: framebuffer stuff seems purposeless, at least with pure OO on MacOS. - // int fbw, fbh; - // glfwGetFramebufferSize(window, &fbw, &fbh); - // int scaling = round((1.0f*fbw)/winWidth); + int fbw, fbh; + glfwGetFramebufferSize(window, &fbw, &fbh); + int scaling = round((1.0f*fbw)/winWidth); if (hasStereo) Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); else Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); + setBackgroundColor(bgcolor); //Set our initial clear / background color + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { drawTimer->sleep(true); @@ -267,10 +271,8 @@ void Canvas::draw() std::cout.flush(); // set it up so draw calls write into the framebuffer - // if (hasEXTFramebuffer) - // glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - // else - // glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer); + glEnable(GL_DEPTH_TEST); // glDrawBuffer(GL_COLOR_ATTACHMENT0); // Scale to window size @@ -312,14 +314,11 @@ void Canvas::draw() } // Update our screenBuffer copy with the screen - // glViewport(0,0,winWidth*scaling,winHeight*scaling); + glViewport(0,0,winWidth*scaling,winHeight*scaling); // set it up so TSGL reads from the framebuffer - // if (hasEXTFramebuffer) - // glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - // else - // glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - // glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer); + glReadBuffer(GL_COLOR_ATTACHMENT0); // screenshots and testing // read from the framebuffer into the screenbuffer @@ -330,30 +329,34 @@ void Canvas::draw() } // actually render everything in the framebuffer to the screen - // glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); + glDisable(GL_DEPTH_TEST); // glDrawBuffer(drawBuffer); - // selectShaders(true); - // const float vertices[36] = { - // 0, 0, 0,1,1,1,1,0,1, - // winWidth,0, 0,1,1,1,1,1,1, - // 0, winHeight,0,1,1,1,1,0,0, - // winWidth,winHeight,0,1,1,1,1,1,0 - // }; - // glBindTexture(GL_TEXTURE_2D,renderedTexture); - // /* these 5 lines don't seem to do anything */ - // glPixelStorei(GL_UNPACK_ALIGNMENT,4); - // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - // /* next two lines are very essential */ - // glBufferData(GL_ARRAY_BUFFER,36*sizeof(float),vertices,GL_DYNAMIC_DRAW); - // glDrawArrays(GL_TRIANGLE_STRIP,0,4); - // glFlush(); // Flush buffer data to the actual draw buffer - // glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - - // selectShaders(false); + selectShaders(TEXTURE_SHADER_TYPE); + + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + + const float vertices[30] = { + -winWidth/2,-winHeight/2,0,0,0, + winWidth/2,-winHeight/2,0,1,0, + -winWidth/2, winHeight/2,0,0,1, + winWidth/2,-winHeight/2,0,1,0, + -winWidth/2, winHeight/2,0,0,1, + winWidth/2, winHeight/2,0,1,1 + }; + glBindTexture(GL_TEXTURE_2D,renderedTexture); + /* these 5 lines don't seem to do anything */ + glPixelStorei(GL_UNPACK_ALIGNMENT,4); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + /* next two lines are very essential */ + glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES,0,6); + glFlush(); // Flush buffer data to the actual draw buffer // Update Screen glfwSwapBuffers(window); @@ -2085,16 +2088,6 @@ int Canvas::getWindowY() { void Canvas::glDestroy() { // Free up our resources - // glDetachShader(shaderProgram, shaderFragment); - // glDetachShader(shaderProgram, shaderVertex); - // glDeleteShader(shaderFragment); - // glDeleteShader(shaderVertex); - // glDeleteProgram(shaderProgram); - // glDetachShader(textureShaderProgram, textureShaderFragment); - // glDetachShader(textureShaderProgram, textureShaderVertex); - // glDeleteShader(textureShaderFragment); - // glDeleteShader(textureShaderVertex); - // glDeleteProgram(textureShaderProgram); delete textShader; delete shapeShader; delete textureShader; @@ -2205,12 +2198,9 @@ void Canvas::initGl() { glfwSetWindowUserPointer(window, this); #endif - // Specify how texture values combine with current surface color values. - // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_REPLACE - - glEnable(GL_TEXTURE_2D); // Enable and disable necessary stuff - glEnable(GL_DEPTH_TEST); // Depth Testing + // glEnable(GL_DEPTH_TEST); // Depth Testing + glDisable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDisable(GL_CULL_FACE); // glCullFace(GL_BACK); @@ -2243,17 +2233,6 @@ void Canvas::initGlew() { exit(102); } - // hasEXTFramebuffer = false; - - // GLint n, i; - // glGetIntegerv(GL_NUM_EXTENSIONS, &n); - // for (i = 0; i < n; i++) { - // std::string s = reinterpret_cast< char const * >(glGetStringi(GL_EXTENSIONS, i)); - // if (s == "GL_EXT_framebuffer_object") { - // hasEXTFramebuffer = true; - // break; - // } - // } const GLubyte* gfxVendor = glGetString(GL_VENDOR); std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); atiCard = (gfx.find("ATI") != std::string::npos); @@ -2265,12 +2244,8 @@ void Canvas::initGlew() { printf("GL Extension: "); for (i = 0; i < n; i++) printf("%s, ", glGetStringi(GL_EXTENSIONS, i)); - // if (hasEXTFramebuffer) - // TsglDebug("EXT Framebuffer available"); #endif - // GLint status; - // Create our Vertex Array Object glGenVertexArrays(1, &VAO); @@ -2297,35 +2272,35 @@ void Canvas::initGlew() { /****** NEW ******/ // Create a framebuffer - // frameBuffer = 0; - // glGenFramebuffersEXT(1, &frameBuffer); - // if (hasEXTFramebuffer) - // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); - // else - // glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBuffer); - // std::cout << glGetError() << std::endl; - // // The texture we're going to render to - // glGenTextures(1, &renderedTexture); - // // "Bind" the newly created texture : all future texture functions will modify this texture - // glBindTexture(GL_TEXTURE_2D, renderedTexture); - // // Give an empty image to OpenGL ( the last "0" ) - // // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems - // glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // // Poor filtering. Needed ! - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // // Set "renderedTexture" as our colour attachement #0 - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,renderedTexture, 0); - // // Set the list of draw buffers. - // GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - // glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - // // Always check that our framebuffer is ok - // if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - // TsglErr("FRAMEBUFFER CREATION FAILED"); - - // glBindFramebuffer(GL_FRAMEBUFFER, 0); + frameBuffer = 0; + glGenFramebuffers(1, &frameBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); + // The texture we're going to render to + glGenTextures(1, &renderedTexture); + // "Bind" the newly created texture : all future texture functions will modify this texture + glBindTexture(GL_TEXTURE_2D, renderedTexture); + // Give an empty image to OpenGL ( the last "0" ) + // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); + // Poor filtering. Needed ! + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // Set "renderedTexture" as our colour attachement #0 + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,renderedTexture, 0); + // Set the list of draw buffers. + + unsigned int rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, winWidth, winHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); } void Canvas::initGlfw() { @@ -2351,6 +2326,7 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window + glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); @@ -2741,7 +2717,7 @@ void Canvas::takeScreenShot() { } void Canvas::selectShaders(unsigned int sType) { - Shader * program; + Shader * program = 0; if (sType == TEXT_SHADER_TYPE) { program = textShader; // position attribute @@ -2810,6 +2786,11 @@ int Canvas::wait() { return 0; } +void Canvas::setBackground(Background * background) { + myBackground = background; + background->defineShaders(shapeShader, textShader, textureShader); +} + //-----------------Unit testing------------------------------------------------------- /*! * \brief Runs unit tests for the Canvas. diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 619476c80..49693e42b 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -97,10 +97,9 @@ class Canvas { unsigned bufferSize; // Size of the screen buffer std::string defaultFontFileName; Timer* drawTimer; // Timer to regulate drawing frequency - // GLuint frameBuffer; // Target buffer for rendering to renderedTexture + GLuint frameBuffer; // Target buffer for rendering to renderedTexture int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) bool hasBackbuffer; // Whether or not the hardware supports double-buffering - // bool hasEXTFramebuffer; // Whether or not the hard supports EXT FBOs bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice @@ -126,10 +125,7 @@ class Canvas { uint8_t* screenBuffer; // Array that is a copy of the screen GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window unsigned proceduralBufferSize; - doubleFunction scrollFunction; // Single function object for scrolling - // GLtexture shaderFragment, // Address of the fragment shader - // shaderProgram, // Addres of the shader program to send to the GPU - // shaderVertex; // Address of the vertex shader + doubleFunction scrollFunction; // Single function object for scrolling // Address of the vertex shader Shader * textShader; Shader * shapeShader; Shader * textureShader; @@ -138,10 +134,7 @@ class Canvas { bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread int syncMutexLocked; // Whether the syncMutex is currently locked - int syncMutexOwner; // Thread ID of the owner of the syncMutex - // GLtexture textureShaderFragment, // Address of the textured fragment shader - // textureShaderProgram, // Addres of the textured shader program to send to the GPU - // textureShaderVertex; // Address of the textured vertex shader + int syncMutexOwner; // Thread ID of the owner of the syncMutex // Address of the textured vertex shader bool toClose; // If the Canvas has been asked to close unsigned int toRecord; // To record the screen each frame GLint uniModel, // Model perspective of the camera @@ -164,6 +157,8 @@ class Canvas { static displayInfo monInfo; // Info about our display static unsigned openCanvases; // Total number of open Canvases + Background * myBackground; + static void buttonCallback(GLFWwindow* window, int key, int action, int mods); // GLFW callback for mouse buttons void draw(); // Draw loop for the Canvas @@ -450,6 +445,8 @@ class Canvas { int wait(); // static void runTests(); + + void setBackground(Background * background); }; } diff --git a/src/TSGL/Image.cpp b/src/TSGL/Image.cpp index f2d1fd87e..e56b91ea7 100644 --- a/src/TSGL/Image.cpp +++ b/src/TSGL/Image.cpp @@ -38,7 +38,6 @@ Image::Image(float x, float y, float z, std::string filename, GLfloat width, GLf stbi_set_flip_vertically_on_load(true); data = stbi_load(filename.c_str(), &pixelWidth, &pixelHeight, 0, 4); tsglAssert(data, "stbi_load(filename) failed."); - glEnable(GL_TEXTURE_2D); // vertex allocation and assignment vertices = new GLfloat[30]; @@ -83,7 +82,6 @@ void Image::draw(Shader * shader) { unsigned int alphaLoc = glGetUniformLocation(shader->ID, "alpha"); glUniform1f(alphaLoc, myAlpha); - glEnable(GL_TEXTURE_2D); glGenTextures(1, &myTexture); // enable textures and bind the texture id glBindTexture(GL_TEXTURE_2D, myTexture); @@ -106,8 +104,6 @@ void Image::draw(Shader * shader) { glDrawArrays(GL_TRIANGLES, 0, 6); glDeleteTextures(1, &myTexture); - - glDisable(GL_TEXTURE_2D); } /** diff --git a/src/TSGL/Text.cpp b/src/TSGL/Text.cpp index 05bb79f60..4186c16c6 100644 --- a/src/TSGL/Text.cpp +++ b/src/TSGL/Text.cpp @@ -78,8 +78,6 @@ void Text::draw(Shader * shader) { glUniform4f(glGetUniformLocation(shader->ID, "textColor"), myColor.R, myColor.G, myColor.B, myColor.A); - glEnable(GL_TEXTURE_2D); - float mouseX = -myWidth / 2; float mouseY = -myHeight / 2; const wchar_t* wideText = myString.c_str(); @@ -135,7 +133,6 @@ void Text::draw(Shader * shader) { // now advance cursors for next glyph (note that advance is number of 1/64 pixels) mouseX += (ch.Advance >> 6); // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) } - glDisable(GL_TEXTURE_2D); } /*! diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index b216befd7..2e7d9ffcd 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -441,7 +441,6 @@ GLtexture TextureHandler::loadPicture(std::string filename, unsigned int &width, // stbi_set_flip_vertically_on_load(true); // unsigned char * data = stbi_load(filename.c_str(), width, height, 0, 4); // tsglAssert(data, "stbi_load(filename) failed."); - // glEnable(GL_TEXTURE_2D); // // create the Image's texture id // glGenTextures(1, &texture); // glBindTexture(GL_TEXTURE_2D, texture); diff --git a/src/tests/testBG.cpp b/src/tests/testBG.cpp new file mode 100644 index 000000000..0b55619ef --- /dev/null +++ b/src/tests/testBG.cpp @@ -0,0 +1,37 @@ +/* + * testBG.cpp + * + * Usage: ./testBG + */ + +#include +#include + +using namespace tsgl; + +void squareFunction(Canvas& can) { + Background * bg = new Background(0,0,0, can.getWindowWidth(), can.getWindowHeight(), 0,0,0,WHITE); + // printf("draw square\n"); + // Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); + // can.add(cube); + bg->drawSquare(0); + can.setBackground(bg); + can.add(bg); + while (can.isOpen()) { + can.sleep(); + bg->setPitch(can.getFrameNumber()/50); + // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); + } + // delete cube; + delete bg; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Square"); + c.setBackgroundColor(BLACK); + c.run(squareFunction); +} \ No newline at end of file diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index 44907768b..b41374340 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -32,6 +32,7 @@ void cubeFunction(Canvas& can) { boolean = !boolean; }); + bool ss = false; while (can.isOpen()) { can.sleep(); // testCube->setCenterX(sin(rotation)*200); @@ -58,6 +59,10 @@ void cubeFunction(Canvas& can) { // boolean = !boolean; // rotation = 0; // } + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } rotation+=0.01; } diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp index ecf4a22c0..e38a07aa4 100644 --- a/src/tests/testImage.cpp +++ b/src/tests/testImage.cpp @@ -57,7 +57,7 @@ void imageFunction(Canvas& can) { // image->setCenterY(sin(floatVal/90) * 100); // image->setCenterZ(sin(floatVal/90) * 100); // image->setYaw(floatVal); - // image->setPitch(floatVal * 100); + image->setPitch(floatVal * 100); // image->setRoll(floatVal); // image->setWidth(sin(floatVal/90) * 100 + 400); // image->setHeight(sin(floatVal/90) * 100 + 400); diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp index 666c9999b..e58b677a7 100644 --- a/src/tests/testSquare.cpp +++ b/src/tests/testSquare.cpp @@ -26,6 +26,7 @@ void squareFunction(Canvas& can) { can.add(square2); float floatVal = 0.0f; GLfloat delta = 0.05; + bool ss = false; while (can.isOpen()) { can.sleep(); // square->setCenterX(sin(floatVal/90) * 100); @@ -44,6 +45,10 @@ void squareFunction(Canvas& can) { // } else { // square->setColor(RED); // } + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } floatVal += 1; } diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp index 7be03beb7..fc07072d1 100644 --- a/src/tests/testText.cpp +++ b/src/tests/testText.cpp @@ -30,9 +30,9 @@ void textFunction(Canvas& can, std::string font) { Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); can.add(uppercase); Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); - Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); + // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); can.add(random); - can.add(rec); + // can.add(rec); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { random->setText(L"Glorgaborg"); @@ -41,9 +41,14 @@ void textFunction(Canvas& can, std::string font) { // random->setFontSize(100); }); + bool ss = false; float rotation = 0.0f; while(can.isOpen()) { can.sleep(); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } // random->setCenterX(sin(rotation)*200); // random->setCenterY(cos(rotation)*200); // random->setCenterZ(sin(rotation)*100); From 01b29d4184bcf98880a95e2d060468b61ef82daf Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 13 Jul 2020 10:19:07 -0400 Subject: [PATCH 047/105] Small change to when screenshot occurs --- src/TSGL/Canvas.cpp | 29 ++++++++++++++--------------- src/tests/testCube.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 2a25ecca5..b38fc553a 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -313,21 +313,6 @@ void Canvas::draw() objectBufferEmpty = true; } - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - - // set it up so TSGL reads from the framebuffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // screenshots and testing - // read from the framebuffer into the screenbuffer - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); - if (toRecord > 0) { - screenShot(); - --toRecord; - } - // actually render everything in the framebuffer to the screen glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); glDisable(GL_DEPTH_TEST); @@ -358,6 +343,20 @@ void Canvas::draw() glDrawArrays(GL_TRIANGLES,0,6); glFlush(); // Flush buffer data to the actual draw buffer + // Update our screenBuffer copy with the screen + glViewport(0,0,winWidth*scaling,winHeight*scaling); + + // set it up so TSGL reads from the framebuffer + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // screenshots and testing + // read from the framebuffer into the screenbuffer + glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); + if (toRecord > 0) { + screenShot(); + --toRecord; + } + // Update Screen glfwSwapBuffers(window); diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp index b41374340..3994dcd81 100644 --- a/src/tests/testCube.cpp +++ b/src/tests/testCube.cpp @@ -59,10 +59,10 @@ void cubeFunction(Canvas& can) { // boolean = !boolean; // rotation = 0; // } - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } + if (can.getFrameNumber() > 50 && !ss) { + can.takeScreenShot(); + ss = true; + } rotation+=0.01; } From bd1844f730990b9eeee4972425fc5fab36c89691 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 13 Jul 2020 11:18:33 -0400 Subject: [PATCH 048/105] Multisample framebuffer render w/ intermediate FBO --- src/TSGL/Canvas.cpp | 51 +++++++++++++++++++++++++-------------------- src/TSGL/Canvas.h | 6 ++++-- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index b38fc553a..5acadf9f0 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -271,9 +271,9 @@ void Canvas::draw() std::cout.flush(); // set it up so draw calls write into the framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, multisampledFBO); glEnable(GL_DEPTH_TEST); - // glDrawBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); // Scale to window size GLint windowWidth, windowHeight; @@ -313,10 +313,13 @@ void Canvas::draw() objectBufferEmpty = true; } + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, winWidth, winHeight, 0, 0, winWidth, winHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + // actually render everything in the framebuffer to the screen glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); glDisable(GL_DEPTH_TEST); - // glDrawBuffer(drawBuffer); selectShaders(TEXTURE_SHADER_TYPE); @@ -2269,32 +2272,34 @@ void Canvas::initGlew() { textureShader = new Shader(textureVertexShader, textureFragmentShader); - /****** NEW ******/ - // Create a framebuffer - frameBuffer = 0; - glGenFramebuffers(1, &frameBuffer); - glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); + // configure MSAA framebuffer + // -------------------------- + glGenFramebuffers(1, &multisampledFBO); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + // create a multisampled color attachment texture + glGenTextures(1, &multisampledTexture); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, winWidth, winHeight, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); + // create multisampled renderbuffer object + unsigned int rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, winWidth, winHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it + + // Create a second framebuffer + intermediateFBO = 0; + glGenFramebuffers(1, &intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); // The texture we're going to render to glGenTextures(1, &renderedTexture); - // "Bind" the newly created texture : all future texture functions will modify this texture glBindTexture(GL_TEXTURE_2D, renderedTexture); - // Give an empty image to OpenGL ( the last "0" ) - // Note: Using RGBA here creates a texture with alpha, which causes weird redrawing problems - glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth+1, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // Poor filtering. Needed ! - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); // Set "renderedTexture" as our colour attachement #0 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,renderedTexture, 0); - // Set the list of draw buffers. - unsigned int rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, winWidth, winHeight); // use a single renderbuffer object for both a depth AND stencil buffer. - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it // Always check that our framebuffer is ok if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) TsglErr("FRAMEBUFFER CREATION FAILED"); diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 49693e42b..23ecba6e8 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -97,7 +97,8 @@ class Canvas { unsigned bufferSize; // Size of the screen buffer std::string defaultFontFileName; Timer* drawTimer; // Timer to regulate drawing frequency - GLuint frameBuffer; // Target buffer for rendering to renderedTexture + GLuint multisampledFBO; // Multisampled target buffer for rendering to renderedTexture + GLuint intermediateFBO; // Intermediate framebuffer into which multisampledFBO will be blitted int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) bool hasBackbuffer; // Whether or not the hardware supports double-buffering bool hasStereo; // Whether or not the hardware supports stereoscopic rendering @@ -116,7 +117,8 @@ class Canvas { unsigned int pointBufferPosition, pointLastPosition; // Holds the position of the allPoints array bool readyToDraw; // Whether a Canvas is ready to start drawing int realFPS; // Actual FPS of drawing - GLuint renderedTexture; // Texture to which we render to every frame + GLuint renderedTexture; // Texture to which we render to every frame. Attached to intermediateFBO + GLuint multisampledTexture; // Texture attached to the multisampled framebuffer #ifdef __APPLE__ pthread_t renderThread; // Thread dedicated to rendering the Canvas #else From 1cf4f544b3182f7703f53a83372e5e342c1abd6d Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 09:10:20 -0400 Subject: [PATCH 049/105] Add files via upload --- install-cygwin.sh | 236 ++++++++++++++++++++++++++++++++++++++++++++++ uninstall-cygwin | 16 ++++ 2 files changed, 252 insertions(+) create mode 100644 install-cygwin.sh create mode 100644 uninstall-cygwin diff --git a/install-cygwin.sh b/install-cygwin.sh new file mode 100644 index 000000000..6a6f829b4 --- /dev/null +++ b/install-cygwin.sh @@ -0,0 +1,236 @@ +#!/bin/bash +# +# install-cygwin.sh is the installation script for TSGL on Cygwin. +# Last updated: 07/09/2020 +# +# -SUBJECT TO CHANGE- +################################################################ + +echo "Installing TSGL..." + +# # Ensure all necessary packages are installed + +# echo +# echo "Checking dependencies..." + +# DepsList="xorg-server xinit xeyes libGL1 libGL-devel +# glm-devel libglut-devel libglut3 libfreetype6 glew +# libGLEW-devel openmpi libfreetype-doc doxygen-doxywizard +# libopenmpi-devel libopenmpi12 libopenmpicxx1 +# cmake libXrandr-devel libXinerama-devel libXcursor-devel +# libXi-devel" + +# sort $DepsList + +# for i in $DepsList; do +# echo "$i" +# done + +# echo "Checking X server dependencies..." + +# InstalledPackages=$(cygcheck -c xorg-server xinit xeyes | sed '^x.') + +# for i in $InstalledPackages; do +# echo "$i" +# done + +# UninstalledPackages="" + +# echo "Packages required: " + +# # Output needed packages +# for i in $UninstalledPackages; do +# echo "$i" +# done + +# Get list of dependencies currently installed +# GCCVersInfo=$(cygcheck -c | grep "gcc-g++") +# GLVersString=$(echo "$GCCVersInfo" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# echo $GLVersString + +# GLVersInfo=$(cygcheck -c | grep OpenGL) + +# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex +# #Get a string containing the version number. +# GLVersString=$(echo "$GLVersInfo" | grep "OpenGL version string: ") + +# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers +# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed +# #Get the version number from the version string. +# GLVersNum=$(echo "$GLVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# #http://tldp.org/LDP/abs/html/comparison-ops.html +# #Check if the version is less than the threshold +# if [ "$GLVersNum" \< "3.0" ] +# then +# echo "Your version of GL is: $GLVersNum." +# echo "You need at least OpenGL version 3.0 or greater." +# echo "Please update your drivers in order to continue." +# echo "Try the following command to update your drivers:" +# echo +# echo "ubuntu-drivers autoinstall" +# echo +# echo "Abort." +# exit 1 +# else +# echo "OpenGL version is sufficient to continue." +# fi + +# echo "Checking for g++..." + +# echo + +# gVersCheck=$(g++ --version) + +# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex +# #Get a string containing the version number. +# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") + +# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers +# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed +# #Get the version number from the version string. +# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# #http://tldp.org/LDP/abs/html/comparison-ops.html +# #Check if the version number is null... +# if [ -z "$gVersNum" ] +# then +# #Yep. g++ is NOT installed. +# echo "g++ not installed!" +# echo "Installing g++..." +# apt-get install g++ + +# #Update versioning info +# gVersCheck=$(g++ --version) + +# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") + +# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers +# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed +# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# else + +# echo "g++ already installed." + +# #No. Check the version. +# if [ "$gVersNum" \< "4.8" ] +# then +# echo "The version of g++ is: $gVersNum." +# echo "You need at least g++ 4.8 or greater in order to continue." +# echo "I can install a greater version of g++ for you." +# echo "Would you like me to do that? (1 = Yes, 2 = No)" +# #Adapted from: http://stackoverflow.com/questions/226703/how-do-i-prompt-for-input-in-a-linux-shell-script +# #Get the choice from the user. +# select choice in "Yes" "No"; do +# case $choice in +# Yes ) #Yes, so... +# echo "Installing a greater version of g++ (4.9)..." + +# #Get g++-4.9 on the machine +# add-apt-repository ppa:ubuntu-toolchain-r/test; +# apt-get update; +# apt-get install --yes --force-yes g++-4.9; +# unlink /usr/bin/g++; #Take out any symlink made before... +# ln -s /usr/bin/g++-4.9 /usr/bin/g++; + +# #Update version info +# gVersCheck=$(g++ --version) + +# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex +# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") + +# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers +# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed +# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# break;; +# No ) #No, use the current version +# echo "Cannot continue without g++ 4.8 or greater." +# echo "Abort." +# exit 1 +# esac +# done + +# else +# #Version number is okay +# echo "g++ version is sufficient to continue." + +# #Check if version number is NOT 4.9 +# if [ "$gVersNum" \< "4.9" ] +# then +# echo "You have $gVersNum installed." +# echo "Would you like me to install g++-4.9? (1 = Yes, 2 = No)" +# select choice in "Yes" "No"; do +# case $choice in +# Yes ) #Yes, so... + +# echo "Installing g++-4.9..." + +# #Get g++-4.9 on the machine +# add-apt-repository ppa:ubuntu-toolchain-r/test; +# apt-get update; +# apt-get install --yes --force-yes g++-4.9; +# unlink /usr/bin/g++; #Take out any symlink made before... +# ln -s /usr/bin/g++-4.9 /usr/bin/g++; + +# #Update version info +# gVersCheck=$(g++ --version) + +# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex +# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") + +# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers +# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed +# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') + +# break;; +# No ) #No, use the current version +# echo "Proceeding with $gVersNum."; +# break;; +# esac +# done +# fi + +# fi +# fi + +# echo + + + + + + + +#Dependencies were installed! (GLEW and glfw, as well as g++) +echo "All dependencies resolved!" + +echo + +echo "Begin installation of TSGL..." + +echo + +#Clean install = remove the TSGL folder and lib files if they already exist +rm -rf /usr/local/include/TSGL +rm -rf /usr/local/lib/libtsgl.* + +#Create the following directories (Since they aren't included in github but are needed) +mkdir -p lib bin + +#Make the library +make + +#Install it +make install + +#Take out the .cpp files from the TSGL library package folder +rm -rf /usr/local/include/TSGL/*.cpp + +#Done +echo "Installation complete! Execute the runtests bash script to verify that everything works!" + +echo + diff --git a/uninstall-cygwin b/uninstall-cygwin new file mode 100644 index 000000000..bc8a7d692 --- /dev/null +++ b/uninstall-cygwin @@ -0,0 +1,16 @@ +#!/bin/sh + +#make clean +make clean + +#Take out the lib and bin folders +rm -rf bin lib + +#Take out the TSGL lib.a and lib.so files +rm /usr/local/lib/libtsgl.* + +#Take out the TSGL folder containing the .h files +rm -rf /usr/local/include/TSGL + +#Done. +echo "\n Uninstall complete!\n" From b6b53a9a694ff869236f7a78f8e5ee25b6b748ac Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 09:11:18 -0400 Subject: [PATCH 050/105] Update install-cygwin.sh --- install-cygwin.sh | 205 +--------------------------------------------- 1 file changed, 1 insertion(+), 204 deletions(-) diff --git a/install-cygwin.sh b/install-cygwin.sh index 6a6f829b4..bfe19f7b2 100644 --- a/install-cygwin.sh +++ b/install-cygwin.sh @@ -1,216 +1,13 @@ #!/bin/bash # # install-cygwin.sh is the installation script for TSGL on Cygwin. -# Last updated: 07/09/2020 +# Last updated: 07/14/2020 # # -SUBJECT TO CHANGE- ################################################################ echo "Installing TSGL..." -# # Ensure all necessary packages are installed - -# echo -# echo "Checking dependencies..." - -# DepsList="xorg-server xinit xeyes libGL1 libGL-devel -# glm-devel libglut-devel libglut3 libfreetype6 glew -# libGLEW-devel openmpi libfreetype-doc doxygen-doxywizard -# libopenmpi-devel libopenmpi12 libopenmpicxx1 -# cmake libXrandr-devel libXinerama-devel libXcursor-devel -# libXi-devel" - -# sort $DepsList - -# for i in $DepsList; do -# echo "$i" -# done - -# echo "Checking X server dependencies..." - -# InstalledPackages=$(cygcheck -c xorg-server xinit xeyes | sed '^x.') - -# for i in $InstalledPackages; do -# echo "$i" -# done - -# UninstalledPackages="" - -# echo "Packages required: " - -# # Output needed packages -# for i in $UninstalledPackages; do -# echo "$i" -# done - -# Get list of dependencies currently installed -# GCCVersInfo=$(cygcheck -c | grep "gcc-g++") -# GLVersString=$(echo "$GCCVersInfo" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# echo $GLVersString - -# GLVersInfo=$(cygcheck -c | grep OpenGL) - -# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex -# #Get a string containing the version number. -# GLVersString=$(echo "$GLVersInfo" | grep "OpenGL version string: ") - -# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers -# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed -# #Get the version number from the version string. -# GLVersNum=$(echo "$GLVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# #http://tldp.org/LDP/abs/html/comparison-ops.html -# #Check if the version is less than the threshold -# if [ "$GLVersNum" \< "3.0" ] -# then -# echo "Your version of GL is: $GLVersNum." -# echo "You need at least OpenGL version 3.0 or greater." -# echo "Please update your drivers in order to continue." -# echo "Try the following command to update your drivers:" -# echo -# echo "ubuntu-drivers autoinstall" -# echo -# echo "Abort." -# exit 1 -# else -# echo "OpenGL version is sufficient to continue." -# fi - -# echo "Checking for g++..." - -# echo - -# gVersCheck=$(g++ --version) - -# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex -# #Get a string containing the version number. -# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") - -# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers -# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed -# #Get the version number from the version string. -# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# #http://tldp.org/LDP/abs/html/comparison-ops.html -# #Check if the version number is null... -# if [ -z "$gVersNum" ] -# then -# #Yep. g++ is NOT installed. -# echo "g++ not installed!" -# echo "Installing g++..." -# apt-get install g++ - -# #Update versioning info -# gVersCheck=$(g++ --version) - -# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") - -# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers -# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed -# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# else - -# echo "g++ already installed." - -# #No. Check the version. -# if [ "$gVersNum" \< "4.8" ] -# then -# echo "The version of g++ is: $gVersNum." -# echo "You need at least g++ 4.8 or greater in order to continue." -# echo "I can install a greater version of g++ for you." -# echo "Would you like me to do that? (1 = Yes, 2 = No)" -# #Adapted from: http://stackoverflow.com/questions/226703/how-do-i-prompt-for-input-in-a-linux-shell-script -# #Get the choice from the user. -# select choice in "Yes" "No"; do -# case $choice in -# Yes ) #Yes, so... -# echo "Installing a greater version of g++ (4.9)..." - -# #Get g++-4.9 on the machine -# add-apt-repository ppa:ubuntu-toolchain-r/test; -# apt-get update; -# apt-get install --yes --force-yes g++-4.9; -# unlink /usr/bin/g++; #Take out any symlink made before... -# ln -s /usr/bin/g++-4.9 /usr/bin/g++; - -# #Update version info -# gVersCheck=$(g++ --version) - -# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex -# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") - -# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers -# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed -# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# break;; -# No ) #No, use the current version -# echo "Cannot continue without g++ 4.8 or greater." -# echo "Abort." -# exit 1 -# esac -# done - -# else -# #Version number is okay -# echo "g++ version is sufficient to continue." - -# #Check if version number is NOT 4.9 -# if [ "$gVersNum" \< "4.9" ] -# then -# echo "You have $gVersNum installed." -# echo "Would you like me to install g++-4.9? (1 = Yes, 2 = No)" -# select choice in "Yes" "No"; do -# case $choice in -# Yes ) #Yes, so... - -# echo "Installing g++-4.9..." - -# #Get g++-4.9 on the machine -# add-apt-repository ppa:ubuntu-toolchain-r/test; -# apt-get update; -# apt-get install --yes --force-yes g++-4.9; -# unlink /usr/bin/g++; #Take out any symlink made before... -# ln -s /usr/bin/g++-4.9 /usr/bin/g++; - -# #Update version info -# gVersCheck=$(g++ --version) - -# #http://stackoverflow.com/questions/18147884/shell-variable-in-a-grep-regex -# gVersString=$(echo "$gVersCheck" | grep "g++ (Ubuntu *") - -# #http://stackoverflow.com/questions/7516455/sed-extract-version-number-from-string-only-version-without-other-numbers -# #http://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed -# gVersNum=$(echo "$gVersString" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') - -# break;; -# No ) #No, use the current version -# echo "Proceeding with $gVersNum."; -# break;; -# esac -# done -# fi - -# fi -# fi - -# echo - - - - - - - -#Dependencies were installed! (GLEW and glfw, as well as g++) -echo "All dependencies resolved!" - -echo - -echo "Begin installation of TSGL..." - echo #Clean install = remove the TSGL folder and lib files if they already exist From 021630a99552d0558c9687ed9e0e5c65321ff431 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 10:30:48 -0400 Subject: [PATCH 051/105] Add files via upload --- Makefile | 202 +++++++++++++++++++--------------------------------- runexamples | 33 +++++++++ runtests | 86 ++++++++++------------ 3 files changed, 144 insertions(+), 177 deletions(-) create mode 100644 runexamples diff --git a/Makefile b/Makefile index 104c60aaa..8e245b684 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,8 @@ +# Master Makefile for TSGL + +# ***************************************************** +# Variables to control Makefile operation + AR=ar CC=g++ RM=rm -f @@ -6,14 +11,13 @@ PREFIX=/usr/local SRC_PATH=src/TSGL/ TESTS_PATH=src/tests/ +EXAMPLES_PATH=src/examples/ OBJ_PATH=build/ VPATH=SRC_PATH:TESTS_PATH:OBJ_PATH HEADERS := $(wildcard src/TSGL/*.h) SOURCES := $(wildcard src/TSGL/*.cpp) -TESTS := $(wildcard src/tests/*.cpp) OBJS := $(patsubst src/TSGL/%.cpp,build/TSGL/%.o,${SOURCES}) -TESTOBJS := $(patsubst src/tests/%.cpp,build/tests/%.o,${TESTS}) NOWARN := -Wno-unused-parameter -Wno-unused-function -Wno-narrowing UNAME := $(shell uname) @@ -21,16 +25,27 @@ ifeq ($(UNAME), Linux) OS_LFLAGS := -lpthread OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ OS_EXTRA_LIB := -L/usr/lib - OS_GLFW := glfw OS_GL := -lGL + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x +endif + +ifeq ($(UNAME), CYGWIN_NT-10.0) + OS_LFLAGS := -lpthread + OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ + OS_EXTRA_LIB := -L/usr/lib + OS_GL := -lGL + OS_OMP := -lgomp -fopenmp + OS_COMPILER := -std=gnu++11 endif ifeq ($(UNAME), Darwin) OS_LFLAGS := -framework Cocoa -framework OpenGl -framework IOKit -framework Corevideo OS_LDIRS := OS_EXTRA_LIB := - OS_GLFW := glfw OS_GL := + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x endif CXXFLAGS=-O3 -g3 -ggdb3 \ @@ -49,7 +64,7 @@ CXXFLAGS=-O3 -g3 -ggdb3 \ -I/usr/include/freetype2 \ -I/usr/include/freetype2/freetype \ -I./ \ - -std=c++0x -fopenmp \ + $(OS_COMPILER) -fopenmp \ ${NOWARN} -fpermissive # -pedantic-errors @@ -58,99 +73,44 @@ LFLAGS=-Llib/ \ ${OS_EXTRA_LIB} \ -L/usr/X11/lib/ \ ${OS_LDIRS} \ - -ltsgl -lfreetype -lGLEW -lglfw -l${OS_GLFW} \ - -lX11 ${OS_GL} -lXrandr -Xpreprocessor -fopenmp -lomp -I"$(brew --prefix libomp)/include" \ + -ltsgl -lfreetype -lGLEW -lglfw \ + -lX11 ${OS_GL} -lXrandr -Xpreprocessor $(OS_OMP) -I"$(brew --prefix libomp)/include" \ ${OS_LFLAGS} DEPFLAGS=-MMD -MP -BINARIES= \ - bin/test2Dvs3D \ - bin/test3DRotation \ - bin/test3DPhilosophers \ - bin/testArrows \ - bin/testBackground \ - bin/testBG \ - bin/testBallroom \ - bin/testCircle \ - bin/testClock \ - bin/testCone \ - bin/testConvexPolygon \ - bin/testConcavePolygon \ - bin/testCube \ - bin/testCuboid \ - bin/testCylinder \ - bin/testDiorama \ - bin/testEllipse \ - bin/testEllipsoid \ - bin/testImage \ - bin/testLines \ - bin/testMergeSort \ - bin/testNewtonPendulum \ - bin/testPhilosophers \ - bin/testPong \ - bin/testPrism \ - bin/testPyramid \ - bin/testRectangle \ - bin/testRegularPolygon \ - bin/testShakerSort \ - bin/testSeaUrchin \ - bin/testSolarSystem \ - bin/testSphere \ - bin/testSquare \ - bin/testStar \ - bin/testText \ - bin/testTransparency \ - bin/testTriangle \ - bin/testTriangleStrip \ -# bin/test_specs \ -# bin/testAlphaRectangle \ -# bin/testAura \ -# bin/testBlurImage \ -# bin/testCalcPi \ -# bin/testColorWheel \ -# bin/testConstructors \ -# bin/testConway \ -# bin/testCosineIntegral \ -# bin/testDice \ -# bin/testFireworks \ -# bin/testForestFire \ -# bin/testFunction \ -# bin/testGetPixels \ -# bin/testGradientWheel \ -# bin/testGraydient \ -# bin/testGreyscale \ -# bin/testHighData \ -# bin/testImageCart \ -# bin/testInverter \ -# bin/testLangton \ -# bin/testLineChain \ -# bin/testLineFan \ -# bin/testMandelbrot \ -# bin/testMouse \ -# bin/testProducerConsumer \ -# bin/testProgressBar \ -# bin/testProjectiles \ -# bin/testReaderWriter \ -# bin/testScreenshot \ -# bin/testSpectrogram \ -# bin/testSpectrum \ -# bin/testTextCart \ -# bin/testTextTwo \ -# bin/testUnits \ -# bin/testVoronoi +TESTFLAGS = -lsrc/TSGL/ + +# **************************************************** +# Targets needed to bring all files up to date #Use make tsgl to make only the library files -all: dif tsgl tests docs tutorial +all: dif tsgl docs tutorial debug: dif tsgl tests dif: build/build #This may change (for the Mac installer)! +#tsgl +ifeq ($(UNAME), Linux) +tsgl: lib/libtsgl.a lib/libtsgl.so +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +tsgl: lib/libtsgl.a lib/libtsgl.dll +endif +ifeq ($(UNAME), Darwin) tsgl: lib/libtsgl.a lib/libtsgl.so +endif -tests: ${BINARIES} +# must run 'make' before 'make tests' and 'make examples' +tests: $(TESTS_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build + +examples: $(EXAMPLES_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build docs: docs/html/index.html @@ -160,12 +120,16 @@ cleanall: clean cleandocs clean: $(RM) -r bin/* build/* lib/* tutorial/docs/html/* *~ *# *.tmp + (cd $(TESTS_PATH) && $(MAKE) clean) + (cd $(EXAMPLES_PATH) && $(MAKE) clean) cleandocs: $(RM) -r docs/html/* # -include build/*.d +#install +ifeq ($(UNAME), Linux) install: test -d $(PREFIX) || mkdir $(PREFIX) test -d $(PREFIX)/lib || mkdir $(PREFIX) @@ -173,18 +137,43 @@ install: install -m 0644 lib/libtsgl.a $(PREFIX)/lib install -m 0755 lib/libtsgl.so $(PREFIX)/lib cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.dll $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), Darwin) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.so $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif build/build: ${HEADERS} ${SOURCES} ${TESTS} @echo 'Files that changed:' @echo $(patsubst src/%,%,$?) +#lib/libtsgl.* ifeq ($(UNAME), Linux) lib/libtsgl.so: ${OBJS} @echo 'Building $(patsubst lib/%,%,$@)' $(CC) -shared -o $@ $? @touch build/build endif - +ifeq ($(UNAME), CYGWIN_NT-10.0) +lib/libtsgl.dll: ${OBJS} + @echo 'Building $(patsubst lib/%,%,$@)' + $(CC) -shared -o $@ $? $(LFLAGS) + @touch build/build +endif ifeq ($(UNAME), Darwin) lib/libtsgl.so: ${OBJS} @echo 'Building $(pathsubst lib/%,%,$@)' @@ -198,46 +187,6 @@ lib/libtsgl.a: ${OBJS} $(AR) -r $@ $? @touch build/build -#List additional dependencies for test binaries -bin/test3DPhilosophers: build/tests/DiningPhilosophers3D/Philosopher3D.o \ - build/tests/DiningPhilosophers3D/Table3D.o -bin/testConway: build/tests/Conway/LifeFarm.o -bin/testFireworks: build/tests/Fireworks/Arc.o \ - build/tests/Fireworks/Dot.o \ - build/tests/Fireworks/Firework.o -bin/testInverter: build/tests/ImageInverter/ImageInverter.o -bin/testLangton: build/tests/Langton/AntFarm.o build/tests/Langton/LangtonAnt.o -bin/testMandelbrot: build/tests/Mandelbrot/Mandelbrot.o \ - build/tests/Mandelbrot/GradientMandelbrot.o \ - build/tests/Mandelbrot/Buddhabrot.o \ - build/TSGL/VisualTaskQueue.o \ - build/tests/Mandelbrot/Julia.o \ - build/tests/Mandelbrot/Nova.o -bin/testPhilosophers: build/tests/DiningPhilosophers/Philosopher.o \ - build/tests/DiningPhilosophers/Table.o -bin/testPong: build/tests/Pong/Pong.o build/tests/Pong/Paddle.o build/tests/Pong/Ball.o -bin/testProducerConsumer: build/tests/ProducerConsumer/Producer.o \ - build/tests/ProducerConsumer/Consumer.o \ - build/tests/ProducerConsumer/Thread.o \ - build/tests/ProducerConsumer/PCThread.o -bin/testReaderWriter: build/tests/ReaderWriter/FLock.o \ - build/tests/ReaderWriter/Lock.o \ - build/tests/ReaderWriter/Reader.o \ - build/tests/ReaderWriter/RLock.o \ - build/tests/ReaderWriter/RWThread.o \ - build/tests/ReaderWriter/Thread.o \ - build/tests/ReaderWriter/WLock.o \ - build/tests/ReaderWriter/Writer.o -bin/testSeaUrchin: build/tests/SeaUrchin/SeaUrchin.o -bin/testVoronoi: build/tests/Voronoi/Voronoi.o build/tests/Voronoi/ShadedVoronoi.o - -#General compilation recipes for test binaries (appended to earlier dependencies) -bin/test%: build/tests/test%.o lib/libtsgl.a - mkdir -p bin - @echo 'Building $(patsubst bin/%,%,$@)' - $(CC) $^ -o $@ $(LFLAGS) - @touch build/build - build/%.o: src/%.cpp @echo "" @tput setaf 3; @@ -248,7 +197,6 @@ build/%.o: src/%.cpp $(CC) -c -fpic $(CXXFLAGS) $(DEPFLAGS) -o "$@" "$<" - #Doxygen stuff docs/html/index.html: ${HEADERS} doxyfile @echo "" @@ -268,5 +216,5 @@ tutorial/docs/html/index.html: ${HEADERS} tutDoxyFile mkdir -p tutorial/docs doxygen tutDoxyFile -.PHONY: all debug clean tsgl tests docs tutorial dif +.PHONY: all debug clean tsgl docs tutorial dif .SECONDARY: ${OBJS} ${TESTOBJS} $(OBJS:%.o=%.d) diff --git a/runexamples b/runexamples new file mode 100644 index 000000000..bc53f64a1 --- /dev/null +++ b/runexamples @@ -0,0 +1,33 @@ +#!/bin/bash + +run () { + echo "" + tput setaf 2 + echo "Running $@" + tput sgr0 + echo "" + $@ +} + +export LD_LIBRARY_PATH=lib # Make sure we load the TSGL library +cd src/examples # CD into the examples directory +make # create example binaries +cd ../.. # CD back to main TSGL directory + +EXAMPLES_PATH=src/examples + +# RUN EXAMPLES +run ./$EXAMPLES_PATH/Ballroom/testBallroom +run ./$EXAMPLES_PATH/Clock/testClock +run ./$EXAMPLES_PATH/DiningPhilosophers/testPhilosophers +run ./$EXAMPLES_PATH/DiningPhilosophers3D/test3DPhilosophers +run ./$EXAMPLES_PATH/MergeSort/testMergeSort +run ./$EXAMPLES_PATH/NewtonPendulum/testNewtonPendulum 900 400 11 # Width, Height, Number Of Balls +run ./$EXAMPLES_PATH/Pong/testPong +run ./$EXAMPLES_PATH/SeaUrchin/testSeaUrchin 16 # Threads +run ./$EXAMPLES_PATH/ShakerSort/testShakerSort +run ./$EXAMPLES_PATH/SolarSystem/testSolarSystem +run ./$EXAMPLES_PATH/ArrayBubbleSort/testArrayBubbleSort +run ./$EXAMPLES_PATH/ArrayShakerSort/testArrayShakerSort +run ./$EXAMPLES_PATH/ThreadedArrayAddition/testThreadedArrayAddition +run ./$EXAMPLES_PATH/ThreadedArrayOperations/testThreadedArrayOperations \ No newline at end of file diff --git a/runtests b/runtests index a184fc40f..b437c153f 100755 --- a/runtests +++ b/runtests @@ -1,57 +1,43 @@ #!/bin/bash +# Note: tests must be run from the main TSGL directory, otherwise fonts and images won't load. + run () { - echo "$@" + echo "" + tput setaf 2 + echo "Running $@" + tput sgr0 + echo "" $@ } -export LD_LIBRARY_PATH=../lib #Make sure we load the TSGL library -cd bin #CD into our binary directory +TESTS_PATH=src/tests +export LD_LIBRARY_PATH=../lib # Make sure we load the TSGL library +cd src/tests && make # CD into test directory and call test Makefile +cd ../.. # CD back to main TSGL directory -run ./testAlphaRectangle 640 480 #Width, Height -run ./testArrows -run ./testAura 1200 900 8 #Width, Height, Segments -run ./testBallroom 640 640 #Width, Height -run ./testBlurImage 36 ../assets/pics/HDR_landscape.jpg #Threads, Image -run ./testCalcPi 100 4 #Segments, Threads -run ./testColorPoints 1000 1000 4 #Width, Height, Threads -run ./testColorWheel 640 640 64 #Width, Height, Threads -run ./testConcavePolygon #Width, Height -run ./testConstructors -run ./testConway 640 640 #Width, Height -run ./testCosineIntegral 640 480 32 #Width, Height, Threads -run ./testDumbSort 1200 600 #Width, Height -run ./testFireworks 800 800 4 50 10 #Width, Height, Threads, Fireworks, Speed -run ./testForestFire 800 600 #Width, Height -run ./testFunction 640 480 #Width, Height -run ./testGetPixels 4 #Threads -run ./testGradientWheel 640 640 256 #Width, Height, Threads -run ./testGraydient 400 400 8 #Width, Height, Threads -run ./testGreyscale 640 480 8 #Width, Height, Threads -run ./testHighData 1200 900 4 #Width, Height, Threads -run ./testImage 1200 600 #Width, Height -run ./testImageCart 1200 600 #Width, Height -run ./testInverter 8 #Threads -run ./testLangton 640 640 #Width, Height -run ./testLineChain 400 400 8 #Width, Height, Threads -run ./testLineFan 800 800 16 #Width, Height, Threads -run ./testMandelbrot 1200 900 8 255 #Width, Height, Threads, Depth -run ./testMouse 900 900 5 #Width, Height, Threads -run ./testNewtonPendulum 900 400 11 #Width, Height, Number Of Balls -run ./testPhilosophers 5 10 #Philosophers, Speed -run ./testPong 7 4 #Ball Speed, Paddle Speed -run ./testProducerConsumer 5 5 #Producers, Consumers -run ./testProgressBar 7 #Threads -run ./testProjectiles 400 400 #Width, Height -run ./testReaderWriter 6 6 #Readers, Writers, Priority, Starved -run ./testRotation 800 800 #Width, Height -run ./testSeaUrchin 16 #Threads -run ./testScreenshot 900 650 #Width, Height -run ./testSmartSort 1024 #Elements, Threads -run ./testSpectrogram ../assets/pics/test.png #Image -run ./testSpectrum 8 #Threads -run ./testStar -run ./testText 1200 900 ../assets/freefont/FreeSerif.ttf #Width, Height, Font -run ./testTextCart 1200 900 ../assets/freefont/FreeSerifItalic.ttf #Width, Height, Font -run ./testTextTwo 1200 900 #Width, Height -run ./testVoronoi 640 480 8 #Width, Height, Threads +# RUN TESTS +run ./$TESTS_PATH/test3DRotation/test3DRotation +run ./$TESTS_PATH/testArrows/testArrows +run ./$TESTS_PATH/testCircle/testCircle +run ./$TESTS_PATH/testConcavePolygon/testConcavePolygon +run ./$TESTS_PATH/testCone/testCone +run ./$TESTS_PATH/testConvexPolygon/testConvexPolygon +run ./$TESTS_PATH/testCube/testCube +run ./$TESTS_PATH/testCuboid/testCuboid +run ./$TESTS_PATH/testCylinder/testCylinder +run ./$TESTS_PATH/testEllipse/testEllipse +run ./$TESTS_PATH/testEllipsoid/testEllipsoid +run ./$TESTS_PATH/testImage/testImage 1200 600 #Width, Height +run ./$TESTS_PATH/testLines/testLines +run ./$TESTS_PATH/testPrism/testPrism +run ./$TESTS_PATH/testPyramid/testPyramid +run ./$TESTS_PATH/testRectangle/testRectangle +run ./$TESTS_PATH/testRegularPolygon/testRegularPolygon +run ./$TESTS_PATH/testSphere/testSphere +run ./$TESTS_PATH/testSquare/testSquare +run ./$TESTS_PATH/testStar/testStar +run ./$TESTS_PATH/testText/testText 1200 600 #Width, Height +run ./$TESTS_PATH/testTransparency/testTransparency +run ./$TESTS_PATH/testTriangle/testTriangle +run ./$TESTS_PATH/testTriangleStrip/testTriangleStrip From 115e9cf0e3be431b9da1346ee8c3bdb8a46aa572 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 10:37:28 -0400 Subject: [PATCH 052/105] Add files via upload --- src/examples/ArrayBubbleSort/CubeArray.cpp | 313 +++++++++++ src/examples/ArrayBubbleSort/CubeArray.h | 81 +++ src/examples/ArrayBubbleSort/Makefile | 63 +++ .../ArrayBubbleSort/testArrayBubbleSort.cpp | 154 +++++ src/examples/ArrayShakerSort/CubeArray.cpp | 313 +++++++++++ src/examples/ArrayShakerSort/CubeArray.h | 81 +++ src/examples/ArrayShakerSort/Makefile | 63 +++ .../ArrayShakerSort/testArrayShakerSort.cpp | 194 +++++++ src/examples/Ballroom/Makefile | 63 +++ src/examples/Ballroom/testBallroom.cpp | 319 +++++++++++ src/examples/Clock/Makefile | 63 +++ src/examples/Clock/testClock.cpp | 108 ++++ src/examples/DiningPhilosophers/Fork.h | 53 ++ src/examples/DiningPhilosophers/Makefile | 63 +++ .../DiningPhilosophers/Philosopher.cpp | 112 ++++ src/examples/DiningPhilosophers/Philosopher.h | 82 +++ src/examples/DiningPhilosophers/Table.cpp | 525 ++++++++++++++++++ src/examples/DiningPhilosophers/Table.h | 58 ++ src/examples/DiningPhilosophers/philEnums.h | 22 + .../DiningPhilosophers/testPhilosophers.cpp | 107 ++++ src/examples/DiningPhilosophers3D/Fork3D.h | 53 ++ src/examples/DiningPhilosophers3D/Makefile | 63 +++ .../DiningPhilosophers3D/Philosopher3D.cpp | 120 ++++ .../DiningPhilosophers3D/Philosopher3D.h | 83 +++ src/examples/DiningPhilosophers3D/Table3D.cpp | 489 ++++++++++++++++ src/examples/DiningPhilosophers3D/Table3D.h | 55 ++ src/examples/DiningPhilosophers3D/philEnums.h | 22 + .../test3DPhilosophers.cpp | 107 ++++ src/examples/Makefile | 23 + src/examples/MergeSort/Makefile | 63 +++ src/examples/MergeSort/testMergeSort.cpp | 204 +++++++ src/examples/NewtonPendulum/Makefile | 63 +++ .../NewtonPendulum/testNewtonPendulum.cpp | 134 +++++ src/examples/Pandemic/Makefile | 63 +++ src/examples/Pandemic/Pandemic.cpp | 64 +++ src/examples/Pandemic/Pandemic.h | 88 +++ src/examples/Pandemic/Person.cpp | 167 ++++++ src/examples/Pandemic/Person.h | 77 +++ src/examples/Pandemic/statusEnums.h | 11 + src/examples/Pandemic/testPandemic.cpp | 88 +++ src/examples/Pandemic/testPerson.cpp | 33 ++ src/examples/Pong/Ball.cpp | 84 +++ src/examples/Pong/Ball.h | 46 ++ src/examples/Pong/Makefile | 63 +++ src/examples/Pong/Paddle.cpp | 86 +++ src/examples/Pong/Paddle.h | 57 ++ src/examples/Pong/Pong.cpp | 84 +++ src/examples/Pong/Pong.h | 44 ++ src/examples/Pong/testPong.cpp | 73 +++ src/examples/SeaUrchin/Makefile | 63 +++ src/examples/SeaUrchin/SeaUrchin.cpp | 33 ++ src/examples/SeaUrchin/SeaUrchin.h | 56 ++ src/examples/SeaUrchin/testSeaUrchin.cpp | 65 +++ src/examples/ShakerSort/Makefile | 63 +++ src/examples/ShakerSort/testShakerSort.cpp | 116 ++++ src/examples/SolarSystem/Makefile | 63 +++ src/examples/SolarSystem/testSolarSystem.cpp | 76 +++ .../ThreadedArrayAddition/CubeArray.cpp | 313 +++++++++++ .../ThreadedArrayAddition/CubeArray.h | 81 +++ src/examples/ThreadedArrayAddition/Makefile | 63 +++ .../testThreadedArrayAddition.cpp | 229 ++++++++ .../ThreadedArrayBubbleSort/CubeArray.cpp | 313 +++++++++++ .../ThreadedArrayBubbleSort/CubeArray.h | 81 +++ src/examples/ThreadedArrayBubbleSort/Makefile | 63 +++ .../testThreadedArrayBubbleSort.cpp | 209 +++++++ .../ThreadedArrayOperations/CubeArray.cpp | 313 +++++++++++ .../ThreadedArrayOperations/CubeArray.h | 81 +++ src/examples/ThreadedArrayOperations/Makefile | 63 +++ .../testThreadedArrayOperations.cpp | 241 ++++++++ 69 files changed, 8029 insertions(+) create mode 100644 src/examples/ArrayBubbleSort/CubeArray.cpp create mode 100644 src/examples/ArrayBubbleSort/CubeArray.h create mode 100644 src/examples/ArrayBubbleSort/Makefile create mode 100644 src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp create mode 100644 src/examples/ArrayShakerSort/CubeArray.cpp create mode 100644 src/examples/ArrayShakerSort/CubeArray.h create mode 100644 src/examples/ArrayShakerSort/Makefile create mode 100644 src/examples/ArrayShakerSort/testArrayShakerSort.cpp create mode 100644 src/examples/Ballroom/Makefile create mode 100644 src/examples/Ballroom/testBallroom.cpp create mode 100644 src/examples/Clock/Makefile create mode 100644 src/examples/Clock/testClock.cpp create mode 100644 src/examples/DiningPhilosophers/Fork.h create mode 100644 src/examples/DiningPhilosophers/Makefile create mode 100644 src/examples/DiningPhilosophers/Philosopher.cpp create mode 100644 src/examples/DiningPhilosophers/Philosopher.h create mode 100644 src/examples/DiningPhilosophers/Table.cpp create mode 100644 src/examples/DiningPhilosophers/Table.h create mode 100644 src/examples/DiningPhilosophers/philEnums.h create mode 100644 src/examples/DiningPhilosophers/testPhilosophers.cpp create mode 100644 src/examples/DiningPhilosophers3D/Fork3D.h create mode 100644 src/examples/DiningPhilosophers3D/Makefile create mode 100644 src/examples/DiningPhilosophers3D/Philosopher3D.cpp create mode 100644 src/examples/DiningPhilosophers3D/Philosopher3D.h create mode 100644 src/examples/DiningPhilosophers3D/Table3D.cpp create mode 100644 src/examples/DiningPhilosophers3D/Table3D.h create mode 100644 src/examples/DiningPhilosophers3D/philEnums.h create mode 100644 src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp create mode 100644 src/examples/Makefile create mode 100644 src/examples/MergeSort/Makefile create mode 100644 src/examples/MergeSort/testMergeSort.cpp create mode 100644 src/examples/NewtonPendulum/Makefile create mode 100644 src/examples/NewtonPendulum/testNewtonPendulum.cpp create mode 100644 src/examples/Pandemic/Makefile create mode 100644 src/examples/Pandemic/Pandemic.cpp create mode 100644 src/examples/Pandemic/Pandemic.h create mode 100644 src/examples/Pandemic/Person.cpp create mode 100644 src/examples/Pandemic/Person.h create mode 100644 src/examples/Pandemic/statusEnums.h create mode 100644 src/examples/Pandemic/testPandemic.cpp create mode 100644 src/examples/Pandemic/testPerson.cpp create mode 100644 src/examples/Pong/Ball.cpp create mode 100644 src/examples/Pong/Ball.h create mode 100644 src/examples/Pong/Makefile create mode 100644 src/examples/Pong/Paddle.cpp create mode 100644 src/examples/Pong/Paddle.h create mode 100644 src/examples/Pong/Pong.cpp create mode 100644 src/examples/Pong/Pong.h create mode 100644 src/examples/Pong/testPong.cpp create mode 100644 src/examples/SeaUrchin/Makefile create mode 100644 src/examples/SeaUrchin/SeaUrchin.cpp create mode 100644 src/examples/SeaUrchin/SeaUrchin.h create mode 100644 src/examples/SeaUrchin/testSeaUrchin.cpp create mode 100644 src/examples/ShakerSort/Makefile create mode 100644 src/examples/ShakerSort/testShakerSort.cpp create mode 100644 src/examples/SolarSystem/Makefile create mode 100644 src/examples/SolarSystem/testSolarSystem.cpp create mode 100644 src/examples/ThreadedArrayAddition/CubeArray.cpp create mode 100644 src/examples/ThreadedArrayAddition/CubeArray.h create mode 100644 src/examples/ThreadedArrayAddition/Makefile create mode 100644 src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp create mode 100644 src/examples/ThreadedArrayBubbleSort/CubeArray.cpp create mode 100644 src/examples/ThreadedArrayBubbleSort/CubeArray.h create mode 100644 src/examples/ThreadedArrayBubbleSort/Makefile create mode 100644 src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp create mode 100644 src/examples/ThreadedArrayOperations/CubeArray.cpp create mode 100644 src/examples/ThreadedArrayOperations/CubeArray.h create mode 100644 src/examples/ThreadedArrayOperations/Makefile create mode 100644 src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp diff --git a/src/examples/ArrayBubbleSort/CubeArray.cpp b/src/examples/ArrayBubbleSort/CubeArray.cpp new file mode 100644 index 000000000..a77d2ff97 --- /dev/null +++ b/src/examples/ArrayBubbleSort/CubeArray.cpp @@ -0,0 +1,313 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + +// CubeArray::CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]){ +// myX = x; +// myY = y; +// myZ = z; +// mySize = size; +// myCubeSideLength = sideLength; +// myYaw = yaw; +// myPitch = pitch; +// myRoll = roll; + +// for(unsigned i = 0; i < size; ++i){ +// myCubes.push_back(new Cube((-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c[0])); +// myCubes[i]->setRotationPoint(0,0,0); +// myCubes[i]->setColor(c[i%(sizeof(c[0])/sizeof(c))]); +// } +// } + +// bool CubeArray::operator==(CubeArray& a2){ +// printf("Equality entered.\n"); +// if(mySize != a2.getSize()){ +// printf("Sizes are different.\n"); +// return false; +// } +// for(unsigned i = 0; i < mySize; ++i){ +// if(myCubes[i] != a2.get(i)){ +// printf("Index %d is different.\n", i); +// return false; +// } +// } +// return true; +// } + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hid it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setFontSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the font size of the CubeArray's Text/numbers to a new size. + * \param fontsize The new font size. + */ +void CubeArray::setFontSize(unsigned int fontsize){ + for(Text * t : myText){ + t->setFontSize(fontsize); + } +} + + +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +void CubeArray::visualSplit(unsigned index){ + for(unsigned i = 0; i < index; ++i){ + myCubes[i]->changeXBy(-myCubeSideLength/2.0); + myText[i]->changeXBy(-myCubeSideLength/2.0); + } + for(unsigned i = index; i < mySize; ++i){ + myCubes[i]->changeXBy(myCubeSideLength/2.0); + myText[i]->changeXBy(myCubeSideLength/2.0); + } +} + +// void CubeArray::visualRegroup(unsigned index){ + +// } + +void CubeArray::visualRegroupAll(float x){ + for(unsigned i = 0; i < mySize; i++){ + myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + } +} + + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/CubeArray.h b/src/examples/ArrayBubbleSort/CubeArray.h new file mode 100644 index 000000000..2fc1c2e16 --- /dev/null +++ b/src/examples/ArrayBubbleSort/CubeArray.h @@ -0,0 +1,81 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + // CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setFontSize(unsigned int fontsize); + + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + void visualSplit(unsigned index); + + void visualRegroupAll(float x); + + // Operations + CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/Makefile b/src/examples/ArrayBubbleSort/Makefile new file mode 100644 index 000000000..981369086 --- /dev/null +++ b/src/examples/ArrayBubbleSort/Makefile @@ -0,0 +1,63 @@ +# Makefile for ArrayBubbleSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrayBubbleSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp b/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp new file mode 100644 index 000000000..2f14a4f3c --- /dev/null +++ b/src/examples/ArrayBubbleSort/testArrayBubbleSort.cpp @@ -0,0 +1,154 @@ +/* + * testArrayBubbleSort.cpp + * + * Usage: ./testArrayBubbleSort [sizeOfArray] + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; +} + +void sortVisualizationFunction(Canvas& can, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int originalArray[arraySize]; + // int sortedArray[] = {40, 35, 80, 62, 60, 74, 36, 10, 19, 5}; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = rand() % (RAND_UPPER + 1); + // originalArray[i] = i + 90; + } + + printf("Before bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Bubble Sort", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + // Text * speedLabel = new Text(0.0, ARRAY_Y - 100.0, TEXT_Z, + // "Speed: x" + std::to_string(sleepTime/250000), FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.125; // initial number of seconds to sleep + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0){ + int end = arraySize; + // Bubble sort algorithm + for(unsigned i = 0; i < arrayA.getSize(); i++){ + for(unsigned j = 1; j < end; j++){ // OR j < arrayA.getSize(); + // speedLabel->setText("Speed: x" + std::to_string(250000.0/sleepTime)); + arrayA.getCube(j)->setColor(RED); + arrayA.getCube(j-1)->setColor(BLUE); + can.sleepFor(sleepTime); + if(arrayA[j] < arrayA[j-1]){ + swap(arrayA[j], arrayA[j-1]); + arrayA.update(j); + arrayA.update(j-1); + can.sleepFor(sleepTime); + } + arrayA.getCube(j)->setColor(ARRAY_COLOR); + arrayA.getCube(j-1)->setColor(ARRAY_COLOR); + can.sleepFor(sleepTime); + } + arrayA.getCube(end-1)->setColor(FINISHED_COLOR); + end--; + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int sizeOfArray = (argc > 1) ? atoi(argv[1]) : 10; + + // Checks validity of sizeOfArray; if invalid, set to default + if((sizeOfArray <= 0 or sizeOfArray > 24)){ + printf("Invalid argument(s).\ + \nUsage: ./testArrayBubbleSort [sizeOfArray]\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + sizeOfArray = 10; + } + + Canvas c(0, -1, 1820, 620, "Array Bubble Sort"); + c.setBackgroundColor(BLACK); + c.run(sortVisualizationFunction, sizeOfArray); +} diff --git a/src/examples/ArrayShakerSort/CubeArray.cpp b/src/examples/ArrayShakerSort/CubeArray.cpp new file mode 100644 index 000000000..a77d2ff97 --- /dev/null +++ b/src/examples/ArrayShakerSort/CubeArray.cpp @@ -0,0 +1,313 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + +// CubeArray::CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]){ +// myX = x; +// myY = y; +// myZ = z; +// mySize = size; +// myCubeSideLength = sideLength; +// myYaw = yaw; +// myPitch = pitch; +// myRoll = roll; + +// for(unsigned i = 0; i < size; ++i){ +// myCubes.push_back(new Cube((-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c[0])); +// myCubes[i]->setRotationPoint(0,0,0); +// myCubes[i]->setColor(c[i%(sizeof(c[0])/sizeof(c))]); +// } +// } + +// bool CubeArray::operator==(CubeArray& a2){ +// printf("Equality entered.\n"); +// if(mySize != a2.getSize()){ +// printf("Sizes are different.\n"); +// return false; +// } +// for(unsigned i = 0; i < mySize; ++i){ +// if(myCubes[i] != a2.get(i)){ +// printf("Index %d is different.\n", i); +// return false; +// } +// } +// return true; +// } + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hid it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setFontSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the font size of the CubeArray's Text/numbers to a new size. + * \param fontsize The new font size. + */ +void CubeArray::setFontSize(unsigned int fontsize){ + for(Text * t : myText){ + t->setFontSize(fontsize); + } +} + + +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +void CubeArray::visualSplit(unsigned index){ + for(unsigned i = 0; i < index; ++i){ + myCubes[i]->changeXBy(-myCubeSideLength/2.0); + myText[i]->changeXBy(-myCubeSideLength/2.0); + } + for(unsigned i = index; i < mySize; ++i){ + myCubes[i]->changeXBy(myCubeSideLength/2.0); + myText[i]->changeXBy(myCubeSideLength/2.0); + } +} + +// void CubeArray::visualRegroup(unsigned index){ + +// } + +void CubeArray::visualRegroupAll(float x){ + for(unsigned i = 0; i < mySize; i++){ + myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + } +} + + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for CubeArray. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/CubeArray.h b/src/examples/ArrayShakerSort/CubeArray.h new file mode 100644 index 000000000..2fc1c2e16 --- /dev/null +++ b/src/examples/ArrayShakerSort/CubeArray.h @@ -0,0 +1,81 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + // CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setFontSize(unsigned int fontsize); + + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + void visualSplit(unsigned index); + + void visualRegroupAll(float x); + + // Operations + CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/Makefile b/src/examples/ArrayShakerSort/Makefile new file mode 100644 index 000000000..322017fa3 --- /dev/null +++ b/src/examples/ArrayShakerSort/Makefile @@ -0,0 +1,63 @@ +# Makefile for ArrayShakerSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrayShakerSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ArrayShakerSort/testArrayShakerSort.cpp b/src/examples/ArrayShakerSort/testArrayShakerSort.cpp new file mode 100644 index 000000000..9d3851da9 --- /dev/null +++ b/src/examples/ArrayShakerSort/testArrayShakerSort.cpp @@ -0,0 +1,194 @@ +/* + * testArrayShakerSort.cpp + * + * Usage: ./testArrayShakerSort [sizeOfArray] + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; +} + +void sortVisualizationFunction(Canvas& can, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int originalArray[arraySize]; + // int sortedArray[] = {40, 35, 80, 62, 60, 74, 36, 10, 19, 5}; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = rand() % (RAND_UPPER + 1); + // originalArray[i] = i + 90; + } + + printf("Before shaker sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Shaker Sort", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + // Text * speedLabel = new Text(0.0, ARRAY_Y - 100.0, TEXT_Z, + // "Speed: x" + std::to_string(sleepTime/250000), FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.5; // number of seconds to sleep + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + bool swapped = true; + int start = 0; + int end = arraySize - 1; + while (can.isOpen()) { + can.sleep(); + + if(complete == 0){ + // Shaker sort + while (swapped) { + // reset the swapped flag on entering + // the loop, because it might be true from + // a previous iteration. + swapped = false; + + // Going up + for (int pos = start; pos < end; ++pos) { + arrayA.getCube(pos)->setColor(RED); + arrayA.getCube(pos+1)->setColor(BLUE); + can.sleepFor(sleepTime); + // Compare values + if (arrayA[pos] > arrayA[pos + 1]) { + swap(arrayA[pos], arrayA[pos + 1]); + swapped = true; + arrayA.update(pos); arrayA.update(pos + 1); + } + // Animation + can.sleepFor(sleepTime); + arrayA.getCube(pos)->setColor(ARRAY_COLOR); + arrayA.getCube(pos+1)->setColor(ARRAY_COLOR); + } + // if nothing moved, then array is sorted. + if (!swapped) + break; + + // otherwise, reset the swapped flag so that it + // can be used in the next stage + swapped = false; + arrayA.getCube(end)->setColor(FINISHED_COLOR); + --end; + + // Going down + for (int pos = end - 1; pos >= start; --pos) { + arrayA.getCube(pos)->setColor(RED); + arrayA.getCube(pos+1)->setColor(BLUE); + can.sleepFor(sleepTime); + if (arrayA[pos] > arrayA[pos + 1]) { + swap(arrayA[pos], arrayA[pos + 1]); + swapped = true; + arrayA.update(pos); arrayA.update(pos + 1); + } + // Animation + can.sleepFor(sleepTime); + arrayA.getCube(pos)->setColor(ARRAY_COLOR); + arrayA.getCube(pos+1)->setColor(ARRAY_COLOR); + } + arrayA.getCube(start)->setColor(FINISHED_COLOR); + ++start; + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter shaker sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int sizeOfArray = (argc > 1) ? atoi(argv[1]) : 10; + + // Checks validity of sizeOfArray; if invalid, set to default + if((sizeOfArray <= 0 or sizeOfArray > 24)){ + printf("Invalid argument(s).\ + \nUsage: ./testArrayShakerSort [sizeOfArray]\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + sizeOfArray = 10; + } + + printf("Use the up and down arrow keys to speed up and slow down animation, respectfully.\n"); + + Canvas c(0, -1, 1820, 620, "Array Shaker Sort"); + c.setBackgroundColor(BLACK); + c.run(sortVisualizationFunction, sizeOfArray); +} + + + diff --git a/src/examples/Ballroom/Makefile b/src/examples/Ballroom/Makefile new file mode 100644 index 000000000..981749b21 --- /dev/null +++ b/src/examples/Ballroom/Makefile @@ -0,0 +1,63 @@ +# Makefile for Ballroom + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBallroom + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Ballroom/testBallroom.cpp b/src/examples/Ballroom/testBallroom.cpp new file mode 100644 index 000000000..722639ca3 --- /dev/null +++ b/src/examples/Ballroom/testBallroom.cpp @@ -0,0 +1,319 @@ +/* + * testBallroom.cpp + * + * Usage: ./testBallroom + */ + +#include +#include +#include + +using namespace tsgl; + +struct Vector2 { + float x,y; + Vector2() { + x = y = 0; + } + Vector2(float xx,float yy) { + x = xx; y = yy; + } + Vector2 operator+(const Vector2 &o) { + return Vector2(x+o.x,y+o.y); + } + Vector2& operator+=(const Vector2 &o) { + x += o.x; y += o.y; + return (*this); + } + Vector2 operator-(const Vector2 &o) { + return Vector2(x-o.x,y-o.y); + } + Vector2 operator-() { + return Vector2(-x,-y); + } + Vector2& operator-=(const Vector2 &o) { + x -= o.x; y -= o.y; + return (*this); + } + Vector2 operator*(const float f) { + return Vector2(x*f,y*f); + } + Vector2& operator*=(const float f) { + x *= f; y *= f; + return (*this); + } + float dot(const Vector2 &o) const { + return x*o.x + y*o.y; + } + float length() const { + return sqrt(x*x+y*y); + } + float angle() const { + return atan2(y,x); + } + float angle(const Vector2 &o) { + return acos(angle(o)); + } + float cosangle(const Vector2 &o) { + return dot(o)/( length() * o.length() ); + } +}; +Vector2 operator+(const Vector2 &v1, const Vector2 &v2) { + return Vector2(v1.x+v2.x,v1.y+v2.y); +} +Vector2 operator-(const Vector2 &v1, const Vector2 &v2) { + return Vector2(v1.x-v2.x,v1.y-v2.y); +} +Vector2 operator*(const Vector2 &v, const float f) { + return Vector2(v.x*f,v.y*f); +} + +class BouncingBall { +private: + float mySpeed, myDir; + int rw, rh; + Circle * circle; + Canvas * can; +public: + Vector2 pos, vel, acc; + ColorFloat color; + int rad; + bool bounced; + BouncingBall(int x, int y, int r, int w, int h, ColorFloat c, Canvas * can) { + pos = Vector2(x,y); + vel = Vector2(0,0); + acc = Vector2(0,0); + mySpeed = myDir = 0; + rad = r; + rw = w; + rh = h; + color = c; + bounced = false; + circle = new Circle(x,y,0,r,0,0,0,c); + // circle->setLayer(1); + can->add(circle); + } + BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorFloat c, Canvas * canvas) { + pos = Vector2(x,y); + vel = Vector2(vx,vy); + acc = Vector2(0,0.1f); + calcSpeed(); + calcDir(); + rad = r; + rw = w; + rh = h; + color = c; + bounced = false; + can = canvas; + circle = new Circle(x,y,0,r,0,0,0,c); + // circle->setLayer(1); + can->add(circle); + } + ~BouncingBall() { + can->remove(circle); + delete circle; + } + void calcSpeed() { + mySpeed = vel.length(); + } + void setSpeed(float s) { + mySpeed = s; + vel.x = s*cos(myDir); + vel.y = s*sin(myDir); + } + void calcDir() { + myDir = vel.angle(); + } + void setDir(float d) { + myDir = d; + vel.x = mySpeed*cos(d); + vel.y = mySpeed*sin(d); + } + void step() { + bounced = false; + vel += acc; + pos += vel; + if (pos.x <= -rw / 2 + rad) { + pos.x = -rw / 2 + rad; + vel.x *= -0.5f; + } else if (pos.x >= rw / 2 -rad) { + pos.x = rw / 2-rad; + vel.x *= -0.5f; + } + if (pos.y <= -rh / 2 + rad) { + pos.y = -rh / 2 + rad; + vel.y *= -1.0f; + } else if (pos.y >= rh / 2 -rad) { + pos.y = rh / 2 -rad; + vel.y *= -1.0f; + } + calcSpeed(); + calcDir(); + circle->setCenter(pos.x,pos.y,0); + } + void setRoomSize(int w, int h) { + rw = w; + rh = h; + } + void bounce(BouncingBall *o) { + if (bounced) + return; + Vector2 dist = pos-o->pos; + float radii = rad+o->rad; + if (dist.length() > radii) + return; + Vector2 vdelta = vel-o->vel; + pos -= vel; + Vector2 pdelta = pos-o->pos; + float ps = pdelta.length()*pdelta.length(); + vel -= pdelta*(vdelta.dot(pdelta)/ps); + o->vel += pdelta*((-vdelta).dot(-pdelta)/ps); + calcSpeed(); + calcDir(); + o->calcSpeed(); + o->calcDir(); + bounced = true; + circle->setCenter(pos.x, pos.y,0); + } + bool collides(BouncingBall *o) { + return ((pos-o->pos).length() <= (rad+o->rad)); + } +}; + +class BallRoom { +private: + int width, height; + float friction, gravity; + bool attract; + std::list balls; + std::list::const_iterator it, jt; + Circle * mouseCircle; + Canvas * can; +public: + BallRoom(int w, int h, Canvas * canvas) { + width = w; + height = h; + friction = 0.99f; + gravity = 0.1f; + attract = true; + can = canvas; + mouseCircle = new Circle(0,0,0,20,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); + // mouseCircle->setLayer(2); + can->add(mouseCircle); + } + ~BallRoom() { + while (!balls.empty()) { + BouncingBall* b = balls.front(); + balls.pop_front(); + delete b; + } + delete mouseCircle; + } + void addBall(int x, int y, int r, ColorFloat c = WHITE) { + addBall(x,y,0,0,r,c); + } + void addBall(int x, int y, int vx, int vy, int r, ColorFloat c = WHITE) { + BouncingBall* b = new BouncingBall(x,y,vx,vy,r,width,height,c, can); + const int MAXFAIL = 1000; + int fails = 0; + for (it = balls.begin(); it != balls.end(); ++it) { + while (b->collides((*it))) { + ++fails; + if (fails == MAXFAIL) { + delete b; + return; + } + } + } + balls.push_back(b); + } + void step(Canvas* c) { + int mx = c->getMouseX() - c->getWindowWidth()/2, my = c->getWindowHeight()/2 - c->getMouseY(); + Vector2 mvec(mx,my); + mouseCircle->setCenter(mx, my, 0); + if (attract) { + mouseCircle->setColor(ColorFloat(0.5,1.0,1.0,0.5)); + } else { + mouseCircle->setColor(ColorFloat(1.0,0.5,0.5,0.5)); + } + for (it = balls.begin(); it != balls.end(); ++it) { + BouncingBall *b = (*it); + + float mdir; + if (attract) + mdir = (mvec - b->pos).angle(); + else + mdir = (b->pos-mvec).angle(); + b->acc = Vector2(cos(mdir),sin(mdir))*gravity; + b->vel *= friction; + + b->step(); + for (jt = balls.begin(); jt != balls.end(); ++jt) { + if (jt == it) + continue; + b->bounce(*jt); + if (b->bounced) + break; + } + } + c->pauseDrawing(); + c->resumeDrawing(); + } + inline void toggleAttract() { + attract ^= true; + } +}; + +/*! + * \brief Lots and lots of multicolored balls! + * \details Draws a lot of multicolored balls onto the Canvas that follow the mouse around. + * - It is drawn in this way: + * - Get the window width and height for convenience of use. + * - Create the area for the balls based off of the window width and height. + * - For each ball: + * - Set its speed to 5. + * - Randomize its initial direction. + * - Add it to the area created with the calculated speed and direction as well as with a random color. + * . + * - Bind the left mouse button so that when you click the screen the attraction of the balls will change. + * (If they are attracted to the mouse then they will be repelled. If they are repelled, then they will be attracted + * to the mouse). + * - While the Canvas is open: + * - Sleep the internal timer until the next draw cycle. + * - Animate the balls and have them bounce off of one another. + * . + * . + * \param can Reference to the Canvas to draw on. + */ +void ballroomFunction(Canvas& can) { + const int WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(); // Window height + BallRoom b(WW,WH, &can); + for (int i = 0; i < 100; ++ i) { + float speed = 5.0f; + float dir = 2 * PI * saferand(0,100) / 100.0f; + ColorInt c = ColorInt(64 + saferand(0,191),64 + saferand(0,191),64 + saferand(0,191),255); + b.addBall(saferand(-WW/2,WW/2), saferand(-WH/2, WH/2), speed*cos(dir),speed*sin(dir),10,c); + } + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { + b.toggleAttract(); + }); + + + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + b.step(&can); + } +} + +//Take command-line arguments for the width and height of the Canvas +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "The Ballroom"); + c.setBackgroundColor(BLACK); + c.run(ballroomFunction); +} diff --git a/src/examples/Clock/Makefile b/src/examples/Clock/Makefile new file mode 100644 index 000000000..729ea5090 --- /dev/null +++ b/src/examples/Clock/Makefile @@ -0,0 +1,63 @@ +# Makefile for Clock + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testClock + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Clock/testClock.cpp b/src/examples/Clock/testClock.cpp new file mode 100644 index 000000000..d2fccf8b6 --- /dev/null +++ b/src/examples/Clock/testClock.cpp @@ -0,0 +1,108 @@ +/* + * testClock.cpp + * + * Usage: ./testClock + */ + +#include +#include +#include + +using namespace tsgl; + +void clockFunction(Canvas& can) { + Prism * head = new Prism(0,133,101,12,100,59,0,0,90,ColorFloat(.6,.3,0,1)); + can.add(head); + + Cuboid * left = new Cuboid(-45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(left); + + Cuboid * right = new Cuboid(45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1)); + can.add(right); + + Cuboid * back = new Cuboid(0,-50,55,80,300,10,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(back); + + Cuboid * bottom = new Cuboid(0,-195,110,79,10,80,0,0,0,ColorFloat(.6,.3,0,1) ); + can.add(bottom); + + Circle * face = new Circle(0,130,161,45,0,0,0,ColorFloat(1,1,0.8,1)); + can.add(face); + + Arrow * second = new Arrow(-19,130,163,38,2,0,0,0,ColorFloat(1,.8,.2,1),false); + can.add(second); + second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * minute = new Arrow(-19,130,162,38,2,0,0,0,BLACK,false); + can.add(minute); + minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Arrow * hour = new Arrow(-10,130,162,20,2,0,0,0,BLACK,false); + can.add(hour); + hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); + + Ellipsoid * pendulum = new Ellipsoid(0, -150, 100,10, 10,2,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); + pendulum->setRotationPoint(0,80,10); + can.add(pendulum); + + Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); + cord->setIsOutlined(false); + cord->setRotationPoint(0,80,10); + can.add(cord); + + time_t t = time(NULL); + // printf("local: %s", asctime(localtime(&t))); + // printf("local: %d:%d:%d\n", localtime(&t)->tm_hour, localtime(&t)->tm_min, localtime(&t)->tm_sec); + + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + + float speed = -0.28; + bool accelerationPositive = true; + while (can.isOpen()) { + can.sleep(); + t = time(NULL); + second->setYaw(localtime(&t)->tm_sec * -6 - 90); + minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); + hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); + if (cord->getYaw() > 97 || cord->getYaw() < 83) { + speed = 0; + } + if (cord->getYaw() > 90 && accelerationPositive == true) { + accelerationPositive = false; + } else if (cord->getYaw() < 90 && accelerationPositive == false) { + accelerationPositive = true; + } + if (accelerationPositive) { + speed += 0.01; + } else { + speed -= 0.01; + } + cord->changeYawBy(speed); + pendulum->changeYawBy(speed); + + } + + delete head; + delete left; + delete right; + delete back; + delete bottom; + delete face; + delete second; + delete minute; + delete hour; + delete pendulum; + delete cord; +} + +int main(int argc, char* argv[]) { + // int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + // int h = (argc > 2) ? atoi(argv[2]) : w; + // if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + // w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 500, 700, "Grandfather Clock"); + c.setBackgroundColor(WHITE); + c.run(clockFunction); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Fork.h b/src/examples/DiningPhilosophers/Fork.h new file mode 100644 index 000000000..cffb1d9ad --- /dev/null +++ b/src/examples/DiningPhilosophers/Fork.h @@ -0,0 +1,53 @@ +/*! + * \struct Fork + * \brief Struct for the forks in the Dining Philosophers' problem + */ + +#ifndef FORK_H_ +#define FORK_H_ + +#include +using namespace tsgl; + +struct Fork { + int user, id; + ConcavePolygon * myShape; + Fork() { + user = -1; id = 0; + + const int POINTS = 20; // number of vertices in polygon + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; + + // scales (out of 100) for the dimensions of the fork + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; + + // create the fork points from the scale arrays + for(int i = 0; i < POINTS; ++i) { + // scale the fork + xs[i] = WIDTH * xscale[i]; + ys[i] = HEIGHT * yscale[i]; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; + } + + //Add vertices + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorFloat(1,1,1,1)); + } + void setCanvas( Canvas* can) { + can->add(myShape); + } + void draw(float x, float y, double angle, ColorFloat c) { + angle -= PI/2; + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); + } + ~Fork() { + delete myShape; + } +}; + +#endif /* FORK_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Makefile b/src/examples/DiningPhilosophers/Makefile new file mode 100644 index 000000000..594982eb2 --- /dev/null +++ b/src/examples/DiningPhilosophers/Makefile @@ -0,0 +1,63 @@ +# Makefile for DiningPhilosophers + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = Fork.h philEnums.h \ + +# Main source file +TARGET = testPhilosophers + +# Object files +ODIR = obj +_OBJ = Philosopher.o Table.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Philosopher.cpp b/src/examples/DiningPhilosophers/Philosopher.cpp new file mode 100644 index 000000000..2e7dc6432 --- /dev/null +++ b/src/examples/DiningPhilosophers/Philosopher.cpp @@ -0,0 +1,112 @@ +#include "Philosopher.h" + +/*! + * \brief Explicitly constructs a new Philosopher. + * \details Explicit constructor for a new Philosopher object. + */ +Philosopher::Philosopher() { + setId(0,1); + myState = thinking; + myAction = doNothing; + myCircle = NULL; + numMeals = 0; +} + +Philosopher::~Philosopher() { + delete myCircle; + for (RegularPolygon * meal : meals) + { + delete meal; + } + meals.clear(); +} + +/** + * Adds Philosopher to Canvas or refreshes its color. + */ +void Philosopher::draw(Canvas& can, float x, float y) { + const float SIZE = 45; + if( !myCircle) { + myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorFloat(1,0,0,1)); + can.add(myCircle); + } +} + +/** + * Updates the Philosopher's color based on its state + */ +void Philosopher::refreshColor() { + ColorFloat c; + switch(myState) { + case hasNone: c=RED; break; + case hasRight: c=ORANGE; break; + case hasLeft: c=PURPLE; break; + case hasBoth: c=GREEN; break; + case isFull: c=BLUE; break; + case thinking: c=BLUE; break; + } + myCircle->setColor(c); +} + +/** + * Adds a meal representation to meals and the Canvas + */ +void Philosopher::addMeal(float x, float y, float z) { + numMeals++; + meals.push_back(new RegularPolygon(x,y,z,3,3,0,0,0,ColorFloat(0.5,0.3,0,1))); +} + +RegularPolygon * Philosopher::getLastMeal() { + return meals.back(); +} + +/** + * Picks up a fork specified by its reference + */ +bool Philosopher::acquire(Fork& f) { + if (f.user >= 0) + return false; + if (f.id == myLeft) { + if (myState == hasNone) + myState = hasLeft; + else if (myState == hasRight) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + if (f.id == myRight) { + if (myState == hasNone) + myState = hasRight; + else if (myState == hasLeft) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + return false; +} + +/** + * Releases a fork specified by its reference + */ +bool Philosopher::release(Fork& f) { + if (f.user != id) + return false; + if (myState != isFull) + myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; + f.user = -1; + return true; +} + +/** + * Thinks and switches to hungry state if a random number is a multiple of 3. + */ +void Philosopher::think() { + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state + setState(hasNone); + setAction(doNothing); + } +} diff --git a/src/examples/DiningPhilosophers/Philosopher.h b/src/examples/DiningPhilosophers/Philosopher.h new file mode 100644 index 000000000..222a4b97e --- /dev/null +++ b/src/examples/DiningPhilosophers/Philosopher.h @@ -0,0 +1,82 @@ +/*! + * \class Philosopher + * \brief Object representing a philosopher in the Dining Philosophers' problem + * \details The Philosopher class contains variables and methods necessary for + * representing a philosopher at a table. Each Philosopher may acquire or release + * the fork to his left or to his right (or both), with his state changing + * accordingly. + */ + +#ifndef PHILOSOPHER_H_ +#define PHILOSOPHER_H_ + +#include +#include +#include "Fork.h" +#include "philEnums.h" + +class Philosopher { +private: + PhilState myState; + PhilAction myAction; + int id, myLeft, myRight; + unsigned int numMeals; + Circle *myCircle; + std::vector meals; +public: + Philosopher(); + ~Philosopher(); + void draw(Canvas& can, float x, float y); + void refreshColor(); + void addMeal(float x, float y, float z); + RegularPolygon * getLastMeal(); + bool acquire(Fork& f); + bool release(Fork& f); + void think(); + + // Mutators + /*! + * \brief Resets the Philosopher to thinking after he eats. + */ + void eat() { myState = thinking; myAction = doNothing;} + /*! + * \brief Mutator for myState + * \param s PhilState to set myState to. + */ + void setState(PhilState s) { myState = s; } + /*! + * \brief Mutator for myAction + * \param s PhilAction to set myAction to. + */ + void setAction(PhilAction a) { myAction = a; } + /*! + * \brief Mutator for id + * \param i Which philosopher id to mutate + * \param nphil Total number of philosophers. + */ + void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } + + //Accessors + /** + * Accessor for number of meals Philosopher has consumed. + */ + int getMeals() { return numMeals; } + /** + * Accessor for Philosopher's state. + */ + PhilState state() { return myState; } + /** + * Accessor for Philosopher's action. + */ + PhilAction action() { return myAction; } + /** + * Accessor for Philosopher's id. + */ + int getId() { return id; } + /** + * Accessor for Philosopher's circle. + */ + bool hasCircle() { return myCircle; } +}; + +#endif /* PHILOSOPHER_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Table.cpp b/src/examples/DiningPhilosophers/Table.cpp new file mode 100644 index 000000000..9bd781750 --- /dev/null +++ b/src/examples/DiningPhilosophers/Table.cpp @@ -0,0 +1,525 @@ +#include "Table.h" + +/*! + * \brief Creates a new Table of dining philosophers. + * \details Explicit constructor for a new Table object. + * \param can The Canvas on which the Table is to be drawn. + * \param p Integer denoting the number of Philosophers at the Table + * \param m PhilMethod denoting how the Philosophers should interact. + */ +Table::Table(Canvas& can, int p, PhilMethod m) { + numPhils = p; + myCan = &can; + myTable = new Circle(0,0,-1,175,0,0,0,ColorFloat(0.5,0.5,0.5,1)); + can.add(myTable); + // can.drawCircle(0,0,1,ColorFloat(0.5,0.5,0.5,1)); + phils = new Philosopher[numPhils]; + forks = new Fork[numPhils]; + for (int i = 0; i < numPhils; ++i) { + phils[i].setId(i,numPhils); + forks[i].id = i; + forks[i].setCanvas(myCan); + } + spaghettis = new Image*[numPhils](); + float delta = 2.0f / numPhils * PI; + for(int i = 0; i < numPhils; i++) { + spaghettis[i] = new Image(120 * cos(i*delta), 140 * sin(i*delta), -0.5, "./assets/pics/spaghet.png", 100, 50, 0,0,0); + can.add(spaghettis[i]); + // myCan->drawImage("../assets/pics/spaghet.png", -50+(200)*cos(i*delta), -25+(215)*sin(i*delta), 100, 50, 1.0f); + } + myMethod = m; + switch(myMethod) { + case forfeitWhenBlocked: + methodString = L"forfeit when blocked"; + break; + case waitWhenBlocked: + methodString = L"wait when blocked"; + break; + case nFrameRelease: + methodString = L"release on nth frame"; + break; + case resourceHierarchy: + methodString = L"hierarchical resources"; + break; + case oddEven: + methodString = L"odd-even check"; + break; + default: + break; + } + + myCan2 = new Canvas(0,0,300,300,"Legend"); + myCan2->start(); + myCan2->setBackgroundColor(GRAY); + + legendTexts = new Text*[9](); + legendTexts[0] = new Text(-134,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); + legendTexts[0]->changeXBy(legendTexts[0]->getWidth() / 2); + myCan2->add(legendTexts[0]); + legendTexts[1] = new Text(-118,96,0,L"\"" + methodString + L"\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[1]->changeXBy(legendTexts[1]->getWidth() / 2); + myCan2->add(legendTexts[1]); + legendTexts[2] = new Text(-134,64,0,L"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); + legendTexts[2]->changeXBy(legendTexts[2]->getWidth() / 2); + myCan2->add(legendTexts[2]); + legendTexts[3] = new Text(-118,32,0,L"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); + legendTexts[3]->changeXBy(legendTexts[3]->getWidth() / 2); + myCan2->add(legendTexts[3]); + legendTexts[4] = new Text(-118,0,0,L"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); + legendTexts[4]->changeXBy(legendTexts[4]->getWidth() / 2); + myCan2->add(legendTexts[4]); + legendTexts[5] = new Text(-118,-32,0,L"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); + legendTexts[5]->changeXBy(legendTexts[5]->getWidth() / 2); + myCan2->add(legendTexts[5]); + legendTexts[6] = new Text(-118,-64,0,L"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); + legendTexts[6]->changeXBy(legendTexts[6]->getWidth() / 2); + myCan2->add(legendTexts[6]); + legendTexts[7] = new Text(-118,-96,0,L"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); + legendTexts[7]->changeXBy(legendTexts[7]->getWidth() / 2); + myCan2->add(legendTexts[7]); + legendTexts[8] = new Text(-118,-121,0,L"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); + legendTexts[8]->changeXBy(legendTexts[8]->getWidth() / 2); + myCan2->add(legendTexts[8]); + + exampleMeal = new RegularPolygon(15, -121,0,3,3,0,0,0, BROWN); + myCan2->add(exampleMeal); +} + +/*! + * \brief Destructor for Table. + */ +Table::~Table() { + if (myCan2->isOpen()) + myCan2->stop(); + delete myCan2; + for (int i = 0; i < 9; i++) { + delete legendTexts[i]; + } + delete[] legendTexts; + delete exampleMeal; + for (int i = 0; i < numPhils; i++) { + delete spaghettis[i]; + } + delete [] spaghettis; + delete myTable; + delete [] phils; + delete [] forks; +} + + /*! + * \brief Method for determining which fork a Philosopher should get. + * \details + * - Store the id numbers for the left and the right Philsopher's state. + * - Switch for the state of a Philosopher: + * - Philosopher has no fork: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher has right fork: + * - If the left fork is free, try to get that fork. + * . + * - Philosopher has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, release the left fork. + * . + * - Philosopher has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher. + * \note This is an example of Deadlock amongst threads. + */ +void Table::forfeitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(releaseRight); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].setState(hasNone); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher should get. + * \details + * - Store the states of the left and right Philosophers. + * - Switch for the state of the current Philosopher: + * - Philosopher has no forks: + * - If the right fork is free, try to get that fork. + * - Else if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher has right fork: + * - If the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher. + * \note This is an example of Livelock amongst threads. + */ +void Table::waitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher should get. + * \details + * - Store the states of the left and right Philosophers. + * - Switch statement for the current Philosopher: + * - Philosopher has no forks: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher has right fork: + * - If the left fork is free, try to get that fork. + * - Else, if the id of the current Philosopher is equal to the frame number of the Canvas + * modulo the number of Philosophers+1, then release the right fork. + * - Else, do nothing. + * . + * - Philosopher has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, if the id of the current Philosopher is equal to the frame number of the Canvas + * modulo the number of Philosophers+1, then release the left fork. + * - Else, do nothing. + * . + * - Philosopher has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher. + */ +void Table::nFrameReleaseMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseRight); + else + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher should get. + * \details + * - Store the states for the left and right Philosophers. + * - Switch statement for the state of the current Philosopher. + * - Philosopher has no forks: + * - If the right Philosopher's id is less than the left Philsopher's id: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Else, if the left fork is free then try and get that fork. + * - Else, do nothing. + * . + * - Philosopher has the right fork: + * - If the left fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher. + */ +void Table::hierarchyMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (right < left) { + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + } else { + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher should get. + * \details + * - Switch statement for the current Philosopher: + * - Philosopher has no forks: + * - If the Philosopher's id is even + * - Philosopher has right fork (odd id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the left fork. + * - Else, release the right fork. + * . + * - Philosopher has left fork (even id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the right fork. + * - Else, release the left fork. + * . + * - Philosopher has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher. + * \note This method is the one that works best. + */ +void Table::oddEvenMethod(int id) { + switch(phils[id].state()) { + case hasNone: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryBoth); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(releaseRight); + } + break; + case hasLeft: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + +/*! + * \brief Method for determining which method of resolution the philosopher is using. + */ +void Table::checkStep() { + int i = omp_get_thread_num(); + if (phils[i].state() == isFull) { + phils[i].eat(); + return; + } + switch(myMethod) { + case forfeitWhenBlocked: + forfeitWhenBlockedMethod(i); + break; + case waitWhenBlocked: + waitWhenBlockedMethod(i); + break; + case nFrameRelease: + nFrameReleaseMethod(i); + break; + case resourceHierarchy: + hierarchyMethod(i); + break; + case oddEven: + oddEvenMethod(i); + break; + default: + break; + } +} + +/*! + * \brief Method for philosopher to act based on myAction. + */ +void Table::actStep() { + // myCan2->sleep(); + int i = omp_get_thread_num(); + int left = i, right = (i+numPhils-1)%numPhils; + switch(phils[i].action()) { + case tryLeft: + phils[i].acquire(forks[left]); + break; + case tryRight: + phils[i].acquire(forks[right]); + break; + case tryBoth: + phils[i].acquire(forks[left]); + phils[i].acquire(forks[right]); + break; + case releaseLeft: + phils[i].release(forks[left]); + break; + case releaseRight: + phils[i].release(forks[right]); + break; + case releaseBoth: + phils[i].release(forks[left]); + phils[i].release(forks[right]); + break; + default: + break; + } +} + +/*! + * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. + */ +void Table::drawStep() { + const float RAD = 225; + float FORK_RAD = 175; + const float ARC =2*PI/numPhils; + const float CLOSE = 0.15f; + const float BASEDIST = RAD+54; + + int i = omp_get_thread_num(); + float pangle = (i*2*PI)/numPhils; + ColorFloat fcolor = ColorFloat(1,1,1,1); + float fangle = (i+0.5f)*ARC; + + if( !phils[i].hasCircle() ) { + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); + } + + phils[i].refreshColor(); + if( phils[i].state() == isFull ) { + int meals = phils[i].getMeals(); + float angle = pangle+(meals/10)*2*PI/(RAD), dist = BASEDIST+8*(meals%10); + // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); + phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); + myCan->add(phils[i].getLastMeal()); + } + if (forks[i].user == i) { + fangle = i*ARC + CLOSE; + fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; + } + else if((forks[i].user == (i+1)%numPhils)) { + fangle = ((i+1)*ARC) - CLOSE; + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; + } else { + FORK_RAD = 140; + fangle = pangle + PI / numPhils; + } + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Table.h b/src/examples/DiningPhilosophers/Table.h new file mode 100644 index 000000000..c6ec53f5e --- /dev/null +++ b/src/examples/DiningPhilosophers/Table.h @@ -0,0 +1,58 @@ +/*! + * \class Table + * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. + * \details The Table class keeps track of the forks and philosophers in the Dining + * Philosophers' problem; it additionally manages the actions of the philosophers. + * \details Each step of the problem is broken up into two phases. In the checking phase, + * the philosophers look at the table around them and, without communicating with the + * other philosophers, determine an action to take based on their state and the states + * of their adjacent forks. + * \details In the action phase, each philosopher attempts to execute the action previously + * determined in the checking phase. If unsuccessful, the philosopher does nothing; + * otherwise, the philosopher's state changes depending on the action taken. + */ + +#ifndef TABLE_H_ +#define TABLE_H_ + +#include +#include "Philosopher.h" + +using namespace tsgl; + +class Table { +private: + int numPhils; + PhilMethod myMethod; + std::wstring methodString; + Canvas *myCan, *myCan2; + Philosopher *phils; + Fork *forks; + Circle * myTable; + Image ** spaghettis; + Text ** legendTexts; + RegularPolygon * exampleMeal; + // TextureHandler loader; +public: + Table(Canvas& can, int p, PhilMethod m); + + ~Table(); + + void forfeitWhenBlockedMethod(int id); + + void waitWhenBlockedMethod(int id); + + void nFrameReleaseMethod(int id); + + void hierarchyMethod(int id); + + void oddEvenMethod(int id); + + void checkStep(); + + void actStep(); + + void drawStep(); +}; + +#endif /* TABLE_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/philEnums.h b/src/examples/DiningPhilosophers/philEnums.h new file mode 100644 index 000000000..17390208e --- /dev/null +++ b/src/examples/DiningPhilosophers/philEnums.h @@ -0,0 +1,22 @@ +#ifndef PHIL_ENUM_H_ +#define PHIL_ENUM_H_ + +/*! \brief Enum for valid states for the Dining Philosophers + */ +enum PhilState { + hasNone, hasRight, hasLeft, hasBoth, isFull, thinking +}; + +/*! \brief Enum for valid actions for the Dining Philosophers + */ +enum PhilAction { + doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth +}; + +/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem + */ +enum PhilMethod { + forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven +}; + +#endif /* PHIL_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/testPhilosophers.cpp b/src/examples/DiningPhilosophers/testPhilosophers.cpp new file mode 100644 index 000000000..eb2ac2076 --- /dev/null +++ b/src/examples/DiningPhilosophers/testPhilosophers.cpp @@ -0,0 +1,107 @@ +/* + * testPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. + * This file includes a main method, Philospher class, Fork class, and Table class. + * + * The program provides a visualization of the Dining Philosophers Problem + * in which philosophers sit around a table, think for a random amount of time, and then want to eat. + * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. + * This visualization includes six different ways of resolving the conflicts. + * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. + * + * Usage: ./DiningPhilosophers + * for enter: + * 'w' for waitWhenBlocked, which results in Deadlock + * 'f' for forfeitWhenBlocked, which results in Livelock + * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 + * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 + * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) + * + * for enter: + * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). + * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. + * + * If step-through is turned off, the spacebar pauses the visualization. + */ + +#include +#include +#include +#include "Table.h" +#include "Philosopher.h" + +using namespace tsgl; + +void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { + + PhilMethod method; + //switch statement to create table with resolution method + char resolutionMethod = RM[0]; + switch(resolutionMethod) { + case 'w': + method = waitWhenBlocked; //Deadlock + break; + case 'f': + method = forfeitWhenBlocked; //Livelock (when synchronized) + break; + case 'n': + method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 + break; + case 'r': + method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 + break; + case 'o': + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + default: + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + } + + Table t(can,philosophers,method); + + srand(time(NULL)); // seed the random number generator for thinking steps + + bool stepThrough = step; // Flag that determines whether the animation pauses between steps + bool paused = false; // Flag that determines whether the animation is paused + bool philPauses[philosophers]; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed + paused = !paused; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + }); + + #pragma omp parallel num_threads(philosophers) + { + while(can.isOpen()) { + can.sleep(); + if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { + if(stepThrough) { philPauses[omp_get_thread_num()] = true; } + t.checkStep(); + can.pauseDrawing(); + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock + #pragma omp barrier //Barrier for optional synchronization + } + t.actStep(); + t.drawStep(); + can.resumeDrawing(); + } + } + } +} + +int main(int argc, char* argv[]) { + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./DiningPhilosophers " + << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in Table.h" << std::endl; + } + int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 + int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 + bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); + std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven + Canvas c(-1, -1, 1300, 1000, "Dining Philosophers",1.0f/speed); + c.run(philosopherFunction,nphil,resM,stepThrough); +} diff --git a/src/examples/DiningPhilosophers3D/Fork3D.h b/src/examples/DiningPhilosophers3D/Fork3D.h new file mode 100644 index 000000000..6425a0a50 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Fork3D.h @@ -0,0 +1,53 @@ +/*! + * \struct Fork3D + * \brief Struct for the forks in the 3D visualization of the Dining Philosophers' problem + */ + +#ifndef FORK3D_H_ +#define FORK3D_H_ + +#include +using namespace tsgl; + +struct Fork3D { + int user, id; + ConcavePolygon * myShape; + Fork3D() { + user = -1; id = 0; + + const int POINTS = 20; // number of vertices in polygon + const float HEIGHT = 42; // 42 is preferred, but can be changed + const float WIDTH = 12; // 12 is preferred, but can be changed + float xs[POINTS], ys[POINTS]; + + // scales (out of 100) for the dimensions of the 3D fork + float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; + float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; + + // create the 3D fork points from the scale arrays + for(int i = 0; i < POINTS; ++i) { + // scale the 3D fork + xs[i] = WIDTH * xscale[i]; + ys[i] = HEIGHT * yscale[i]; + // xs[i] = xs[i]/100; + // ys[i] = ys[i]/100; + } + + //Add vertices + myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,WHITE); + } + void setCanvas( Canvas* can) { + can->add(myShape); + } + void draw(float x, float y, double angle, ColorFloat c) { + angle -= PI/2; + myShape->setColor(c); + myShape->setCenter(x, y, 0); + myShape->setYaw(angle*180/PI); + } + ~Fork3D() { + delete myShape; + } +}; + +#endif /* FORK3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Makefile b/src/examples/DiningPhilosophers3D/Makefile new file mode 100644 index 000000000..af6d2a1c3 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Makefile @@ -0,0 +1,63 @@ +# Makefile for DiningPhilosophers3D + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = Fork3D.h philEnums.h \ + +# Main source file +TARGET = test3DPhilosophers + +# Object files +ODIR = obj +_OBJ = Philosopher3D.o Table3D.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Philosopher3D.cpp b/src/examples/DiningPhilosophers3D/Philosopher3D.cpp new file mode 100644 index 000000000..b7e9c0b92 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Philosopher3D.cpp @@ -0,0 +1,120 @@ +#include "Philosopher3D.h" + +/*! + * \brief Explicitly constructs a new Philosopher3D. + * \details Explicit constructor for a new Philosopher3D object. + */ +Philosopher3D::Philosopher3D() { + setId(0,1); + myState = thinking; + myAction = doNothing; + myCylinder = NULL; + myCone = NULL; + numMeals = 0; +} + +Philosopher3D::~Philosopher3D() { + delete myCylinder; + delete myCone; + for (Pyramid * meal : meals) + { + delete meal; + } + meals.clear(); +} + +/** + * Adds Philosopher3D to Canvas or refreshes its color. + */ +void Philosopher3D::draw(Canvas& can, float x, float y) { + const float SIZE = 45; + if( !myCylinder) { + myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,RED); + can.add(myCylinder); + } + if( !myCone && myCylinder) { + myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorFloat(0.7,0,0,1)); + myCone->setRotationPoint(myCylinder->getCenterX(), myCylinder->getCenterY(), myCylinder->getCenterZ()); + can.add(myCone); + } +} + +/** + * Updates the Philosopher3D's color based on its state + */ +void Philosopher3D::refreshColor() { + ColorFloat c; + switch(myState) { + case hasNone: c=RED; break; + case hasRight: c=ORANGE; break; + case hasLeft: c=PURPLE; break; + case hasBoth: c=GREEN; break; + case isFull: c=BLUE; break; + case thinking: c=BLUE; break; + } + myCylinder->setColor(c); + myCone->setColor(ColorFloat(c.R*.7,c.G*.7,c.B*.7,c.A)); +} + +/** + * Adds a meal representation to meals and the Canvas + */ +void Philosopher3D::addMeal(float x, float y, float z) { + numMeals++; + meals.push_back(new Pyramid(x,y,z,3,8,4,0,0,90,ColorFloat(0.5,0.3,0,1))); +} + +Pyramid * Philosopher3D::getLastMeal() { + return meals.back(); +} + +/** + * Picks up a fork specified by its reference + */ +bool Philosopher3D::acquire(Fork3D& f) { + if (f.user >= 0) + return false; + if (f.id == myLeft) { + if (myState == hasNone) + myState = hasLeft; + else if (myState == hasRight) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + if (f.id == myRight) { + if (myState == hasNone) + myState = hasRight; + else if (myState == hasLeft) + myState = hasBoth; + else + return false; + f.user = id; + return true; + } + return false; +} + +/** + * Releases a fork specified by its reference + */ +bool Philosopher3D::release(Fork3D& f) { + if (f.user != id) + return false; + if (myState != isFull) + myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; + f.user = -1; + return true; +} + +/** + * Thinks and switches to hungry state if a random number is a multiple of 3. + */ +void Philosopher3D::think() { + if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state + setState(hasNone); + setAction(doNothing); + } +} diff --git a/src/examples/DiningPhilosophers3D/Philosopher3D.h b/src/examples/DiningPhilosophers3D/Philosopher3D.h new file mode 100644 index 000000000..0781393c4 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Philosopher3D.h @@ -0,0 +1,83 @@ +/*! + * \class Philosopher3D + * \brief Object representing a 3D philosopher in the Dining Philosophers' problem + * \details The Philosopher3D class contains variables and methods necessary for + * representing a philosopher at a table. Each Philosopher3D may acquire or release + * the fork to his left or to his right (or both), with his state changing + * accordingly. + */ + +#ifndef PHILOSOPHER3D_H_ +#define PHILOSOPHER3D_H_ + +#include +#include +#include "Fork3D.h" +#include "philEnums.h" + +class Philosopher3D { +private: + PhilState myState; + PhilAction myAction; + int id, myLeft, myRight; + unsigned int numMeals; + Cylinder *myCylinder; + Cone * myCone; + std::vector meals; +public: + Philosopher3D(); + ~Philosopher3D(); + void draw(Canvas& can, float x, float y); + void refreshColor(); + void addMeal(float x, float y, float z); + Pyramid * getLastMeal(); + bool acquire(Fork3D& f); + bool release(Fork3D& f); + void think(); + + // Mutators + /*! + * \brief Resets the Philosopher3D to thinking after he eats. + */ + void eat() { myState = thinking; myAction = doNothing;} + /*! + * \brief Mutator for myState + * \param s PhilState to set myState to. + */ + void setState(PhilState s) { myState = s; } + /*! + * \brief Mutator for myAction + * \param s PhilAction to set myAction to. + */ + void setAction(PhilAction a) { myAction = a; } + /*! + * \brief Mutator for id + * \param i Which philosopher id to mutate + * \param nphil Total number of philosophers. + */ + void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } + + //Accessors + /** + * Accessor for number of meals Philosopher3D has consumed. + */ + int getMeals() { return numMeals; } + /** + * Accessor for Philosopher3D's state. + */ + PhilState state() { return myState; } + /** + * Accessor for Philosopher3D's action. + */ + PhilAction action() { return myAction; } + /** + * Accessor for Philosopher3D's id. + */ + int getId() { return id; } + /** + * Accessor for Philosopher3D's cylinder. + */ + bool hasCylinder() { return myCylinder; } +}; + +#endif /* PHILOSOPHER3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Table3D.cpp b/src/examples/DiningPhilosophers3D/Table3D.cpp new file mode 100644 index 000000000..60fe9e951 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Table3D.cpp @@ -0,0 +1,489 @@ +#include "Table3D.h" + +/*! + * \brief Creates a new 3D Table of dining Philosopher3Ds. + * \details Explicit constructor for a new Table3D object. + * \param can The Canvas on which the Table3D is to be drawn. + * \param p Integer denoting the number of Philosopher3Ds at the Table3D + * \param m PhilMethod denoting how the Philosopher3Ds should interact. + */ +Table3D::Table3D(Canvas& can, int p, PhilMethod m) { + numPhils = p; + myCan = &can; + myTable = new Cylinder(0,0,-55,100,150,0,0,90,ColorFloat(0.5,0.5,0.5,1)); + can.add(myTable); + phils = new Philosopher3D[numPhils]; + forks = new Fork3D[numPhils]; + for (int i = 0; i < numPhils; ++i) { + phils[i].setId(i,numPhils); + forks[i].id = i; + forks[i].setCanvas(myCan); + } + // float delta = 2.0f / numPhils * PI; + // for(int i = 0; i < numPhils; i++) { + // myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); + // } + myMethod = m; + switch(myMethod) { + case forfeitWhenBlocked: + methodString = "forfeit when blocked"; + break; + case waitWhenBlocked: + methodString = "wait when blocked"; + break; + case nFrameRelease: + methodString = "release on nth frame"; + break; + case resourceHierarchy: + methodString = "hierarchical resources"; + break; + case oddEven: + methodString = "odd-even check"; + break; + default: + break; + } + + // myCan2 = new Canvas(0,0,300,300,"Legend"); + // myCan2->start(); + // myCan2->drawText("Method:",16,32,32,BLACK); + // myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); + // myCan2->drawText("Legend:",16,96,24,BLACK); + // myCan2->drawText("Red: Hungry",32,128,24,RED); + // myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); + // myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); + // myCan2->drawText("Green: Eating",32,224,24,GREEN); + // myCan2->drawText("Blue: Thinking",32,256,24,BLUE); + // myCan2->drawText("Meals eaten: ",32,288,24,BROWN); + // myCan2->drawCircle(165,281,3,BROWN); +} + +/*! + * \brief Destructor for Table3D. + */ +Table3D::~Table3D() { + // if (myCan2->isOpen()) + // myCan2->stop(); + // delete myCan2; + delete myTable; + delete [] phils; + delete [] forks; +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the id numbers for the left and the right Philsopher's state. + * - Switch for the state of a Philosopher3D: + * - Philosopher3D has no fork: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Deadlock amongst threads. + */ +void Table3D::forfeitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(releaseRight); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].setState(hasNone); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch for the state of the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This is an example of Livelock amongst threads. + */ +void Table3D::waitWhenBlockedMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states of the left and right Philosopher3Ds. + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the right fork is free, try to get that fork. + * - Else, if the left fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has right fork: + * - If the left fork is free, try to get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the right fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas + * modulo the number of Philosopher3Ds+1, then release the left fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::nFrameReleaseMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseRight); + else + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else { + if (id == (myCan->getFrameNumber() % numPhils+1)) + phils[id].setAction(releaseLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Store the states for the left and right Philosopher3Ds. + * - Switch statement for the state of the current Philosopher3D. + * - Philosopher3D has no forks: + * - If the right Philosopher3D's id is less than the left Philsopher's id: + * - If the right fork is free, try to get that fork. + * - Else, do nothing. + * . + * - Else, if the left fork is free then try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the right fork: + * - If the left fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has the left fork: + * - If the right fork is free, try and get that fork. + * - Else, do nothing. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + */ +void Table3D::hierarchyMethod(int id) { + int left = id, right = (id+numPhils-1)%numPhils; + switch(phils[id].state()) { + case hasNone: + if (right < left) { + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + } else { + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else + phils[id].setAction(doNothing); + } + break; + case hasRight: + if (forks[left].user == -1) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(doNothing); + } + break; + case hasLeft: + if (forks[right].user == -1) + phils[id].setAction(tryRight); + else + phils[id].setAction(doNothing); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + + /*! + * \brief Method for determining which fork a Philosopher3D should get. + * \details + * - Switch statement for the current Philosopher3D: + * - Philosopher3D has no forks: + * - If the Philosopher3D's id is even + * - Philosopher3D has right fork (odd id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the left fork. + * - Else, release the right fork. + * . + * - Philosopher3D has left fork (even id): + * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number + * modulo 2, then try and get the right fork. + * - Else, release the left fork. + * . + * - Philosopher3D has both forks: + * - Release both of them. + * . + * . + * . + * \param id The id number of the current Philosopher3D. + * \note This method is the one that works best. + */ +void Table3D::oddEvenMethod(int id) { + switch(phils[id].state()) { + case hasNone: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryBoth); + else + phils[id].setAction(doNothing); + break; + case hasRight: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryLeft); + else { + phils[id].setAction(releaseRight); + } + break; + case hasLeft: + if ((id % 2) == (myCan->getFrameNumber() % 2)) + phils[id].setAction(tryRight); + else + phils[id].setAction(releaseLeft); + break; + case hasBoth: + phils[id].setAction(releaseBoth); + break; + case thinking: + phils[id].think(); + break; + default: + break; + } +} + +/*! + * \brief Method for determining which method of resolution the philosopher is using. + */ +void Table3D::checkStep() { + int i = omp_get_thread_num(); + if (phils[i].state() == isFull) { + phils[i].eat(); + return; + } + switch(myMethod) { + case forfeitWhenBlocked: + forfeitWhenBlockedMethod(i); + break; + case waitWhenBlocked: + waitWhenBlockedMethod(i); + break; + case nFrameRelease: + nFrameReleaseMethod(i); + break; + case resourceHierarchy: + hierarchyMethod(i); + break; + case oddEven: + oddEvenMethod(i); + break; + default: + break; + } +} + +/*! + * \brief Method for philosopher to act based on myAction. + */ +void Table3D::actStep() { + // myCan2->sleep(); + int i = omp_get_thread_num(); + int left = i, right = (i+numPhils-1)%numPhils; + switch(phils[i].action()) { + case tryLeft: + phils[i].acquire(forks[left]); + break; + case tryRight: + phils[i].acquire(forks[right]); + break; + case tryBoth: + phils[i].acquire(forks[left]); + phils[i].acquire(forks[right]); + break; + case releaseLeft: + phils[i].release(forks[left]); + break; + case releaseRight: + phils[i].release(forks[right]); + break; + case releaseBoth: + phils[i].release(forks[left]); + phils[i].release(forks[right]); + break; + default: + break; + } +} + +/*! + * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. + */ +void Table3D::drawStep() { + const float RAD = 195; + float FORK_RAD = 130; + const float ARC =2*PI/numPhils; + const float CLOSE = 0.15f; + const float BASEDIST = RAD+58; + + int i = omp_get_thread_num(); + float pangle = (i*2*PI)/numPhils; + ColorFloat fcolor = WHITE; + float fangle = (i+0.5f)*ARC; + + if( !phils[i].hasCylinder() ) { + phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); + } + + phils[i].refreshColor(); + if( phils[i].state() == isFull ) { + int meals = phils[i].getMeals(); + float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+8*(meals%10); + // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); + phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); + myCan->add(phils[i].getLastMeal()); + } + if (forks[i].user == i) { + fangle = i*ARC + CLOSE; + fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; + } + else if((forks[i].user == (i+1)%numPhils)) { + fangle = ((i+1)*ARC) - CLOSE; + fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; + } else { + FORK_RAD = 120; + fangle = pangle + PI / numPhils; + } + forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/Table3D.h b/src/examples/DiningPhilosophers3D/Table3D.h new file mode 100644 index 000000000..daf857b5c --- /dev/null +++ b/src/examples/DiningPhilosophers3D/Table3D.h @@ -0,0 +1,55 @@ +/*! + * \class Table3D + * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. + * \details The Table3D class keeps track of the forks and philosophers in the Dining + * Philosophers' problem; it additionally manages the actions of the philosophers. + * \details Each step of the problem is broken up into two phases. In the checking phase, + * the philosophers look at the 3D table around them and, without communicating with the + * other philosophers, determine an action to take based on their state and the states + * of their adjacent forks. + * \details In the action phase, each philosopher attempts to execute the action previously + * determined in the checking phase. If unsuccessful, the philosopher does nothing; + * otherwise, the philosopher's state changes depending on the action taken. + */ + +#ifndef TABLE3D_H_ +#define TABLE3D_H_ + +#include +#include "Philosopher3D.h" + +using namespace tsgl; + +class Table3D { +private: + int numPhils; + PhilMethod myMethod; + std::string methodString; + Canvas *myCan/* , *myCan2 */; + Philosopher3D *phils; + Fork3D *forks; + Cylinder * myTable; + // TextureHandler loader; +public: + Table3D(Canvas& can, int p, PhilMethod m); + + ~Table3D(); + + void forfeitWhenBlockedMethod(int id); + + void waitWhenBlockedMethod(int id); + + void nFrameReleaseMethod(int id); + + void hierarchyMethod(int id); + + void oddEvenMethod(int id); + + void checkStep(); + + void actStep(); + + void drawStep(); +}; + +#endif /* TABLE3D_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/philEnums.h b/src/examples/DiningPhilosophers3D/philEnums.h new file mode 100644 index 000000000..17390208e --- /dev/null +++ b/src/examples/DiningPhilosophers3D/philEnums.h @@ -0,0 +1,22 @@ +#ifndef PHIL_ENUM_H_ +#define PHIL_ENUM_H_ + +/*! \brief Enum for valid states for the Dining Philosophers + */ +enum PhilState { + hasNone, hasRight, hasLeft, hasBoth, isFull, thinking +}; + +/*! \brief Enum for valid actions for the Dining Philosophers + */ +enum PhilAction { + doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth +}; + +/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem + */ +enum PhilMethod { + forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven +}; + +#endif /* PHIL_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp b/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp new file mode 100644 index 000000000..01fe01236 --- /dev/null +++ b/src/examples/DiningPhilosophers3D/test3DPhilosophers.cpp @@ -0,0 +1,107 @@ +/* + * test3DPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. + * This file includes a main method, Philospher3D class, Fork3D class, and Table3D class. + * + * The program provides a 3D visualization of the Dining Philosophers Problem + * in which philosophers sit around a table, think for a random amount of time, and then want to eat. + * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. + * This visualization includes six different ways of resolving the conflicts. + * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. + * + * Usage: ./test3DPhilosophers + * for enter: + * 'w' for waitWhenBlocked, which results in Deadlock + * 'f' for forfeitWhenBlocked, which results in Livelock + * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 + * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 + * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) + * + * for enter: + * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). + * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. + * + * If step-through is turned off, the spacebar pauses the visualization. + */ + +#include +#include +#include +#include "Table3D.h" +#include "Philosopher3D.h" + +using namespace tsgl; + +void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { + + PhilMethod method; + //switch statement to create table with resolution method + char resolutionMethod = RM[0]; + switch(resolutionMethod) { + case 'w': + method = waitWhenBlocked; //Deadlock + break; + case 'f': + method = forfeitWhenBlocked; //Livelock (when synchronized) + break; + case 'n': + method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 + break; + case 'r': + method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 + break; + case 'o': + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + default: + method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 + break; + } + + Table3D t(can,philosophers,method); + + srand(time(NULL)); // seed the random number generator for thinking steps + + bool stepThrough = step; // Flag that determines whether the animation pauses between steps + bool paused = false; // Flag that determines whether the animation is paused + bool philPauses[philosophers]; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed + paused = !paused; + for(int i = 0; i < philosophers; i++) { + philPauses[i] = false; + } + }); + + #pragma omp parallel num_threads(philosophers) + { + while(can.isOpen()) { + can.sleep(); + if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { + if(stepThrough) { philPauses[omp_get_thread_num()] = true; } + t.checkStep(); + can.pauseDrawing(); + if(method == forfeitWhenBlocked) { //Synchronize to see Livelock + #pragma omp barrier //Barrier for optional synchronization + } + t.actStep(); + t.drawStep(); + can.resumeDrawing(); + } + } + } +} + +int main(int argc, char* argv[]) { + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./test3DPhilosophers " + << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in tests/test3DPhilosophers.cpp" << std::endl; + } + int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 + int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 + bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); + std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven + Canvas c(-1, -1, 1300, 1000, "3D Dining Philosophers",1.0f/speed); + c.run(philosopherFunction,nphil,resM,stepThrough); +} diff --git a/src/examples/Makefile b/src/examples/Makefile new file mode 100644 index 000000000..d556b3ebd --- /dev/null +++ b/src/examples/Makefile @@ -0,0 +1,23 @@ +# Master Makefile for Examples + +# ***************************************************** + +SUBDIRS_TO_BUILD := $(wildcard */.) # Used to build the examples +SUBDIRS_TO_CLEAN := $(subst /.,..., $(SUBDIRS_TO_BUILD)) # Used to clean the examples + +all: $(SUBDIRS_TO_BUILD) + +$(SUBDIRS_TO_BUILD): + @echo "" + @tput setaf 3; + @echo "++++++++++++++++ Generating Binaries for$(subst /., , $@)++++++++++++++++" + @tput sgr0; + @echo "" + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) + +clean: $(SUBDIRS_TO_CLEAN) + +$(SUBDIRS_TO_CLEAN): + cd $(subst ...,/.,$@) && $(MAKE) clean diff --git a/src/examples/MergeSort/Makefile b/src/examples/MergeSort/Makefile new file mode 100644 index 000000000..f9a3a1cbe --- /dev/null +++ b/src/examples/MergeSort/Makefile @@ -0,0 +1,63 @@ +# Makefile for MergeSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMergeSort + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/MergeSort/testMergeSort.cpp b/src/examples/MergeSort/testMergeSort.cpp new file mode 100644 index 000000000..04e95382f --- /dev/null +++ b/src/examples/MergeSort/testMergeSort.cpp @@ -0,0 +1,204 @@ +/* + * testMergeSort.cpp + * + * Usage: ./testMergeSort + */ + +#include +#include + +using namespace tsgl; + +enum MergeState { + S_MERGE = 1, + S_SHIFT = 2, + S_WAIT = 3, + S_DONE = 4, + S_HIDE = 5 +}; + +struct sortData { + ColorFloat color; //Color of the thread + MergeState state; //Current state of the threads + int first, last, //Start and end of our block + left, right, //Indices of two numbers to compare + fi, hi, li, //Indices of first middle and last numbers in a set + depth; //Current depth of the merge + float* a; //Array of numbers to sort + int seg, segs; //Current / total segments + int size; + + sortData(float* arr, int f, int l, ColorFloat c) { + fi = hi = li = 0; //Initialize indices + left = right = 0; //Initialize bounds + color = c; //Set the color + a = arr; //Get a pointer to the array we'll be sorting + first = f; //Set the first element we need to worry about + last = l; //Set the last element we need to worry about + depth = 0; //We start at depth 0 + seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment + while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done + ++depth; //Otherwise, increment the depth... + segs *= 2; //...and double the number of segments + } + state = S_SHIFT; //Start Merging + size = 2; + } + + void restart(int l) { + depth = 0; + hi = last; + right = hi+1; + last = li = l; + fi = left = first; + state = S_MERGE; + size *= 2; + } + + void sortStep() { + float tmp; + int pivot, jump; + switch(state) { + case S_SHIFT: + pivot = jump = segs/2; + fi = first; li = last; + hi = (fi + li) / 2; //Set our half index to the median of our first and last + for (tmp = depth; tmp > 0; --tmp) { + jump /= 2; + if (seg < pivot) { + pivot -= jump; + li = hi; //Set out last index to our old half index + } else { + pivot += jump; + fi = hi+1; //Set out first index to our old half index plus one + } + hi = (fi + li) / 2; //Set our new half index to the median of our first and last + } + left = fi; right = hi+1; + state = S_MERGE; //We're ready to start Merging + break; + case S_MERGE: + if (left > right || right > last) { + seg = 0; //Reset our segment(s) + segs /= 2; //We're now using half as many segments + state = (depth-- == 0) ? S_WAIT : S_SHIFT; + } else if (right > li) { + ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices + } else if (left <= hi && a[left] < a[right]) { + ++left; + } else { + tmp = a[right]; + for (int x = right; x > left; --x) + a[x] = a[x-1]; + a[left] = tmp; + ++left; ++right; ++hi; + } + break; + default: + break; + } + } +}; + +/*! + * \brief Visualization of the bottom-up mergesort algorithm. + * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. + * \details Uses lines to represent the items being sorted. + * \details At the start, the items being sorted are all divided. + * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. + * \details Different colors represent different sections being sorted. + * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. + */ +void mergeSortFunction(Canvas& can, int threads, int size) { + const int IPF = 1; // Iterations per frame + float* numbers = new float[size]; // Array to store the data + Rectangle** rectangles = new Rectangle*[size]; // Array to store the data + float start = -can.getWindowWidth() * .45; + float width = can.getWindowWidth() * .9 / size; + for (int i = 0; i < size; i++) { + numbers[i] = saferand(1,can.getWindowHeight()); + rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); + can.add(rectangles[i]); + } + + int baseNumVals = size / threads; + int extraVals = size % threads; + sortData** sd = new sortData*[threads]; + int firstIndex = 0; + int lastIndex = (extraVals == 0) ? baseNumVals-1 : baseNumVals; + for (int i = 0; i < threads; ++i) { + sd[i] = new sortData(numbers,firstIndex,lastIndex,Colors::highContrastColor(i)); + firstIndex = lastIndex+1; + if (i < extraVals-1) lastIndex += (baseNumVals + 1); + else lastIndex += baseNumVals; + } + while (can.isOpen()) { + #pragma omp parallel num_threads(threads) + { + int tid = omp_get_thread_num(); + can.sleep(); + if (sd[tid]->state == S_WAIT) { //Merge waiting threads + if ((tid % sd[tid]->size) > 0) + sd[tid]->state = S_DONE; + else { + int next = tid+sd[tid]->size/2; + if (next < threads && sd[next]->state == S_DONE) { + sd[next]->state = S_HIDE; + sd[tid]->restart(sd[next]->last); + } + } + } + for (int i = 0; i < IPF; i++) + sd[tid]->sortStep(); + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + float height; + ColorFloat color; + if (sd[tid]->state != S_HIDE) { + //Draw a black rectangle over our portion of the screen to cover up the old drawing + // can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); + for (int i = sd[tid]->first; i <= sd[tid]->last; ++i, ++start) { + height = numbers[i]; + if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) + color = WHITE; + else { + if (i == sd[tid]->right || i == sd[tid]->left) + color = WHITE; + else if (i < sd[tid]->left) + color = sd[tid]->color; + else if (i >= sd[tid]->fi && i <= sd[tid]->li) + color = Colors::blend(sd[tid]->color, WHITE, 0.5f); + else + color = Colors::blend(sd[tid]->color, BLACK, 0.5f); + } + rectangles[i]->setHeight(height); + rectangles[i]->setColor(color); + } + } + can.resumeDrawing(); //Tell the Canvas it can resume updating + } + } + for (int i = 0; i < threads; ++i) + delete sd[i]; + delete [] sd; + delete [] numbers; + for (int i = 0; i < size; i++) { + delete rectangles[i]; + } + delete [] rectangles; +} + +//Takes in command line arguments for the window width and height +//as well as for the number of threads to use +int main(int argc, char* argv[]) { + int s = (argc > 1) ? atoi(argv[1]) : 1024; + if (s < 10) s = 10; + int w = s * 1.3; + int h = w/2; + + int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); + for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 + + Canvas c(0, 0, w, h, "Bottom-up Merge Sort"); + c.setBackgroundColor(BLACK); + c.run(mergeSortFunction, threads, s); +} diff --git a/src/examples/NewtonPendulum/Makefile b/src/examples/NewtonPendulum/Makefile new file mode 100644 index 000000000..ed460d696 --- /dev/null +++ b/src/examples/NewtonPendulum/Makefile @@ -0,0 +1,63 @@ +# Makefile for NewtonPendulum + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testNewtonPendulum + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/NewtonPendulum/testNewtonPendulum.cpp b/src/examples/NewtonPendulum/testNewtonPendulum.cpp new file mode 100644 index 000000000..180361c3c --- /dev/null +++ b/src/examples/NewtonPendulum/testNewtonPendulum.cpp @@ -0,0 +1,134 @@ +/* + * testNewtonPendulum.cpp + * + * Usage: ./testNewtonPendulum + */ + +#include "tsgl.h" +#include "Util.h" + +using namespace tsgl; + +/*! + * \brief Simulates Newton's Cradle (or Newton's Pendulum as some call it) ( see http://s.hswstatic.com/gif/newtons-cradle-1.jpg ). + * \details Simulates Newton's Pendulum in the following way: + * - User variables store the sizes of each ball, the number of balls (command-line argument), and the radius of each ball. + * They also store the acceleration, top speed, and the amount to inverse the direction of the swing of the balls. + * - Automatic variables store the window width and height, the center of the window, the line length, and the offset of each ball. + * - Initial positions of the edge balls are determined. + * - The leftmost ball is stationary; the rightmost is moving at top speed. + * - While the Canvas has not been closed: + * - The Canvas' internal timer is put to sleep until the next drawing loop. + * - Conditionals determine the left and right ball motion. + * - The animation loop is paused. + * - The Canvas is cleared. + * - The stationary balls and lines are drawn first, followed by the moving balls and lines. + * - The animation is resumed. + * . + * . + * \param can Reference to the Canvas to draw on. + * \param numberOfBalls The number of balls to use in the function. + */ + +void newtonPendulumFunction(Canvas& can, int numberOfBalls) { + //User variables + const int BALLS = numberOfBalls, //Keep this odd + RADIUS = 20; //Radius of circles + const float ACCEL = 0.5f, //Acceleration of balls + TOPSPEED = 9.0f, //Starting speed of balls + AMP = 100; //Inverse amplitude of balls + + const float LINELEN = can.getWindowHeight() / 2, + OFFSET = RADIUS*(BALLS-1); + + Line ** lines = new Line*[BALLS - 2]; + Circle ** balls = new Circle*[BALLS - 2]; + for (int i = -(BALLS/2)+1; i < BALLS/2; ++i) { + lines[i + BALLS/2 - 1] = new Line(RADIUS*2*i,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + can.add(lines[i + BALLS/2 - 1]); + balls[i + BALLS/2 - 1] = new Circle(RADIUS*2*i,0,0, RADIUS, 0,0,0,GRAY); + can.add(balls[i + BALLS/2 - 1]); + } + + //Add moving Shapes + Circle* leftCircle = new Circle(-OFFSET,0,0, RADIUS, 0,0,0,GRAY); + leftCircle->setRotationPoint(-OFFSET, LINELEN, 0); + Circle* rightCircle = new Circle(OFFSET,0,0, RADIUS, 0,0,0,GRAY); + rightCircle->setRotationPoint(OFFSET, LINELEN, 0); + Line* leftLine = new Line(-OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + leftLine->setRotationPoint(-OFFSET, LINELEN, 0); + Line* rightLine = new Line(OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); + rightLine->setRotationPoint(OFFSET, LINELEN, 0); + can.add(rightLine); can.add(leftLine); + can.add(leftCircle); can.add(rightCircle); + + //Computation + float rightPos = 0, leftPos = 0; //Initial positions of the edge balls + float leftMoving = 0, rightMoving = TOPSPEED; //Right goes first, left stays stationary + while(can.isOpen()) { + can.sleep(); + + //Drawing conditional for right ball motion + if(rightMoving != 0 || rightPos != 0) { //If the ball isn't stationary + rightMoving -= ACCEL; + rightPos += rightMoving; //Move it + if(rightPos < 0) { //If its hit the stopping point + leftMoving = -TOPSPEED; //Make it stationary and make the left ball move + rightMoving = 0; + rightPos = 0; //Reset the stopping point + } + } + //Drawing conditional for left ball motion + //Similar to the right ball motion, but with the left stop value and left ball + if(leftMoving != 0 || leftPos != 0) { + leftMoving += ACCEL; + leftPos += leftMoving; + if(leftPos > 0) { + rightMoving = TOPSPEED; + leftMoving = 0; + leftPos = 0; + } + } + + //Move the lines and balls! + //Left + leftLine->setYaw(leftPos/AMP * 180 / PI - 90); + leftCircle->setYaw(leftPos/AMP * 180 / PI); + //Right + rightLine->setYaw(rightPos/AMP * 180 / PI - 90); + rightCircle->setYaw(rightPos/AMP * 180 / PI); + } + + delete leftCircle; + delete rightCircle; + delete leftLine; + delete rightLine; + for (int i = 0; i < BALLS - 2; i++) { + delete balls[i]; + delete lines[i]; + } + delete [] balls; + delete [] lines; +} + +//Takes command line arguments for the width and height of the screen +//as well as for the number of balls +int main(int argc, char * argv[]) { + //Width and height + int w = (argc > 1) ? atoi(argv[1]) : 1.2 * Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75 * w; + int numberOfBalls = atoi(argv[3]); //Number of balls + if(w <= 0 || h <= 0) { + w = 1200; + h = 900; + } + //Determine if the number of balls is valid + if(numberOfBalls <= 0) { //If negative, set it to 7 + numberOfBalls = 7; + } else if(numberOfBalls % 2 == 0) { //If even, add 1 + numberOfBalls++; + } + Canvas c(-1, -1, w, h, "Newton's Pendulum"); + c.setBackgroundColor(WHITE); + c.run(newtonPendulumFunction,numberOfBalls); +} diff --git a/src/examples/Pandemic/Makefile b/src/examples/Pandemic/Makefile new file mode 100644 index 000000000..ad3608c88 --- /dev/null +++ b/src/examples/Pandemic/Makefile @@ -0,0 +1,63 @@ +# Makefile for Pandemic + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = statusEnums.h + +# Main source file +TARGET = testPandemic + +# Object files +ODIR = obj +_OBJ = Pandemic.o Person.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Pandemic/Pandemic.cpp b/src/examples/Pandemic/Pandemic.cpp new file mode 100644 index 000000000..b799c8622 --- /dev/null +++ b/src/examples/Pandemic/Pandemic.cpp @@ -0,0 +1,64 @@ +#include "Pandemic.h" + +#define RADIUS 5 + +using namespace tsgl; + +Pandemic::Pandemic(Canvas& can, unsigned numPeople){ + // current day + current_day = 0; + // people counters + number_of_people = numPeople; + num_initially_infected = 0; + // states counters + num_infected = 0; + num_susceptible = numPeople; + num_immune = 0; + num_dead = 0; + + // stats + num_infections = 0; + num_infection_attempts = 0; + num_deaths = 0; + num_recoveries = 0; + + // Generate random seed + srand( time(0) ); + // // Set radius + // float radius = 250/number_of_people; + // Fill vectors + for(unsigned i = 0; i < number_of_people; ++i){ + myPersons.push_back(new Person(rand()%(can.getWindowWidth())-(can.getWindowWidth())/2, + rand()%(can.getWindowHeight())-can.getWindowHeight()/2, + RADIUS, susceptible)); // myPersons + x_locations.push_back(myPersons[i]->getX()); // x_locations + y_locations.push_back(myPersons[i]->getY()); // y_locations + infected_x_locations.push_back(0); // infected_x_locations + infected_y_locations.push_back(0); // infected_y_locations + states.push_back(susceptible); // states + num_days_infected.push_back(0); // num_days_infected + } + +} + +void Pandemic::draw(Canvas& can){ + for(unsigned i = 0; i < number_of_people; ++i){ + myPersons[i]->draw(can); + } +} + +/*! + * \brief Destructor for Pandemic. + */ +Pandemic::~Pandemic(){ + for(unsigned i = 0; i < number_of_people; ++i){ + delete myPersons[i]; + } + myPersons.clear(); + x_locations.clear(); + y_locations.clear(); + infected_x_locations.clear(); + infected_y_locations.clear(); + states.clear(); + num_days_infected.clear(); +} \ No newline at end of file diff --git a/src/examples/Pandemic/Pandemic.h b/src/examples/Pandemic/Pandemic.h new file mode 100644 index 000000000..da12fb190 --- /dev/null +++ b/src/examples/Pandemic/Pandemic.h @@ -0,0 +1,88 @@ +#ifndef PANDEMIC_H_ +#define PANDEMIC_H_ + +#include +#include +#include "Person.h" +#include "statusEnums.h" + +using namespace tsgl; + +class Pandemic { +private: + char* myName; +protected: + // persons + std::vector myPersons; + // current day + unsigned current_day; + // people counters + unsigned number_of_people; + unsigned num_initially_infected; + // states counters + unsigned num_infected; + unsigned num_susceptible; + unsigned num_immune; + unsigned num_dead; + // locations + std::vector x_locations; + std::vector y_locations; + //infected people's locations + std::vector infected_x_locations; + std::vector infected_y_locations; + // state + std::vector states; + // infected time + std::vector num_days_infected; + + // stats + unsigned num_infections; + unsigned num_infection_attempts; + unsigned num_deaths; + unsigned num_recoveries; +public: + Pandemic(Canvas& can, unsigned numPeople); + + void draw(Canvas& can); + + // Accessors + Person * getPerson(unsigned i) { return myPersons[i]; } + + unsigned getCurrentDay() { return current_day; } + + unsigned getNumPeople() { return number_of_people; } + + unsigned getNumInitiallyInfected() { return num_initially_infected; } + + unsigned getNumInfected() { return num_infected; } + + unsigned getNumSusceptible() { return num_susceptible; } + + unsigned getNumImmune() { return num_immune; } + + unsigned getNumDead() { return num_dead; } + + int getXLocation(unsigned i) { return x_locations[i]; } + + int getYLocation(unsigned i) { return y_locations[i]; } + + int getInfectedXLocation(unsigned i) { return infected_x_locations[i]; } + + int getInfectedYLocation(unsigned i) { return infected_y_locations[i]; } + + int getState(unsigned i) { return states[i]; } + + int getNumDaysInfected(unsigned i) { return num_days_infected[i]; } + + unsigned numInfections() { return num_infections; } + + unsigned getNumInfectionAttempts() { return num_infection_attempts; } + + unsigned getNumDeaths() { return num_deaths; } + + unsigned getNumRecoveries() { return num_recoveries; } + + virtual ~Pandemic(); +}; + +#endif /* PANDEMIC_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/Person.cpp b/src/examples/Pandemic/Person.cpp new file mode 100644 index 000000000..d1afa89a4 --- /dev/null +++ b/src/examples/Pandemic/Person.cpp @@ -0,0 +1,167 @@ +#include "Person.h" + +using namespace tsgl; + +Person::Person(float x, float y, GLfloat radius, char status){ + myX = x; + myY = y; + myCircleRadius = radius; + myStatus = status; + + switch(myStatus){ + case susceptible : + myColor = ColorFloat(1,1,0,1); + break; + case infected : + myColor = ColorFloat(1,0,0,1); + break; + case immune : + myColor = ColorFloat(0,1,0,1); + break; + case dead : + myColor = ColorFloat(0.5,0.5,0.5,1); + break; + default: + myColor = ColorFloat(0,0,0,1); + } + + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); + +} + +/** + * \brief Adds the Person to the canvas. + * \param can The Canvas on which the Person is to be drawn. + */ +void Person::draw(Canvas& can){ + can.add(myCircle); +} + +/** + * \brief Sets the radius of the Person's Circle to a new radius. + * \param radius The new radius. + */ +void Person::setCircleRadius(GLfloat radius){ + myCircle->setRadius(radius); +} + +// /** +// * \brief Sets the Person's Cubes to a new color. +// * \param color The new ColorFloat. +// */ +// void Person::setColor(ColorFloat color){ +// for (Cube * c : myCubes){ +// c->setColor(color); +// } +// } + +// /** +// * \brief Sets the Person's Cubes to new colors. +// * \param c The new array of ColorFloats. +// * \param size The size of the array of ColorFloats +// */ +// void Person::setColor(ColorFloat c[], unsigned size){ +// for(unsigned i = 0; i < mySize; ++i){ +// myCubes[i]->setColor(c[i%size]); +// } +// } + +// /** +// * \brief Sets the Person's Text/numbers to a new color. +// * \param color The new ColorFloat. +// */ +// void Person::setTextColor(ColorFloat color){ +// for(Text * t : myText){ +// t->setColor(color); +// } +// } + +// /** +// * \brief Sets the font of the Person's Text/numbers to a new font. +// * \param filename The path and file name of the font. +// */ +// void Person::setFont(std::string filename){ +// for(Text * t : myText){ +// t->setFont(filename); +// } +// } + +// /** +// * \brief Sets the font size of the Person's Text/numbers to a new size. +// * \param fontsize The new font size. +// */ +// void Person::setFontSize(unsigned int fontsize){ +// for(Text * t : myText){ +// t->setFontSize(fontsize); +// } +// } + + +// void Person::changeYawBy(GLfloat yaw){ +// for(unsigned i = 0; i < mySize; ++i){ +// myCubes[i]->changeYawBy(yaw); +// myText[i]->changeYawBy(yaw); +// } +// } + +// void Person::changePitchBy(GLfloat pitch){ +// for(unsigned i = 0; i < mySize; ++i){ +// myCubes[i]->changePitchBy(pitch); +// myText[i]->changePitchBy(pitch); +// } +// } + +// void Person::changeRollBy(GLfloat roll){ +// for(unsigned i = 0; i < mySize; ++i){ +// myCubes[i]->changeRollBy(roll); +// myText[i]->changeRollBy(roll); +// } +// } + +// void Person::visualSplit(unsigned index){ +// for(unsigned i = 0; i < index; ++i){ +// myCubes[i]->changeXBy(-myCubeSideLength/2.0); +// myText[i]->changeXBy(-myCubeSideLength/2.0); +// } +// for(unsigned i = index; i < mySize; ++i){ +// myCubes[i]->changeXBy(myCubeSideLength/2.0); +// myText[i]->changeXBy(myCubeSideLength/2.0); +// } +// } + +// // void Person::visualRegroup(unsigned index){ + +// // } + +// void Person::visualRegroupAll(float x){ +// for(unsigned i = 0; i < mySize; i++){ +// myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); +// myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); +// } +// } + + +// /** +// * \brief If the sizes are equal, adds the values of two Persons and returns +// * the sums in a new Person. +// * If the sizes are not equal, returns a default-constructed Person. +// * \param c2 The Person to be added with the current one. +// */ +// Person Person::operator+(Person& c2){ +// if(mySize == c2.getSize()){ +// int summedArray[mySize]; +// for(unsigned i = 0; i < mySize; i++){ +// summedArray[i] = myData[i] + c2[i]; +// printf("%.2d\n", summedArray[i]); +// } +// return Person(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); +// } +// return Person(); +// } + +/*! + * \brief Destructor for Table. + */ +Person::~Person(){ + delete myCircle; +} \ No newline at end of file diff --git a/src/examples/Pandemic/Person.h b/src/examples/Pandemic/Person.h new file mode 100644 index 000000000..864292e64 --- /dev/null +++ b/src/examples/Pandemic/Person.h @@ -0,0 +1,77 @@ +#ifndef PERSON_H_ +#define PERSON_H_ + +#include +#include "Circle.h" +#include "statusEnums.h" + +using namespace tsgl; + +class Person { +protected: + float myX, myY; + GLfloat myCircleRadius; + Circle* myCircle; + // Circle* myCircle[1]; + ColorFloat myColor; + + // Pandemic data + char myStatus; + unsigned numDaysInfected; +public: + // Person(); + + Person(float x, float y, GLfloat radius, char status); + + void draw(Canvas& can); + + + // Accessors + GLfloat getCircleRadius() { return myCircleRadius; } + + Circle * getCircle() { return myCircle; } + + float getX() { return myX; } + + float getY() { return myY; } + + char getStatus() { return myStatus; } + + unsigned getNumDaysInfected() { return numDaysInfected; } + + + // // Mutators + // int& operator[](unsigned i) { return myData[i]; } + + void setCircleRadius(GLfloat radius); + + // void setColor(ColorFloat c); + + // void setColor(ColorFloat c[], unsigned size); + + // void setTextColor(ColorFloat c); + + // void setFont(std::string filename); + + // void setFontSize(unsigned int fontsize); + + + // void changeYawBy(GLfloat yaw); + + // void changePitchBy(GLfloat pitch); + + // void changeRollBy(GLfloat roll); + + // void visualSplit(unsigned index); + + // void visualRegroupAll(float x); + + // // Operations + // CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~Person(); +}; + +#endif /* PERSON_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/statusEnums.h b/src/examples/Pandemic/statusEnums.h new file mode 100644 index 000000000..4381e5859 --- /dev/null +++ b/src/examples/Pandemic/statusEnums.h @@ -0,0 +1,11 @@ +#ifndef STATUS_ENUM_H_ +#define STATUS_ENUM_H_ + +#include + +/*! \brief Enum for valid Person states for the Pandemic + */ +enum PersonState { + infected = 'v', immune = 'i', susceptible = 's', dead = 'd' +}; +#endif /* STATUS_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/testPandemic.cpp b/src/examples/Pandemic/testPandemic.cpp new file mode 100644 index 000000000..1c01f10bc --- /dev/null +++ b/src/examples/Pandemic/testPandemic.cpp @@ -0,0 +1,88 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [infectionRate] + 1 <= numPersons <= 200, defaults to 50 + 0 <= infectionRate <= 100, defaults to 20 + */ + +#include +#include +#include "Person.h" +#include "Pandemic.h" + +// disease constants +#define INFECTION_RADIUS 10 +// #define DURATION_OF_DISEASE +// #define contagiousness_factor; +// #define deadliness_factor; // +// time constants +#define NUM_DAYS 21 // total number of days for pandemic +#define MS_PER_DAY 200000; // microseconds per day + +using namespace tsgl; + +void pandemicFunction(Canvas& can, unsigned numPersons, unsigned infectionRate) { + // Generate random seed + srand( time(0) ); + + // Create Pandemic + Pandemic * p = new Pandemic(can, numPersons); + + float sleepTime = 0.125; // initial number of seconds to sleep 0.5 + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + p->draw(can); + + unsigned complete = 0; // ensures simulation only runs once + while (can.isOpen()) { + if(complete == 0){ + for(unsigned currentDay = 0; currentDay < NUM_DAYS; ++currentDay){ + + } + complete = 1; + } + } + + // Output + printf("\nStatistics and data: \ + \n\ + \nSusceptible: %d\ + \nInfected: %d\ + \nImmune: %d\ + \nDead: %d\ + \n", p->getNumSusceptible(), p->getNumInfected(), p->getNumImmune(), p->getNumDead()); + + // Deallocate all object memory + delete p; + +} + +int main(int argc, char* argv[]){ + int numPersons = (argc > 1) ? atoi(argv[1]) : 50; + int infectionRate = (argc > 2) ? atoi(argv[2]) : 20; + + // Checks validity of numPersons and infectionRate; if invalid, set to default + if((numPersons <= 0 or numPersons > 200)){ + printf("Invalid argument(s).\ + \nUsage: ./testPandemic [numPersons] [infectionRate]\n \ + 1 <= numPersons <= 200\ + 0 <= infectionRate <= 100 \ + \nUsing default parameters...\n"); + numPersons = 50; + infectionRate = 20; + } + + Canvas c(0, -1, 620, 620, "Pandemic Simulation"); + c.setBackgroundColor(BLACK); + c.run(pandemicFunction, numPersons, infectionRate); +} diff --git a/src/examples/Pandemic/testPerson.cpp b/src/examples/Pandemic/testPerson.cpp new file mode 100644 index 000000000..fd8a75b20 --- /dev/null +++ b/src/examples/Pandemic/testPerson.cpp @@ -0,0 +1,33 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [infectionRate] + 1 <= numPersons <= 100, defaults to 50 + 0 <= infectionRate <= 100, defaults to 20 + */ + +#include +#include +#include "Person.h" + +using namespace tsgl; + +void personFunction(Canvas& can) { + Person * p1 = new Person(0, 0, 50, susceptible); + + p1->draw(can); + + while (can.isOpen()) { + can.sleep(); + } + + // Deallocate all object memory + delete p1; + +} + +int main(int argc, char* argv[]){ + Canvas c(0, -1, 1820, 620, "Pandemic Simulation"); + c.setBackgroundColor(WHITE); + c.run(personFunction); +} diff --git a/src/examples/Pong/Ball.cpp b/src/examples/Pong/Ball.cpp new file mode 100644 index 000000000..676f6f47c --- /dev/null +++ b/src/examples/Pong/Ball.cpp @@ -0,0 +1,84 @@ +/* + * Ball.cpp + */ + +#include "Ball.h" + + + /*! + * \brief Explicitly construct the Ball object. + * \details Explicit constructor for the Ball object. + * \param can Reference to the Canvas that will have the Ball object. + * \param speed Reference to the speed of the Ball object. + * \return The constructed Ball object. + */ +Ball::Ball(Canvas& can, int & speed) { + mySpeed = speed; + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while(myXX > -4 && myXX < 4); + myCircle = new Circle(myX, myY, 0, 8, 0,0,0, WHITE); + can.add(myCircle); +} + + /*! + * \brief Accessor for the Ball object's current x-coordinate. + * \return myX The x-coordinate of the Ball object. + */ +float Ball::getX() const { + return myX; +} + + /*! + * \brief Accessor for the Ball object's current y-coordinate. + * \return myY The y-coordinate of the Ball object. + */ +float Ball::getY() const { + return myY; +} + + /*! + * \brief Invert the Ball's direction. + * \details The Ball's direction must be inverted whenever it collides with a Paddle object or + * when it touches one of the boundary walls in the game of Pong. + * \param choice Determines which coordinate value to invert (y-coordinate = 0, x-coordinate = 1). + * \see Paddle class, Pong class. + */ +void Ball::invert(int choice) { + if(choice == 0) { + myYY = -myYY; + } else if(choice == 1) { + myXX = -myXX; + myYY += randfloat(1000) * 2 - 1; + } +} + + /*! + * \brief Move the Ball object. + * \details Actually moves the Ball object around. + */ +void Ball::move() { + myX += myXX; + myY += myYY; + myCircle->setCenter(myX, myY, 0); +} + + /*! + * \brief Reset the Ball object's position. + * \details After a point is earned in the game of Pong, the Ball object's position must be reset back + * to the middle of the Canvas and its direction must be randomized again. + * \param can Reference to the Canvas object that has the Ball object. + */ +void Ball::reset(Canvas& can) { + myX = -8; + myY = -8; + do { + myDir = randfloat(1000) * 2 * PI; + myXX = mySpeed * cos(myDir); + myYY = mySpeed * sin(myDir); + } while (myXX > -4 && myXX < 4); +} diff --git a/src/examples/Pong/Ball.h b/src/examples/Pong/Ball.h new file mode 100644 index 000000000..322f5c471 --- /dev/null +++ b/src/examples/Pong/Ball.h @@ -0,0 +1,46 @@ +/* + * Ball.h + */ + +#ifndef BALL_H_ +#define BALL_H_ + +#include + +using namespace tsgl; + +/*! + * class Ball + * \brief We can't play Pong without a Ball! + * \details Creates the ball needed in order to play Pong. + * \details The constructor determines the speed and direction of the ball. + * \details The draw() method draws the ball onto the Canvas object. + * \details The ball's position is always reset after a point has been earned in the game. + * \details Collisions with the paddle or the boundaries are not handled here; they are handled in the Pong class' draw() method. + * \see Paddle class, Pong class. + */ +class Ball { + public: + Ball(Canvas& can, int & speed); + + float getX() const; + + float getY() const; + + void invert(int choice); + + void move(); + + void reset(Canvas& can); + + /*! + * \brief Destroys the Ball object. + */ + virtual ~Ball() { delete myCircle; } + +private: + float myX, myY, myXX, myYY, mySpeed, myDir; + Circle* myCircle; +}; + +#endif /* BALL_H_ */ diff --git a/src/examples/Pong/Makefile b/src/examples/Pong/Makefile new file mode 100644 index 000000000..2c1527bbc --- /dev/null +++ b/src/examples/Pong/Makefile @@ -0,0 +1,63 @@ +# Makefile for Pong + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPong + +# Object files +ODIR = obj +_OBJ = Ball.o Paddle.o Pong.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Pong/Paddle.cpp b/src/examples/Pong/Paddle.cpp new file mode 100644 index 000000000..091c7d9c2 --- /dev/null +++ b/src/examples/Pong/Paddle.cpp @@ -0,0 +1,86 @@ +/* + * Paddle.cpp + */ + +#include "Paddle.h" + + /*! + * \brief Explicitly constructs a Paddle object. + * \details Explicit constructor for a Paddle object. + * \param can Reference to the Canvas to have the Paddle object on. + * \param speed Reference to the speed of the Paddle object. + * \return The constructed Paddle object. + */ +Paddle::Paddle(Canvas& can, int & speed, int side) { + mySpeed = speed; + myDir = myPoints = 0; + myY = - 32; + myRect = new Rectangle(0,myY,0,24,64,0,0,0, BLACK); + if(side == -1) { //Left side + myRect->setColor(BLUE); + myRect->setCenterX(-can.getWindowWidth() / 2 + 20); + } else if(side == 1) { //Right side + myRect->setColor(RED); + myRect->setCenterX(can.getWindowWidth() / 2 - 20); + } + can.add(myRect); +} + + /*! + * \brief Binds the buttons. + * \details Binds the buttons with the Canvas. In this case, the keys that move the paddle up and down. + * \param can Reference to the Canvas to bind the keys to. + * \param side The side that the Paddle object is on (left = -1 and the W and S keys are bound, right = 1 and the Up and Down arrow keys are bound). + */ +void Paddle::bindings(Canvas& can, int side) { + if(side == 1) { //Right + can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = 1;}); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = -1;}); + can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); + } else if(side == -1) { //Left + can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = 1;}); + can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = -1;}); + can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); + can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); + } +} + + /*! + * \brief Increments the Paddle object's score in the game of Pong. + */ +void Paddle::increment() { + ++myPoints; +} + + /*! + * \brief Actually Moves the Paddle object up or down. + */ +void Paddle::move() { + myY += mySpeed * myDir; + myRect->changeYBy(mySpeed * myDir); +} + + /*! + * \brief Accessor for the score of the Paddle object. + * \return myPoints The current score of the Paddle object in the game of Pong. + */ +int Paddle::getPoints() const { + return myPoints; +} + + /*! + * \brief Accessor for the current y-coordinate of the Paddle object. + * \return myY The y-coordinate of the Paddle object. + */ +float Paddle::getY() const { + return myY; +} + + /*! + * \brief Mutator for the direction of the Paddle object. + * \details Changes the current direction of the Paddle object (up or down). + */ +void Paddle::setDir(int direction) { + myDir = direction; +} diff --git a/src/examples/Pong/Paddle.h b/src/examples/Pong/Paddle.h new file mode 100644 index 000000000..f5b56960b --- /dev/null +++ b/src/examples/Pong/Paddle.h @@ -0,0 +1,57 @@ +/* + * Paddle.h + */ + +#ifndef PADDLE_H_ +#define PADDLE_H_ + +#include +#include "Ball.h" + +using namespace tsgl; + +/*! + * class Paddle + * \brief How can you hit a ball without a paddle? + * \details Creates a Paddle in order to play the game, Pong. + * \details The W and S keys move the left paddle, the Up and Down arrow keys move the right paddle in the game. + * \details Collisions with the ball are not handled here; they are handled in the Pong class' draw() method. + * \details The left and right paddles in the game are created from this class; they are essentially the same object. + * However, there are side parameters in some of the methods that determine which side to place the Paddle object on and how to treat + * the Paddle object (either as the left or the right paddle in the game). The Pong class handles how to distribute points to the Paddle objects + * in the game (the Paddle class only has an increment() method that increments its score counter; the Pong class determines which object should + * call that method when a point is earned). + * \see Ball class, Pong class. + */ +class Paddle { +public: + Paddle(Canvas& can, int & speed, int side); + + void bindings(Canvas& can, int side); + + void draw(Canvas& can, int side); + + void increment(); + + void move(); + + int getPoints() const; + + float getY() const; + + void setDir(int direction); + + /** + * \brief Destroys the Paddle object. + */ + ~Paddle() { delete myRect; } + +private: + int myDir; //-1 = up, 1 = down, 0 = stationary + int myPoints; //Score + int mySpeed; //Speed + float myY; //y-coordinate for Paddle + Rectangle * myRect; +}; + +#endif /* PADDLE_H_ */ diff --git a/src/examples/Pong/Pong.cpp b/src/examples/Pong/Pong.cpp new file mode 100644 index 000000000..8ac917cc6 --- /dev/null +++ b/src/examples/Pong/Pong.cpp @@ -0,0 +1,84 @@ +/* + * Pong.cpp + */ + +#include "Pong.h" + +using namespace tsgl; + + /*! + * \brief Explicitly construct the game, Pong. + * \details Explicit constructor for the game, Pong. It sets up the Paddle objects and the Ball object + * in order to play. + * \param can Reference to the Canvas to use when playing Pong. + * \param ballSpeed Reference to the ball speed to use in the game. + * \param paddleSpeed Reference to the paddle speed to use in the game. + */ +Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { + leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object + rightPaddle = new Paddle(can, paddleSpeed, 1); + //Bind the buttons + leftPaddle->bindings(can, -1); // W & S keys + rightPaddle->bindings(can, 1); // Up and Down arrow keys + pongBall = new Ball(can, ballSpeed); + // leftScore = new Text(L"0", can.getWindowWidth() / 2-64, 40, 32, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); + // rightScore = new Text(L"0", can.getWindowWidth()/2+64, 40, 32, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); + // can.add(leftScore); can.add(rightScore); +} + + /*! + * \brief Draw the game of Pong. + * \details Actually draws all of the necessary components in order to play Pong. + * This also includes any necessary button bindings in order to move the Paddle objects. + * \param can Reference to the Canvas to draw on. + * \see Paddle class, Ball class. + */ +void Pong::draw(Canvas& can) { + // While the window has not been closed.... + while (can.isOpen()) { + can.sleep(); + // Move the ball + pongBall->move(); + // Handle ball boundary collisions + if (pongBall->getX() > can.getWindowWidth() / 2 + 8) { + leftPaddle->increment(); // Increment the points + // leftScore->setText( std::to_wstring(leftPaddle->getPoints())); + pongBall->reset(can); // Reset the ball's position + } else if (pongBall->getX() < -can.getWindowWidth() / 2 -8) { + rightPaddle->increment(); + // rightScore->setText( std::to_wstring(rightPaddle->getPoints())); + pongBall->reset(can); + } else if (pongBall->getY() > can.getWindowHeight() / 2 - 8 || pongBall->getY() < -can.getWindowHeight() / 2 + 8) pongBall->invert(0); //Invert the ball's y-coordinate changer + // Handle ball paddle collisions + // handle left + if (pongBall->getX() - 8 < -can.getWindowWidth() / 2 + 32 && + pongBall->getX() - 8 > -can.getWindowWidth() / 2 + 16 && + pongBall->getY() > leftPaddle->getY() - 32 && + pongBall->getY() < leftPaddle->getY() + 32) + { + pongBall->invert(1); + } + // handle right + else if (pongBall->getX() + 8 > can.getWindowWidth() / 2 - 32 && + pongBall->getX() + 8 < can.getWindowWidth() / 2 - 16 && + pongBall->getY() > rightPaddle->getY() - 32 && + pongBall->getY() < rightPaddle->getY() + 32) + { + pongBall->invert(1); + } + // Move the paddles if necessary + leftPaddle->move(); + rightPaddle->move(); + } +} + +/** + * \brief Destroys the Pong game object. + */ +Pong::~Pong() { + delete pongBall; + delete leftPaddle; + delete rightPaddle; + // delete leftScore; + // delete rightScore; +} \ No newline at end of file diff --git a/src/examples/Pong/Pong.h b/src/examples/Pong/Pong.h new file mode 100644 index 000000000..c8af2d11a --- /dev/null +++ b/src/examples/Pong/Pong.h @@ -0,0 +1,44 @@ +/* + * Pong.h + */ + +#ifndef PONG_H_ +#define PONG_H_ + +#include +#include +#include +#include +#include +#include "Ball.h" +#include "Paddle.h" +#include "Util.h" + +using namespace tsgl; + +/*! + * \class Pong + * \brief An old-school classic! + * \details Draw the interactive game of Pong. The two paddles are objects and the ball is also an object. + * \details The constructor constructs the two paddle objects and the ball object. + * \details Use the W and S keys in order to move the left paddle, the Up and Down arrow keys in order to move the right paddle. + * \details Everything else is handled in the draw() method (button bindings, score keeping, drawing the objects and the game itself, + * ball collisions with the paddles and the boundaries). + * \see Paddle class, Ball class. + */ +class Pong { +public: + + Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); + + void draw(Canvas& can); + + ~Pong(); + +private: + Paddle *leftPaddle, *rightPaddle; + Ball *pongBall; + // Text *leftScore, *rightScore; +}; + +#endif /* PONG_H_ */ diff --git a/src/examples/Pong/testPong.cpp b/src/examples/Pong/testPong.cpp new file mode 100644 index 000000000..eb12267da --- /dev/null +++ b/src/examples/Pong/testPong.cpp @@ -0,0 +1,73 @@ +/* + * testPong.cpp + * + * Usage: ./testPong + */ + +#include "Pong.h" + +using namespace tsgl; + +/*! + * \brief Let's play some Pong! + * \details + * - Create an instance of the Pong class which encapsulates a lot of the data needed + * in order to draw the game of Pong. + * - Take in command-line arguments for the ball and paddle speed. + * - When you create an instance of the class: + * - Seed the random number generator. + * - Create the Paddle objects and the Ball object needed in order to play Pong. + * - ( see the Paddle and Ball object classes for more details on how they are created ). + * . + * - When you draw: + - Bind the buttons of the Canvas to the two Paddle objects: + * - Bind the up arrow's on-press and on-release events to set the right + * Paddle object's direction to -1 (up) and 0 (static) respectively. + * - Bind the down arrow's on-press and on-release events to set the right + * Paddle object's direction to 1 (down) and 0 respectively. + * - Bind the W key's on-press and on-release events to set the left + * Paddle object's direction to -1 and 0 respectively. + * - Bind the S key's on-press and on-release events to set the left + * Paddle object's direction to 1 and 0 respectively. + * . + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - Move the Ball object in its current direction at its current speed. + * - If the Ball object passed by one of the goal areas, increment the appropriate player's score, + * reset the Ball object's position, and send it off in a random direction and speed. + * - If the Ball object hits the top or bottom of the screen, bounce it. + * - If the Ball object hits a Paddle object, reverse its x-speed and randomly adjust its y-speed. + * - Move the Paddle objects according to their current directions. + * - Draw the Ball object and Paddle objects. + * - Draw the scores at the top of the screen. + * . + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param ballSpeed Reference to the ball speed in the game. + * \param paddleSpeed Reference to the paddle speed in the game. + */ +void pongFunction(Canvas& can, int ballSpeed, int paddleSpeed) { + Pong p1(can, ballSpeed, paddleSpeed); //Create the Pong object + p1.draw(can); //Draw the game +} + +//Takes command-line arguments for the ball and paddle speed +int main(int argc, char * argv[]) { + //Default speeds for the ball and paddles + const int BALL_DEFAULT_SPEED = 8, PADDLE_DEFAULT_SPEED = 4; + //Window width and height + int w = 1.5*Canvas::getDisplayHeight(); + int h = 0.5*w; + //Determine the ball and paddle speed from command-line arguments + int ballSpeed = (argc > 1) ? atoi(argv[1]) : BALL_DEFAULT_SPEED; + int paddleSpeed = (argc > 2) ? atoi(argv[2]) : PADDLE_DEFAULT_SPEED; + //Check if valid + if(ballSpeed > 10 || paddleSpeed > 10) { + ballSpeed = BALL_DEFAULT_SPEED; + paddleSpeed = PADDLE_DEFAULT_SPEED; + } + Canvas c(-1,-1,w,h,"Tennis for Two"); + c.setBackgroundColor(BLACK); + c.run(pongFunction,ballSpeed, paddleSpeed); +} diff --git a/src/examples/SeaUrchin/Makefile b/src/examples/SeaUrchin/Makefile new file mode 100644 index 000000000..ace4eed7e --- /dev/null +++ b/src/examples/SeaUrchin/Makefile @@ -0,0 +1,63 @@ +# Makefile for SeaUrchin + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSeaUrchin + +# Object files +ODIR = obj +_OBJ = SeaUrchin.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/SeaUrchin/SeaUrchin.cpp b/src/examples/SeaUrchin/SeaUrchin.cpp new file mode 100644 index 000000000..042b62f65 --- /dev/null +++ b/src/examples/SeaUrchin/SeaUrchin.cpp @@ -0,0 +1,33 @@ +/* + * SeaUrchin.cpp + */ + +#include "SeaUrchin.h" + +SeaUrchin::SeaUrchin(Canvas& can, int threadId) { + myX = -can.getWindowWidth() / 2 + 60; + myY = -can.getWindowHeight() / 2 + 60; + myX += (threadId % 8) * 110; + myY += (threadId / 8) * 110; + float delta = 180 / MY_SPOKES; + myColor = Colors::highContrastColor(threadId); + for(int i = 0; i < MY_SPOKES; i++) { + Line * l = new Line(myX, myY, 0, 100, i * delta, 0, 0, myColor); + lines.push_back(l); + can.add(l); + } +} + +void SeaUrchin::move(Canvas& can) { + float delta = 180 / MY_SPOKES; + for(int j = 0; j < MY_SPOKES; ++j) { + lines[j]->setYaw(j * delta + can.getReps() * 180 / PI); + } +} + +SeaUrchin::~SeaUrchin() { + for (unsigned int i = 0; i < lines.size(); i++) { + delete lines[i]; + } +} + diff --git a/src/examples/SeaUrchin/SeaUrchin.h b/src/examples/SeaUrchin/SeaUrchin.h new file mode 100644 index 000000000..e163e22d3 --- /dev/null +++ b/src/examples/SeaUrchin/SeaUrchin.h @@ -0,0 +1,56 @@ +/* + * SeaUrchin.h + */ + +#ifndef SEAURCHIN_H_ +#define SEAURCHIN_H_ + +#include + +using namespace tsgl; + +/*! + * \class SeaUrchin + * \brief Who doesn't love sea urchins? + * \details Draws a sea urchin onto the Canvas. + * \details Used as an example of what it means to put a process on a thread. + * \details The SeaUrchin objects are created in a parallel block, and each thread gets one SeaUrchin. + * \details Then, the thread draws the SeaUrchin onto the Canvas. + * \details Each SeaUrchin object has its own color and plot data based off of the thread's id number. + * \details SeaUrchin objects are drawn similar to the line fan in testLineFan. + * \see testLineFan. + */ +class SeaUrchin { +public: + + /*! + * \brief Explicitly construct a SeaUrchin object. + * \details Explicit constructor for a SeaUrchin object. + * \param can Reference to the Canvas to draw to. + * \param threadId The id of the thread that is currently creating a SeaUrchin object. + * \return The constructed SeaUrchin object. + */ + SeaUrchin(Canvas& can, int threadId); //Default constructor + + /*! + * \brief Draw the SeaUrchin. + * \details Actually draws the SeaUrchin object onto the Canvas. + * \param can Reference to the Canvas object to draw to. + */ + void move(Canvas& can); + + /*! + * \brief Destroy a SeaUrchin. + * \details Destructor for a SeaUrchin object. + * \note This function does absolutely nothing. + */ + virtual ~SeaUrchin(); + +private: + static const int MY_SPOKES = 8; + int myX, myY; + ColorFloat myColor; + std::vector lines; +}; + +#endif /* SEAURCHIN_H_ */ diff --git a/src/examples/SeaUrchin/testSeaUrchin.cpp b/src/examples/SeaUrchin/testSeaUrchin.cpp new file mode 100644 index 000000000..22d4257d7 --- /dev/null +++ b/src/examples/SeaUrchin/testSeaUrchin.cpp @@ -0,0 +1,65 @@ +/* + * testSeaUrchin.cpp + * + * Usage: ./testSeaUrchin + */ + +#include "tsgl.h" +#include + +#include "SeaUrchin.h" + +using namespace tsgl; + +// possible FIXME: sometimes this results in a segmentation fault. no discernable pattern+ + +/*! + * \brief Displays different colored sea urchins and takes a command-line argument. + * \details Displays different colored sea urchins where each sea urchin is drawn by a thread + * (the command-line argument is the number of threads to use). + * It is drawn as follows: + * - The sea urchins are drawn in a similar way as the line fan in testLineFan. + * - A class contains all of the necessary data and methods to draw the sea urchins. + * - A parallel block is created and the process is forked. + * - The current thread's id number is stored. + * - When you create the SeaUrchin object: + * - Set old x and y-coordinate values and increment them based off of the current thread's id number. + * - Set new x and y-coordinate values to 0. + * - Assign a color to the current thread. + * . + * - While the Canvas is open: + * - Sleep the Canvas' internal timer until the next draw cycle. + * - Clear the Canvas. + * - When you draw the SeaUrchin onto the Canvas: + * - Set a delta value to make the SeaUrchins spin. + * - For i to the number of spokes of a SeaUrchin: + * - Calculate the new x and y-coordinate values based off of the delta value and the old x and y-coordinate values. + * - Draw a spoke of the SeaUrchin on the Canvas. + * . + * . + * . + * - If the Canvas has been closed, output a message to the console saying "YOU KILLED MY SEA URCHINS! :'(" . + * . + * \param can Reference to the Canvas being drawn on. + * \param threads Reference to the number of threads to use in the process. + * \see testLineFan, SeaUrchin class. + */ +void seaUrchinFunction(Canvas& can, int threads) { + #pragma omp parallel num_threads(threads) + { + SeaUrchin s(can, omp_get_thread_num()); //A thread gets a Sea Urchin + while(can.isOpen()) { //Draw loop + can.sleep(); + s.move(can); //And draws it + } + } +} + +int main(int argc, char * argv[]) { + int nthreads = (argc > 1) ? atoi(argv[1]) : 16; //Number of threads + clamp(nthreads,1,16); //Max number of threads is 16 + Canvas c(-1, -1, 885, 230, "Sea Urchins!", FRAME * 2); + c.setBackgroundColor(BLACK); + c.run(seaUrchinFunction, nthreads); +} + diff --git a/src/examples/ShakerSort/Makefile b/src/examples/ShakerSort/Makefile new file mode 100644 index 000000000..74dfe4299 --- /dev/null +++ b/src/examples/ShakerSort/Makefile @@ -0,0 +1,63 @@ +# Makefile for ShakerSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testShakerSort + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ShakerSort/testShakerSort.cpp b/src/examples/ShakerSort/testShakerSort.cpp new file mode 100644 index 000000000..bef6a0f43 --- /dev/null +++ b/src/examples/ShakerSort/testShakerSort.cpp @@ -0,0 +1,116 @@ +/* + * testShakerSort.cpp + * + * Usage: ./testShakerSort + */ + +#include + +using namespace tsgl; + +/*! + * \brief Provides a visualization for a basic (and slow) shaker sort. + * \details + * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. + * - An integer array of size \b SIZE is allocated. + * - A flag \b goingUp is set. + * - Our integer array is filled with random integers under the Canvas' height. + * - The background color is set to gray for visibility. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - While the Canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - If the minimum sorted element is greater than or equals the maximum, we're done. + * - At a rate of \b IPF times a second: + * - If we're going up and the element above us is less than us, swap. + * - If we're going down and the element below us is less than us, swap. + * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. + * . + * - Pause the animation. + * - Clear the Canvas. + * - From 0 to \b SIZE: + * - Get the height of each element in the integer array. + * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. + * . + * - Resume the animation. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void shakerSortFunction(Canvas& can) { + const int SIZE = 550, // Size of the data pool (set to 550 by default) + IPF = 50; // Iterations per frame + Rectangle* rectangles[SIZE]; // Array to store the data + float numbers[SIZE]; // Array to store the data + int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; + float temp; + bool goingUp = true; + int canWidth = (can.getWindowWidth() > can.getDisplayWidth()) ? can.getDisplayWidth() : can.getWindowWidth(); + float start = canWidth * -.45; + float rectangleWidth = canWidth * .9 / SIZE; + for (int i = 0; i < SIZE; i++) { + rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, saferand(1,can.getWindowHeight()*.9), 0, 0, 0, RED); + numbers[i] = rectangles[i]->getHeight(); + can.add(rectangles[i]); + } + can.setBackgroundColor(GRAY); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + if (min >= max) { // We are done sorting. + // If we don't call wait(), we segfault. If we call return instead, rectangles[] doesn't get deallocated. + // return would be fine if we hadn't allocated memory in this method to which Canvas needed access. + can.wait(); + } + for (int i = 0; i < IPF; i++) { + if (goingUp) { + if (numbers[pos] > numbers[pos + 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos + 1];; + numbers[pos + 1] = temp; + lastSwap = pos; + } + if (pos >= max) { + pos = max; + max = (lastSwap < max) ? lastSwap : max - 1; + goingUp = !goingUp; + } else + pos++; + } else { + if (numbers[pos] < numbers[pos - 1]) { + temp = numbers[pos]; + numbers[pos] = numbers[pos - 1]; + numbers[pos - 1] = temp; + lastSwap = pos; + } + if (pos <= min) { + pos = min; + min = (lastSwap > min) ? lastSwap : min + 1; + goingUp = !goingUp; + } else + pos--; + } + } + ColorFloat color; + can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily + for (int i = 0; i < SIZE; i++) { + color = (i == pos) ? YELLOW : RED; + rectangles[i]->setColor(color); + rectangles[i]->setHeight(numbers[i]); + } + can.resumeDrawing(); //Tell the Canvas it can resume drawing + } + + for (int i = 0; i < SIZE; i++) { + delete rectangles[i]; + } +} + +//Takes in command line arguments for the window width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid + w = 1300; h = 900; // If not, set the width and height to a default value + } + Canvas c(-1, -1, w, h, "Shaker Sort"); + c.run(shakerSortFunction); +} diff --git a/src/examples/SolarSystem/Makefile b/src/examples/SolarSystem/Makefile new file mode 100644 index 000000000..a98ede8c6 --- /dev/null +++ b/src/examples/SolarSystem/Makefile @@ -0,0 +1,63 @@ +# Makefile for SolarSystem + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSolarSystem + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/SolarSystem/testSolarSystem.cpp b/src/examples/SolarSystem/testSolarSystem.cpp new file mode 100644 index 000000000..c35dc459f --- /dev/null +++ b/src/examples/SolarSystem/testSolarSystem.cpp @@ -0,0 +1,76 @@ +/* + * testSolarSystem.cpp + * + * Usage: ./testSolarSystem + */ + +#include +#include + +using namespace tsgl; + +void ssFunction(Canvas& can) { + Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); + + mercury->setRotationPoint(0,0,0); + venus->setRotationPoint(0,0,0); + earth->setRotationPoint(0,0,0); + mars->setRotationPoint(0,0,0); + jupiter->setRotationPoint(0,0,0); + saturn->setRotationPoint(0,0,0); + saturnRings->setRotationPoint(0,0,0); + uranus->setRotationPoint(0,0,0); + neptune->setRotationPoint(0,0,0); + + can.add(sun); + can.add(mercury); + can.add(venus); + can.add(earth); + can.add(mars); + can.add(jupiter); + can.add(saturn); + can.add(saturnRings); + can.add(uranus); + can.add(neptune); + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + sun->setPitch(rotation); + mercury->setPitch(rotation * 4); + venus->setPitch(rotation * 3 / 2); + earth->setPitch(rotation); + mars->setPitch(rotation/2); + jupiter->setPitch(rotation/12); + saturn->setPitch(rotation/30); + saturnRings->setPitch(rotation/30); + uranus->setPitch(rotation/90); + neptune->setPitch(rotation/180); + rotation += 1; + } + + delete sun; + delete mercury; + delete venus; + delete earth; + delete mars; + delete jupiter; + delete saturn; + delete saturnRings; + delete uranus; + delete neptune; +} + +int main(int argc, char* argv[]) { + Canvas c(0, -1, 1800, 620, "Solar System"); + c.setBackgroundColor(BLACK); + c.run(ssFunction); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/CubeArray.cpp b/src/examples/ThreadedArrayAddition/CubeArray.cpp new file mode 100644 index 000000000..7fd143e5c --- /dev/null +++ b/src/examples/ThreadedArrayAddition/CubeArray.cpp @@ -0,0 +1,313 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + +// CubeArray::CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]){ +// myX = x; +// myY = y; +// myZ = z; +// mySize = size; +// myCubeSideLength = sideLength; +// myYaw = yaw; +// myPitch = pitch; +// myRoll = roll; + +// for(unsigned i = 0; i < size; ++i){ +// myCubes.push_back(new Cube((-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c[0])); +// myCubes[i]->setRotationPoint(0,0,0); +// myCubes[i]->setColor(c[i%(sizeof(c[0])/sizeof(c))]); +// } +// } + +// bool CubeArray::operator==(CubeArray& a2){ +// printf("Equality entered.\n"); +// if(mySize != a2.getSize()){ +// printf("Sizes are different.\n"); +// return false; +// } +// for(unsigned i = 0; i < mySize; ++i){ +// if(myCubes[i] != a2.get(i)){ +// printf("Index %d is different.\n", i); +// return false; +// } +// } +// return true; +// } + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hid it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setFontSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the font size of the CubeArray's Text/numbers to a new size. + * \param fontsize The new font size. + */ +void CubeArray::setFontSize(unsigned int fontsize){ + for(Text * t : myText){ + t->setFontSize(fontsize); + } +} + + +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +void CubeArray::visualSplit(unsigned index){ + for(unsigned i = 0; i < index; ++i){ + myCubes[i]->changeXBy(-myCubeSideLength/2.0); + myText[i]->changeXBy(-myCubeSideLength/2.0); + } + for(unsigned i = index; i < mySize; ++i){ + myCubes[i]->changeXBy(myCubeSideLength/2.0); + myText[i]->changeXBy(myCubeSideLength/2.0); + } +} + +// void CubeArray::visualRegroup(unsigned index){ + +// } + +void CubeArray::visualRegroupAll(float x){ + for(unsigned i = 0; i < mySize; i++){ + myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + } +} + + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for Table. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/CubeArray.h b/src/examples/ThreadedArrayAddition/CubeArray.h new file mode 100644 index 000000000..2fc1c2e16 --- /dev/null +++ b/src/examples/ThreadedArrayAddition/CubeArray.h @@ -0,0 +1,81 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + // CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setFontSize(unsigned int fontsize); + + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + void visualSplit(unsigned index); + + void visualRegroupAll(float x); + + // Operations + CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/Makefile b/src/examples/ThreadedArrayAddition/Makefile new file mode 100644 index 000000000..5aeded5f7 --- /dev/null +++ b/src/examples/ThreadedArrayAddition/Makefile @@ -0,0 +1,63 @@ +# Makefile for ThreadedArrayAddition + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayAddition + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp b/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp new file mode 100644 index 000000000..4068e1b6a --- /dev/null +++ b/src/examples/ThreadedArrayAddition/testThreadedArrayAddition.cpp @@ -0,0 +1,229 @@ +/* + * testThreadedArrayAddition.cpp + * + * Usage: ./testThreadedArrayAddition [threadingType] [numberOfThreads] [sizeOfArrays] + threadingType = 0 (slices) or 1 (chunks), defaults to 0 + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArrays <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 49 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_A_Y TITLE_Y - 125.0 // y-coordinate for Array 1 blocks +#define ARRAY_B_Y TITLE_Y - (2 * 125.0) // y-coordinate for Array 2 blocks +#define ARRAY_C_Y TITLE_Y - (3 * 125.0) // y-coordinate for Array 3 blocks +#define CUBE_Z 0.0 // z-coordinate for all Cube objects +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 25 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + Cube* myArrayABlock; + Cube* myArrayBBlock; + Cube* myArrayCBlock; +public: + // Constructor + ThreadData(unsigned tid, ColorFloat color, Cube* arrayABlock, Cube* arrayBBlock, Cube* arrayCBlock){ + threadID = tid; + myColor = color; + myArrayABlock = arrayABlock; + myArrayBBlock = arrayBBlock; + myArrayCBlock = arrayCBlock; + } + // Runs the animation for threaded array addition process + void runAddition(Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // get value from arrayA + myArrayABlock->setColor(myColor); + can.sleepFor(sleepTime); + + // get value from arrayB + myArrayBBlock->setColor(myColor); + can.sleepFor(sleepTime); + + // enter sum into arrayC + myArrayCBlock->setColor(myColor); + } +}; + + +void arrayFunction(Canvas& can, int threadingType, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to sum + int numArrayA[arraySize]; + int numArrayB[arraySize]; + int numArrayC[arraySize]; + + // Fill numerical arrays A and B with random numbers between 0 and 49 + for(unsigned i = 0; i < arraySize; i++){ + numArrayA[i] = (rand() % (RAND_UPPER+1)); + numArrayB[i] = (rand() % (RAND_UPPER+1)); + } + + // Create 3D arrays + CubeArray arrayA(0, ARRAY_A_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayA, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + CubeArray arrayB(0, ARRAY_B_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayB, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + CubeArray arrayC(0, ARRAY_C_Y, CUBE_Z, SIDE_LENGTH, arraySize, numArrayC, 0, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * arrayALabel = new Text(arrayA.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_A_Y, TEXT_Z, + L"a", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * arrayBLabel = new Text(arrayB.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_B_Y, TEXT_Z, + L"b", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * arrayCLabel = new Text(arrayC.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_C_Y, TEXT_Z, + L"c", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Addition: c[i] = a[i] + b[i]", FONT, FONT_SIZE + 20, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {arrayALabel, arrayBLabel, arrayCLabel, titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + arrayB.draw(can); + arrayC.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.5; // initial number of seconds to sleep + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0 and threadingType == 0){ + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + numArrayC[i] = numArrayA[i] + numArrayB[i]; + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i), arrayB.getCube(i), + arrayC.getCube(i)); + td->runAddition(can, sleepTime); + arrayC[i] = numArrayC[i]; + arrayC.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + complete = 1; + } + if(complete == 0 and threadingType == 1){ + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static, 1) + for(unsigned i = 0; i < arraySize; i++){ + + numArrayC[i] = numArrayA[i] + numArrayB[i]; + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i), arrayB.getCube(i), + arrayC.getCube(i)); + td->runAddition(can, sleepTime); + arrayC[i] = numArrayC[i]; + arrayC.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + complete = 1; + } + } + + // Output + printf("\nAdded two arrays of size %d using %d threads\n", arraySize, numThreads); + printf("\nArray A: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayA[i]); + } + printf("\nArray B: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayB[i]); + } + printf("\nArray C: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArrayC[i]); + } + printf("\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + +} + +int main(int argc, char* argv[]){ + int threadingType = (argc > 1) ? atoi(argv[1]) : 0; + int numberOfThreads = (argc >2) ? atoi(argv[2]) : 4; + int sizeOfArrays = (argc > 3) ? atoi(argv[3]) : 10; + + // Checks validity of threadingType, numThreads, and sizeOfArrays; if one is invalid, set all to default + if((threadingType < 0 or threadingType > 1) or (sizeOfArrays <= 0 or sizeOfArrays > 24) or + (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayAddition [threadingType] [numberOfThreads] [sizeOfArrays]\n \ + threadingType = 0 (slices) or 1 (chunks)\n \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArrays <= 24\ + \nUsing default parameters...\n"); + threadingType = 0; + numberOfThreads = 4; + sizeOfArrays = 10; + } + + Canvas c(0, -1, 1820, 620, "Threaded Array Addition"); + c.setBackgroundColor(BLACK); + c.run(arrayFunction, threadingType, numberOfThreads, sizeOfArrays); +} diff --git a/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp b/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp new file mode 100644 index 000000000..7fd143e5c --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/CubeArray.cpp @@ -0,0 +1,313 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + +// CubeArray::CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]){ +// myX = x; +// myY = y; +// myZ = z; +// mySize = size; +// myCubeSideLength = sideLength; +// myYaw = yaw; +// myPitch = pitch; +// myRoll = roll; + +// for(unsigned i = 0; i < size; ++i){ +// myCubes.push_back(new Cube((-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c[0])); +// myCubes[i]->setRotationPoint(0,0,0); +// myCubes[i]->setColor(c[i%(sizeof(c[0])/sizeof(c))]); +// } +// } + +// bool CubeArray::operator==(CubeArray& a2){ +// printf("Equality entered.\n"); +// if(mySize != a2.getSize()){ +// printf("Sizes are different.\n"); +// return false; +// } +// for(unsigned i = 0; i < mySize; ++i){ +// if(myCubes[i] != a2.get(i)){ +// printf("Index %d is different.\n", i); +// return false; +// } +// } +// return true; +// } + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hid it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setFontSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the font size of the CubeArray's Text/numbers to a new size. + * \param fontsize The new font size. + */ +void CubeArray::setFontSize(unsigned int fontsize){ + for(Text * t : myText){ + t->setFontSize(fontsize); + } +} + + +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +void CubeArray::visualSplit(unsigned index){ + for(unsigned i = 0; i < index; ++i){ + myCubes[i]->changeXBy(-myCubeSideLength/2.0); + myText[i]->changeXBy(-myCubeSideLength/2.0); + } + for(unsigned i = index; i < mySize; ++i){ + myCubes[i]->changeXBy(myCubeSideLength/2.0); + myText[i]->changeXBy(myCubeSideLength/2.0); + } +} + +// void CubeArray::visualRegroup(unsigned index){ + +// } + +void CubeArray::visualRegroupAll(float x){ + for(unsigned i = 0; i < mySize; i++){ + myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + } +} + + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for Table. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/CubeArray.h b/src/examples/ThreadedArrayBubbleSort/CubeArray.h new file mode 100644 index 000000000..2fc1c2e16 --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/CubeArray.h @@ -0,0 +1,81 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + // CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setFontSize(unsigned int fontsize); + + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + void visualSplit(unsigned index); + + void visualRegroupAll(float x); + + // Operations + CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/Makefile b/src/examples/ThreadedArrayBubbleSort/Makefile new file mode 100644 index 000000000..8576b9828 --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/Makefile @@ -0,0 +1,63 @@ +# Makefile for ThreadedArrayBubbleSort + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayBubbleSort + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp b/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp new file mode 100644 index 000000000..984f06faf --- /dev/null +++ b/src/examples/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort.cpp @@ -0,0 +1,209 @@ +/* + * testArrayBubbleSort.cpp + * + * Usage: ./testThreadedArrayBubbleSort [numberOfThreads] [sizeOfArrays] + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArrays <= 24, defaults to 10 + */ + +#include +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 99 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays +#define NUM_COLOR WHITE // color value for all numbers +#define FINISHED_COLOR ColorFloat(0, 0.6, 0, 1) // color value for sorted numbers (green) +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + unsigned myIndex; +public: + // Constructor + ThreadData(unsigned tid, ColorFloat color, unsigned index){ + threadID = tid; + myColor = color; + myIndex = index; + } + + // Swaps the positions of two values in the array + void swap(int& a, int& b){ + int temp = a; + a = b; + b = temp; + } + + // Runs the sorting and animation for threaded array bubble sort process + void runSort(CubeArray& arr, Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // Get value from first block + arr.getCube(myIndex)->setColor(myColor); + // Get value from second block + arr.getCube(myIndex+1)->setColor(myColor); + can.sleepFor(sleepTime); + + // Compare values + if(arr[myIndex] > arr[myIndex+1]){ + swap(arr[myIndex], arr[myIndex+1]); + arr.update(myIndex); arr.update(myIndex+1); + } + can.sleepFor(sleepTime); + + // Leave blocks + arr.getCube(myIndex)->setColor(ARRAY_COLOR); + arr.getCube(myIndex+1)->setColor(ARRAY_COLOR); + } +}; + +void sortVisualizationFunction(Canvas& can, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int originalArray[arraySize]; + // int sortedArray[] = {40, 35, 80, 62, 60, 74, 36, 10, 19, 5}; + + // Fill numerical array with random numbers between 0 and 99 + for(unsigned i = 0; i < arraySize; i++){ + originalArray[i] = rand() % (RAND_UPPER + 1); + // originalArray[i] = i + 90; + } + + printf("Before bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", originalArray[i]); + } + printf("\n"); + + // Create 3D array + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, originalArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Bubble Sort in Parallel", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + // Text * speedLabel = new Text(0.0, ARRAY_Y - 100.0, TEXT_Z, + // "Speed: x" + std::to_string(sleepTime/250000), FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * sortedLabel = new Text(0.0, ARRAY_Y - 200.0, TEXT_Z, + L"Sorted!", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {titleLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.125; // initial number of seconds to sleep 0.5 + + // Key bindings to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 8){ + sleepTime *= 2; + } + }); + + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + if(complete == 0){ + // Parallel bubble sort + for(int i = 0; i < arrayA.getSize(); i++){ + int first = i%2; + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned j = first; j < arraySize - 1; j+=2){ + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], j); + td->runSort(arrayA, can, sleepTime); + delete td; + } + } + //******************************************************************** + } + arrayA.setColor(FINISHED_COLOR); + can.add(sortedLabel); + complete = 1; + } + } + + // Output + printf("\nAfter bubble sort: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\nSorted array of size %d using %d threads.\n", arraySize, numThreads); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + delete sortedLabel; + +} + +int main(int argc, char* argv[]){ + int numberOfThreads = (argc >1) ? atoi(argv[1]) : 4; + int sizeOfArrays = (argc > 2) ? atoi(argv[2]) : 10; + + // Checks validity of numThreads and sizeOfArrays; if one is invalid, set all to default + if((sizeOfArrays <= 0 or sizeOfArrays > 24) or (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayBubbleSort [numberOfThreads] [sizeOfArrays]\n \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArrays <= 24\ + \nUsing default parameters...\n"); + numberOfThreads = 4; + sizeOfArrays = 10; + } + + Canvas c(0, -1, 1820, 620, "Threaded Array Bubble Sort"); + c.setBackgroundColor(BLACK); + c.run(sortVisualizationFunction, numberOfThreads, sizeOfArrays); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/CubeArray.cpp b/src/examples/ThreadedArrayOperations/CubeArray.cpp new file mode 100644 index 000000000..7fd143e5c --- /dev/null +++ b/src/examples/ThreadedArrayOperations/CubeArray.cpp @@ -0,0 +1,313 @@ +#include "CubeArray.h" + +using namespace tsgl; + +// typedef Item int; + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(){ + myX = 0.0; + myY = 0.0; + myZ = 0.0; + mySize = 10; + myCubeSideLength = 50.0; + myYaw = 0.0; + myPitch = 0.0; + myRoll = 0.0; + + // Fill array of Cubes + for(unsigned i = 0; i < mySize; ++i){ + myCubes.push_back(new Cube((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ, + myCubeSideLength, myYaw, myPitch, myRoll, RED)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + for(unsigned i = 0; i < mySize; ++i){ + myData.push_back(0); + myText.push_back(new Text((myX-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength), myY, myZ+myCubeSideLength/2.0, + std::to_wstring(myData[i]), "./assets/freefont/FreeSansBold.ttf", myCubeSideLength/2.25, + myYaw, myPitch, myRoll, WHITE)); + myText[i]->setRotationPoint(0,0,0); + } +} + +/*! + * \brief Explicitly constructs a new CubeArray. + * \details This is the constructor for the CubeArray class. + * \param x The x coordinate of the center of the CubeArray. + * \param y The y coordinate of the center of the CubeArray. + * \param z The z coordinate of the center of the CubeArray. + * \param sideLength The side length of the CubeArray's Cubes. + * \param size The number of Cubes in the CubeArray. + * \param dataArray The array of values that CubeArray copies. + * \param dataArraySize The size of the array passed to CubeArray. + * \param yaw The yaw of the CubeArray. + * \param pitch The pitch of the CubeArray. + * \param roll The roll of the CubeArray. + * \param c1 A ColorFloat for the color of the CubeArray's Cubes. + * \param c2 A ColorFloat for the color of the CubeArray's Text/numbers. + * \return A new CubeArray with the specified size, values, and colors. + */ +CubeArray::CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2){ + myX = x; + myY = y; + myZ = z; + mySize = size; + myCubeSideLength = sideLength; + myYaw = yaw; + myPitch = pitch; + myRoll = roll; + + // Fill array of Cubes + for(unsigned i = 0; i < size; ++i){ + myCubes.push_back(new Cube((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c1)); + myCubes[i]->setRotationPoint(0,0,0); + } + // Copy dataArray into myData + // if size of dataArray is less than CubeArray size, fill the remaining spaces with blanks + // if size of dataArray is greater than CubeArray size, only copy up to the last index of myData + if(dataArraySize < size){ + for(unsigned i = 0; i < dataArraySize; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + for(unsigned i = dataArraySize; i < size; ++i){ + myData.push_back(0); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, L"", + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + else{ + for(unsigned i = 0; i < size; ++i){ + myData.push_back(dataArray[i]); + myText.push_back(new Text((x-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z+sideLength/2.0, std::to_wstring(myData[i]), + "./assets/freefont/FreeSansBold.ttf", sideLength/2.25, yaw, pitch, roll, c2)); + myText[i]->setRotationPoint(0,0,0); + } + } + //TODO: Simplify above code +} + +// CubeArray::CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]){ +// myX = x; +// myY = y; +// myZ = z; +// mySize = size; +// myCubeSideLength = sideLength; +// myYaw = yaw; +// myPitch = pitch; +// myRoll = roll; + +// for(unsigned i = 0; i < size; ++i){ +// myCubes.push_back(new Cube((-(int)(size-1)*(sideLength/2.0)) + (i * sideLength), y, z, sideLength, yaw, pitch, roll, c[0])); +// myCubes[i]->setRotationPoint(0,0,0); +// myCubes[i]->setColor(c[i%(sizeof(c[0])/sizeof(c))]); +// } +// } + +// bool CubeArray::operator==(CubeArray& a2){ +// printf("Equality entered.\n"); +// if(mySize != a2.getSize()){ +// printf("Sizes are different.\n"); +// return false; +// } +// for(unsigned i = 0; i < mySize; ++i){ +// if(myCubes[i] != a2.get(i)){ +// printf("Index %d is different.\n", i); +// return false; +// } +// } +// return true; +// } + +/** + * \brief Adds the CubeArray to the canvas. + * \param can The Canvas on which the CubeArray is to be drawn. + */ +void CubeArray::draw(Canvas& can){ + for(unsigned i = 0; i < mySize; ++i){ + can.add(myCubes[i]); + can.add(myText[i]); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the vector contained by the CubeArray. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(){ + for(unsigned i = 0; i < mySize; ++i){ + myText[i]->setText(std::to_wstring(myData[i])); + } +} + +/** + * \brief Updates the graphics/visual portion of the CubeArray to match + * the value at a specified index contained by the CubeArray. + * \param index The index of the graphic Text to change. + * \note Should be called after every change in the array's data to update graphic Text + */ +void CubeArray::update(unsigned index){ + myText[index]->setText(std::to_wstring(myData[index])); +} + +/** + * \brief Sets the side length of the CubeArray's Cubes to a new side length, + * resizes the text to retain the Cube/Text size proportion, and + * moves the Text so that the resized Cube does not overlap and hid it + * \param length The new side length. + */ +void CubeArray::setCubeSideLength(GLfloat length){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setSideLength(length); + myText[i]->setFontSize(length/2.5); + myText[i]->setCenterZ(myCubes[i]->getSideLength()/2.0); + } +} + +/** + * \brief Sets the CubeArray's Cubes to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setColor(ColorFloat color){ + for (Cube * c : myCubes){ + c->setColor(color); + } +} + +/** + * \brief Sets the CubeArray's Cubes to new colors. + * \param c The new array of ColorFloats. + * \param size The size of the array of ColorFloats + */ +void CubeArray::setColor(ColorFloat c[], unsigned size){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->setColor(c[i%size]); + } +} + +/** + * \brief Sets the CubeArray's Text/numbers to a new color. + * \param color The new ColorFloat. + */ +void CubeArray::setTextColor(ColorFloat color){ + for(Text * t : myText){ + t->setColor(color); + } +} + +/** + * \brief Sets the font of the CubeArray's Text/numbers to a new font. + * \param filename The path and file name of the font. + */ +void CubeArray::setFont(std::string filename){ + for(Text * t : myText){ + t->setFont(filename); + } +} + +/** + * \brief Sets the font size of the CubeArray's Text/numbers to a new size. + * \param fontsize The new font size. + */ +void CubeArray::setFontSize(unsigned int fontsize){ + for(Text * t : myText){ + t->setFontSize(fontsize); + } +} + + +void CubeArray::changeYawBy(GLfloat yaw){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeYawBy(yaw); + myText[i]->changeYawBy(yaw); + } +} + +void CubeArray::changePitchBy(GLfloat pitch){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changePitchBy(pitch); + myText[i]->changePitchBy(pitch); + } +} + +void CubeArray::changeRollBy(GLfloat roll){ + for(unsigned i = 0; i < mySize; ++i){ + myCubes[i]->changeRollBy(roll); + myText[i]->changeRollBy(roll); + } +} + +void CubeArray::visualSplit(unsigned index){ + for(unsigned i = 0; i < index; ++i){ + myCubes[i]->changeXBy(-myCubeSideLength/2.0); + myText[i]->changeXBy(-myCubeSideLength/2.0); + } + for(unsigned i = index; i < mySize; ++i){ + myCubes[i]->changeXBy(myCubeSideLength/2.0); + myText[i]->changeXBy(myCubeSideLength/2.0); + } +} + +// void CubeArray::visualRegroup(unsigned index){ + +// } + +void CubeArray::visualRegroupAll(float x){ + for(unsigned i = 0; i < mySize; i++){ + myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); + } +} + + +/** + * \brief If the sizes are equal, adds the values of two CubeArrays and returns + * the sums in a new CubeArray. + * If the sizes are not equal, returns a default-constructed CubeArray. + * \param c2 The CubeArray to be added with the current one. + */ +CubeArray CubeArray::operator+(CubeArray& c2){ + if(mySize == c2.getSize()){ + int summedArray[mySize]; + for(unsigned i = 0; i < mySize; i++){ + summedArray[i] = myData[i] + c2[i]; + printf("%.2d\n", summedArray[i]); + } + return CubeArray(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); + } + return CubeArray(); +} + +/*! + * \brief Destructor for Table. + */ +CubeArray::~CubeArray(){ + for(unsigned i = 0; i < mySize; ++i){ + delete myCubes[i]; + delete myText[i]; + } + myCubes.clear(); + myText.clear(); +} \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/CubeArray.h b/src/examples/ThreadedArrayOperations/CubeArray.h new file mode 100644 index 000000000..2fc1c2e16 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/CubeArray.h @@ -0,0 +1,81 @@ +#ifndef CUBE_ARRAY_H_ +#define CUBE_ARRAY_H_ + +#include +#include "Cube.h" +#include +#include + +using namespace tsgl; + +typedef int Item; + +class CubeArray { +private: + unsigned mySize; +protected: + float myX, myY, myZ; + GLfloat myCubeSideLength; + std::vector myCubes; + std::vector myData; + std::vector myText; + float myYaw, myPitch, myRoll; +public: + CubeArray(); + + CubeArray(float x, float y, float z, GLfloat sideLength, unsigned size, Item dataArray[], unsigned dataArraySize, + float yaw, float pitch, float roll, ColorFloat c1, ColorFloat c2); + + // CubeArray(float x, float y, float z, unsigned size, GLfloat sideLength, Item* dataArray, float yaw, float pitch, float roll, ColorFloat c[]); + + void draw(Canvas& can); + + void update(); + + void update(unsigned index); + + // Accessors + unsigned getSize() { return mySize; } + + GLfloat getCubeSideLength() { return myCubeSideLength; } + + Cube * getCube(unsigned i) { return myCubes[i]; } + + const int& operator[](unsigned i) const { return myData[i]; } + + + // Mutators + int& operator[](unsigned i) { return myData[i]; } + + void setCubeSideLength(GLfloat length); + + void setColor(ColorFloat c); + + void setColor(ColorFloat c[], unsigned size); + + void setTextColor(ColorFloat c); + + void setFont(std::string filename); + + void setFontSize(unsigned int fontsize); + + + void changeYawBy(GLfloat yaw); + + void changePitchBy(GLfloat pitch); + + void changeRollBy(GLfloat roll); + + void visualSplit(unsigned index); + + void visualRegroupAll(float x); + + // Operations + CubeArray operator+ (CubeArray& c2); + + // bool operator==(CubeArray& a2); + + virtual ~CubeArray(); +}; + +#endif /* CUBE_ARRAY_H_ */ \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/Makefile b/src/examples/ThreadedArrayOperations/Makefile new file mode 100644 index 000000000..9b69bacb3 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/Makefile @@ -0,0 +1,63 @@ +# Makefile for ThreadedArrayOperations + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedArrayOperations + +# Object files +ODIR = obj +_OBJ = CubeArray.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp b/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp new file mode 100644 index 000000000..642904958 --- /dev/null +++ b/src/examples/ThreadedArrayOperations/testThreadedArrayOperations.cpp @@ -0,0 +1,241 @@ +/* + * testThreadedArrayOperations.cpp + * + * Usage: ./testThreadedArrayOperations [operation] [numberOfThreads] [sizeOfArray] + operation = 0 (addition), 1 (multiplication), or 2 (exponentiation), defaults to 0 + 1 <= numberOfThreads <= 12, defaults to 4 + 1 <= sizeOfArray <= 24, defaults to 10 + */ + +#include +#include "CubeArray.h" + +// Size constants +#define SIDE_LENGTH 50 // side length of all array blocks +#define RAND_UPPER 9 // maximum value of the random numbers in the arrays + +// Space/distance constants +#define TITLE_Y 225.0 // y-coordinate of title label +#define ARRAY_Y 0.0 // y-coordinate for Array +#define ARRAY_Z 0.0 // z-coordinate for Array +#define TEXT_Z SIDE_LENGTH/2.0 // z-coordinate for all Text objects +#define YAW 0.0 // yaw value for all Drawable objecs +#define PITCH 0.0 // pitch value for all Drawable objects +#define ROLL 0.0 // roll value for all Drawable objects + +// Other constants +#define ARRAY_COLOR ColorFloat(0.5, 0.5, 0.5, 1) // color value for all arrays (gray) +#define NUM_COLOR WHITE // color value for all numbers +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 35 // font size for all text + +using namespace tsgl; + +// Stores data for threads running in parallel +class ThreadData{ +private: + unsigned threadID; + ColorFloat myColor; + Cube* myArrayBlock; +public: + ThreadData(unsigned tid, ColorFloat color, Cube* arrayBlock){ + threadID = tid; + myColor = color; + myArrayBlock = arrayBlock; + } + // Runs the animation for threaded array addition processe + void runAnimation(Canvas& can, float sleepTime){ + can.sleepFor(sleepTime); + + // get value from array + myArrayBlock->setColor(myColor); + can.sleepFor(sleepTime); + } +}; + +void operationVisualization(Canvas& can, int operation, int numThreads, int arraySize) { + // Generate random seed + srand( time(0) ); + + // Create arrays to perform operation on + int numArray[arraySize]; + + // Fill numerical array with random numbers between 0 and 9 + for(unsigned i = 0; i < arraySize; i++){ + numArray[i] = (rand() % (RAND_UPPER+1)); + } + + // Create 3D arrays + CubeArray arrayA(0, ARRAY_Y, ARRAY_Z, SIDE_LENGTH, arraySize, numArray, arraySize, YAW, PITCH, ROLL, ARRAY_COLOR, NUM_COLOR); + + // Create text labels + Text * arrayALabel = new Text(arrayA.getCube(0)->getCenterX() - SIDE_LENGTH, ARRAY_Y, TEXT_Z, + L"a", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + Text * titleLabel = new Text(0.0, TITLE_Y, TEXT_Z, + L"Array Scalar Operations: a +/*/^ n", FONT, FONT_SIZE + 10, YAW, PITCH, ROLL, YELLOW); + Text * operationNumLabel = new Text(0.0, TITLE_Y-50, TEXT_Z, + L"n = 0", FONT, FONT_SIZE, YAW, PITCH, ROLL, YELLOW); + + // Create arrays to store labels + Text * labelArray[] = {arrayALabel, titleLabel, operationNumLabel}; + unsigned numLabels = sizeof(labelArray)/sizeof(labelArray[0]); + + + // Create arrays to store colors + ColorFloat colorArray[] = {ColorFloat(0.6, 0, 0, 1), // red + ColorFloat(0.6, 0.298, 0, 1), // brown + ColorFloat(0.6, 0.6, 0, 1), // yellow + ColorFloat(0.298, 0.6, 0, 1), // yellow-green + ColorFloat(0, 0.6, 0, 1), // green + ColorFloat(0, 0.6, 0.298, 1), // blue-green + ColorFloat(0, 0.6, 0.6, 1), // turquoise + ColorFloat(0, 0.298, 0.6, 1), // blue + ColorFloat(0, 0, 0.6, 1), // dark blue + ColorFloat(0.298, 0, 0.6, 1), // purple + ColorFloat(0.6, 0, 0.6, 1), // magenta + ColorFloat(0.6, 0, 0.298, 1)}; // dark magenta + unsigned numColors = sizeof(colorArray)/sizeof(colorArray[0]); + + // Draw arrays on canvas + arrayA.draw(can); + // Draw labels on canvas + for(unsigned i = 0; i < numLabels; i++){ + can.add(labelArray[i]); + } + + float sleepTime = 0.5; // initial number of seconds to sleep + unsigned complete = 0; // ensures animation only runs once + while (can.isOpen()) { + can.sleep(); + // ADDITION + if(complete == 0 and operation == 0){ + // Generate random number to add (0 - 990) + int operationNum = rand() % 991; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a + n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = arrayA[i] + operationNum; + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nAdded %d to array of size %d using %d threads\n", operationNum, arraySize, numThreads); + complete = 1; + } + + // MULTIPLICATION + if(complete == 0 and operation == 1){ + // Generate random number to mulitply by (1 - 111) + int operationNum = (rand() % 111) + 1; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a * n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = arrayA[i] * operationNum; + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nMultiplied array of size %d by %d using %d threads\n", arraySize, operationNum, numThreads); + complete = 1; + } + + // EXPONENTIATION + if(complete == 0 and operation == 2){ + // Generate random number to exponentiate by (2 - 3) + unsigned int operationNum = (rand() % 2) + 2; + // Set labels to match operation + titleLabel->setText(L"Array Scalar Operations: a^n"); + operationNumLabel->setText(L"n = " + std::to_wstring(operationNum)); + + //**************************** Parallel ****************************** + #pragma omp parallel num_threads(numThreads) + { + unsigned tid = omp_get_thread_num(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < arraySize; i++){ + + ThreadData * td = new ThreadData(tid, colorArray[tid%numColors], arrayA.getCube(i)); + td->runAnimation(can, sleepTime); + arrayA[i] = pow(arrayA[i], operationNum); + arrayA.update(i); + can.sleepFor(sleepTime); + + delete td; + } + } + //******************************************************************** + printf("\nExponentiated array of size %d by %d using %d threads\n", arraySize, operationNum, numThreads); + complete = 1; + } + } + + // Output + printf("Before scalar operation: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", numArray[i]); + } + printf("\nAfter scalar operation: "); + for(unsigned i = 0; i < arraySize; i++){ + printf("%5d", arrayA[i]); + } + printf("\n\n"); + + // Deallocate all object memory + for (unsigned i = 0; i < numLabels; i++){ + delete labelArray[i]; + } + +} + +int main(int argc, char* argv[]){ + int operation = (argc > 1) ? atoi(argv[1]) : 0; + int numberOfThreads = (argc >2) ? atoi(argv[2]) : 4; + int sizeOfArray = (argc > 3) ? atoi(argv[3]) : 10; + + // Checks validity of operation, numThreads, and sizeOfArray; if one is invalid, set all to default + if((operation < 0 or operation > 2) or (sizeOfArray <= 0 or sizeOfArray > 24) or + (numberOfThreads <= 0 or numberOfThreads > 12)){ + printf("Invalid argument(s).\ + \nUsage: ./testThreadedArrayOperations [operation] [numberOfThreads] [sizeOfArray]\n \ + operation = 0 (addition), 1 (multiplication), or 2 (exponentiation), defaults to 0 \ + 1 <= numberOfThreads <= 12\n \ + 1 <= sizeOfArray <= 24\ + \nUsing default parameters...\n"); + operation = 0; + numberOfThreads = 4; + sizeOfArray = 10; + } + + Canvas c(0, -1, 1820, 620, "Threaded Array Scalar Operations"); + c.setBackgroundColor(BLACK); + c.run(operationVisualization, operation, numberOfThreads, sizeOfArray); +} From 2cb78b34055b6772d1b21b22531a4ed92cefa739 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 10:57:51 -0400 Subject: [PATCH 053/105] Add files via upload --- src/tests/Makefile | 43 +++++++ src/tests/test3DRotation/Makefile | 63 ++++++++++ src/tests/test3DRotation/test3DRotation.cpp | 49 ++++++++ src/tests/testArrows/Makefile | 63 ++++++++++ src/tests/testArrows/testArrows.cpp | 52 ++++++++ src/tests/testCircle/Makefile | 63 ++++++++++ src/tests/testCircle/testCircle.cpp | 68 +++++++++++ src/tests/testConcavePolygon/Makefile | 63 ++++++++++ .../testConcavePolygon/testConcavePolygon.cpp | 92 ++++++++++++++ src/tests/testCone/Makefile | 63 ++++++++++ src/tests/testCone/testCone.cpp | 89 ++++++++++++++ src/tests/testConvexPolygon/Makefile | 63 ++++++++++ .../testConvexPolygon/testConvexPolygon.cpp | 58 +++++++++ src/tests/testCube/Makefile | 63 ++++++++++ src/tests/testCube/testCube.cpp | 76 ++++++++++++ src/tests/testCuboid/Makefile | 63 ++++++++++ src/tests/testCuboid/testCuboid.cpp | 86 +++++++++++++ src/tests/testCylinder/Makefile | 63 ++++++++++ src/tests/testCylinder/testCylinder.cpp | 76 ++++++++++++ src/tests/testEllipse/Makefile | 63 ++++++++++ src/tests/testEllipse/testEllipse.cpp | 72 +++++++++++ src/tests/testEllipsoid/Makefile | 63 ++++++++++ src/tests/testEllipsoid/testEllipsoid.cpp | 113 ++++++++++++++++++ src/tests/testImage/Makefile | 63 ++++++++++ src/tests/testImage/testImage.cpp | 101 ++++++++++++++++ src/tests/testLines/Makefile | 63 ++++++++++ src/tests/testLines/testLines.cpp | 68 +++++++++++ src/tests/testPrism/Makefile | 63 ++++++++++ src/tests/testPrism/testPrism.cpp | 85 +++++++++++++ src/tests/testPyramid/Makefile | 63 ++++++++++ src/tests/testPyramid/testPyramid.cpp | 79 ++++++++++++ src/tests/testRectangle/Makefile | 63 ++++++++++ src/tests/testRectangle/testRectangle.cpp | 69 +++++++++++ src/tests/testRegularPolygon/Makefile | 63 ++++++++++ .../testRegularPolygon/testRegularPolygon.cpp | 64 ++++++++++ src/tests/testSphere/Makefile | 63 ++++++++++ src/tests/testSphere/testSphere.cpp | 81 +++++++++++++ src/tests/testSquare/Makefile | 63 ++++++++++ src/tests/testSquare/testSquare.cpp | 62 ++++++++++ src/tests/testStar/Makefile | 63 ++++++++++ src/tests/testStar/testStar.cpp | 53 ++++++++ src/tests/testText/Makefile | 63 ++++++++++ src/tests/testText/testText.cpp | 74 ++++++++++++ src/tests/testTransparency/Makefile | 63 ++++++++++ .../testTransparency/testTransparency.cpp | 32 +++++ src/tests/testTriangle/Makefile | 63 ++++++++++ src/tests/testTriangle/testTriangle.cpp | 60 ++++++++++ src/tests/testTriangleStrip/Makefile | 63 ++++++++++ .../testTriangleStrip/testTriangleStrip.cpp | 61 ++++++++++ 49 files changed, 3275 insertions(+) create mode 100644 src/tests/Makefile create mode 100644 src/tests/test3DRotation/Makefile create mode 100644 src/tests/test3DRotation/test3DRotation.cpp create mode 100644 src/tests/testArrows/Makefile create mode 100644 src/tests/testArrows/testArrows.cpp create mode 100644 src/tests/testCircle/Makefile create mode 100644 src/tests/testCircle/testCircle.cpp create mode 100644 src/tests/testConcavePolygon/Makefile create mode 100644 src/tests/testConcavePolygon/testConcavePolygon.cpp create mode 100644 src/tests/testCone/Makefile create mode 100644 src/tests/testCone/testCone.cpp create mode 100644 src/tests/testConvexPolygon/Makefile create mode 100644 src/tests/testConvexPolygon/testConvexPolygon.cpp create mode 100644 src/tests/testCube/Makefile create mode 100644 src/tests/testCube/testCube.cpp create mode 100644 src/tests/testCuboid/Makefile create mode 100644 src/tests/testCuboid/testCuboid.cpp create mode 100644 src/tests/testCylinder/Makefile create mode 100644 src/tests/testCylinder/testCylinder.cpp create mode 100644 src/tests/testEllipse/Makefile create mode 100644 src/tests/testEllipse/testEllipse.cpp create mode 100644 src/tests/testEllipsoid/Makefile create mode 100644 src/tests/testEllipsoid/testEllipsoid.cpp create mode 100644 src/tests/testImage/Makefile create mode 100644 src/tests/testImage/testImage.cpp create mode 100644 src/tests/testLines/Makefile create mode 100644 src/tests/testLines/testLines.cpp create mode 100644 src/tests/testPrism/Makefile create mode 100644 src/tests/testPrism/testPrism.cpp create mode 100644 src/tests/testPyramid/Makefile create mode 100644 src/tests/testPyramid/testPyramid.cpp create mode 100644 src/tests/testRectangle/Makefile create mode 100644 src/tests/testRectangle/testRectangle.cpp create mode 100644 src/tests/testRegularPolygon/Makefile create mode 100644 src/tests/testRegularPolygon/testRegularPolygon.cpp create mode 100644 src/tests/testSphere/Makefile create mode 100644 src/tests/testSphere/testSphere.cpp create mode 100644 src/tests/testSquare/Makefile create mode 100644 src/tests/testSquare/testSquare.cpp create mode 100644 src/tests/testStar/Makefile create mode 100644 src/tests/testStar/testStar.cpp create mode 100644 src/tests/testText/Makefile create mode 100644 src/tests/testText/testText.cpp create mode 100644 src/tests/testTransparency/Makefile create mode 100644 src/tests/testTransparency/testTransparency.cpp create mode 100644 src/tests/testTriangle/Makefile create mode 100644 src/tests/testTriangle/testTriangle.cpp create mode 100644 src/tests/testTriangleStrip/Makefile create mode 100644 src/tests/testTriangleStrip/testTriangleStrip.cpp diff --git a/src/tests/Makefile b/src/tests/Makefile new file mode 100644 index 000000000..c4d9bb6eb --- /dev/null +++ b/src/tests/Makefile @@ -0,0 +1,43 @@ +# Master Makefile for Examples + +# ***************************************************** + +SUBDIRS := $(wildcard */.) + +all: $(SUBDIRS) + +$(SUBDIRS): + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@)+++++++++++++++++" + @tput sgr0; + @echo "" + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS) + +clean: + (cd test3DRotation && $(MAKE) clean) + (cd testArrows && $(MAKE) clean) + (cd testCircle && $(MAKE) clean) + (cd testConcavePolygon && $(MAKE) clean) + (cd testCone && $(MAKE) clean) + (cd testConvexPolygon && $(MAKE) clean) + (cd testCube && $(MAKE) clean) + (cd testCuboid && $(MAKE) clean) + (cd testCylinder && $(MAKE) clean) + (cd testEllipse && $(MAKE) clean) + (cd testEllipsoid && ${MAKE} clean) + (cd testImage && $(MAKE) clean) + (cd testLines && $(MAKE) clean) + (cd testPrism && $(MAKE) clean) + (cd testPyramid && $(MAKE) clean) + (cd testRectangle && $(MAKE) clean) + (cd testRegularPolygon && $(MAKE) clean) + (cd testSphere && $(MAKE) clean) + (cd testSquare && $(MAKE) clean) + (cd testStar && $(MAKE) clean) + (cd testText && $(MAKE) clean) + (cd testTransparency && ${MAKE} clean) + (cd testTriangle && $(MAKE) clean) + (cd testTriangleStrip && ${MAKE} clean) \ No newline at end of file diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile new file mode 100644 index 000000000..03345c4c7 --- /dev/null +++ b/src/tests/test3DRotation/Makefile @@ -0,0 +1,63 @@ +# Makefile for test3DRotation + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test3DRotation + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test3DRotation/test3DRotation.cpp b/src/tests/test3DRotation/test3DRotation.cpp new file mode 100644 index 000000000..44e2d82d9 --- /dev/null +++ b/src/tests/test3DRotation/test3DRotation.cpp @@ -0,0 +1,49 @@ +/* + * test3DRotation.cpp + * + * Usage: ./test3DRotation + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); + testCube->setRotationPoint(0,0,0); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); + Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + can.add(testCube); + can.add(testPrism); + can.add(testSphere); + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + testCube->setYaw(rotation); + testPrism->setYaw(-rotation); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setYaw(-rotation); + rotation += 1; + } + + delete testCube; + delete testPrism; + delete testSphere; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Rotation"); + c.setBackgroundColor(BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile new file mode 100644 index 000000000..7411d70f1 --- /dev/null +++ b/src/tests/testArrows/Makefile @@ -0,0 +1,63 @@ +# Makefile for testArrows + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrows + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp new file mode 100644 index 000000000..4857daa1b --- /dev/null +++ b/src/tests/testArrows/testArrows.cpp @@ -0,0 +1,52 @@ +/** + * testArrows.cpp tests displaying the Line class's Arrow and Dotted attributes + */ +#include +using namespace tsgl; + +void arrowFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.5), ColorFloat(0,1,0,1) }; + Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); + Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); + c.add(doubleArrow); + c.add(arrow2); + // doubleArrow->setCenterX(100); + // doubleArrow->setRotationPoint(0,0,0); + // doubleArrow->setYaw(45); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(colors); + // printf("%f\n", doubleArrow->getAlpha()); + float floatVal = 0.0f; + GLfloat delta = 5; + bool boolean = true; + while( c.isOpen() ) { + c.sleep(); + // doubleArrow->setCenterX(sin(floatVal/90)); + // doubleArrow->setCenterY(sin(floatVal/90)); + // doubleArrow->setCenterZ(sin(floatVal/90)); + // doubleArrow->setYaw(floatVal); + // doubleArrow->setPitch(floatVal); + // doubleArrow->setRoll(floatVal); + // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); + if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { + delta *= -1; + arrow2->setIsOutlined(boolean); + arrow2->setIsFilled(!boolean); + boolean = !boolean; + } + doubleArrow->changeLengthBy(delta); + floatVal += 1; + } + + delete doubleArrow; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Arrows"); + c.setBackgroundColor(BLACK); + c.run(arrowFunction); +} \ No newline at end of file diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile new file mode 100644 index 000000000..dbd7c9653 --- /dev/null +++ b/src/tests/testCircle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCircle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCircle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCircle/testCircle.cpp b/src/tests/testCircle/testCircle.cpp new file mode 100644 index 000000000..3017ff708 --- /dev/null +++ b/src/tests/testCircle/testCircle.cpp @@ -0,0 +1,68 @@ +/* + * testCircle.cpp + * + * Usage: ./testCircle + */ + +#include +#include + +using namespace tsgl; + +void circleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Circle * circle = new Circle(0,0,0,100,0,0,0,colors); + + // printf("%f\n", circle->getAlpha()); + // circle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", circle->getAlpha()); + // circle->setColor(colors); + // printf("%f\n", circle->getAlpha()); + // circle->setCenterX(200); + // circle->setRotationPoint(0,0,0); + can.add(circle); + float floatVal = 0.0f; + GLfloat delta = 1; + while (can.isOpen()) { + can.sleep(); + // circle->setCenterX(sin(floatVal/90) * 100); + // circle->setCenterY(sin(floatVal/90) * 100); + // circle->setCenterZ(sin(floatVal/90) * 100); + // circle->setYaw(floatVal); + // circle->setPitch(floatVal); + // circle->setRoll(floatVal); + // circle->setRadius(sin(floatVal/90) * 100 + 100); + if (circle->getRadius() > 300 || circle->getRadius() < 100) { + delta *= -1; + } + circle->changeRadiusBy(delta); + if (delta > 0) { + circle->setColor(colors); + } else { + circle->setColor(RED); + } + floatVal += 1; + } + + delete circle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Basic Circle"); + c.setBackgroundColor(BLACK); + c.run(circleFunction); +} \ No newline at end of file diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile new file mode 100644 index 000000000..b6163fc7e --- /dev/null +++ b/src/tests/testConcavePolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConcavePolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConcavePolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConcavePolygon/testConcavePolygon.cpp b/src/tests/testConcavePolygon/testConcavePolygon.cpp new file mode 100644 index 000000000..547c07364 --- /dev/null +++ b/src/tests/testConcavePolygon/testConcavePolygon.cpp @@ -0,0 +1,92 @@ +/* + * testConcavePolygon.cpp + * + * Usage: ./testConcavePolygon + */ + +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/** + * \brief Draw Concave polygons, which have one or more interior angles > 180 + * \note See http://www.mathopenref.com/polygonconcave.html + * \details + * - Initialize a constant \b PSIZE. + * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. + * - Create an empty array of colors of size \b PSIZE and fill it with random colors. + * - Fill the arrays of integers, \b xx and \b yy, with specific values. + * - While the Canvas is open: + * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. + * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void concavePolygonFunction(Canvas& can) { + const int PSIZE = 64; + + float xx[PSIZE]; + float yy[PSIZE]; + ColorFloat color[PSIZE]; + for (unsigned i = 0; i < PSIZE; ++i) + color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); + + color[1] = color[PSIZE-1]; + + xx[0] = 0; + yy[0] = 0; + for (int i = 0; i < PSIZE-1; ++i) { + if (i % 2 == 0) { + xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } else { + xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } + } + + // for (int i = 0; i < PSIZE; ++i) { + // if (i % 2 == 0) { + // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } else { + // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } + // } + + ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(color); + // printf("%f\n", c2->getAlpha()); + can.add(c2); + + float floatVal = 0.0f; + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + // c2->setCenterX(sin(floatVal/90)); + // c2->setCenterY(sin(floatVal/90)); + // c2->setCenterZ(sin(floatVal/90)); + // c2->setYaw(floatVal); + // c2->setPitch(floatVal); + // c2->setRoll(floatVal); + floatVal += 1; + } + + delete c2; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Concave Polygons"); + c.setBackgroundColor(WHITE); + c.run(concavePolygonFunction); +} diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile new file mode 100644 index 000000000..38b60a4c2 --- /dev/null +++ b/src/tests/testCone/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCone + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCone + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCone/testCone.cpp b/src/tests/testCone/testCone.cpp new file mode 100644 index 000000000..bcb7f9cab --- /dev/null +++ b/src/tests/testCone/testCone.cpp @@ -0,0 +1,89 @@ +/* + * testCone.cpp + * + * Usage: ./testCone + */ + +#include +#include + +using namespace tsgl; + +void coneFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; + Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); + Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); + can.add(testCone); + can.add(testCone2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCone->setCenterX(sin(rotation)*2); + // testCone->setCenterY(cos(rotation)*2); + // testCone->setCenterZ(sin(rotation)); + // testCone->setYaw(rotation*45); + // testCone->setPitch(rotation*45); + testCone->setRoll(rotation*45); + // testCone->setHeight(sin(rotation)+1.01); + // testCone->setRadius(sin(rotation)+1.01); + // if(testCone->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCone->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeHeightBy(delta); + // if(testCone->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCone->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCone->setColor(RED); + } else { + testCone->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCone; + delete testCone2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cone"); + c.setBackgroundColor(BLACK); + c.run(coneFunction); +} \ No newline at end of file diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile new file mode 100644 index 000000000..642cd99a6 --- /dev/null +++ b/src/tests/testConvexPolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConvexPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConvexPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConvexPolygon/testConvexPolygon.cpp b/src/tests/testConvexPolygon/testConvexPolygon.cpp new file mode 100644 index 000000000..8e7b77932 --- /dev/null +++ b/src/tests/testConvexPolygon/testConvexPolygon.cpp @@ -0,0 +1,58 @@ +/* + * testConvexPolygon.cpp + * + * Usage: ./testConvexPolygon + */ + +#include +#include + +using namespace tsgl; + +void convexPolygonFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { -50,-50, 0,25,50, 50, 25 }; + float y[] = { -50, 25,50,40,10,-10,-50 }; + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); + // cp->setCenterX(2); + // cp->setRotationPoint(0,0,0); + can.add(cp); + float floatVal = 0.0f; + while (can.isOpen()) { + can.sleep(); + // cp->setCenterX(sin(floatVal/90) * 100); + // cp->setCenterY(sin(floatVal/90) * 100); + // cp->setCenterZ(sin(floatVal/90) * 100); + // cp->setYaw(floatVal); + // cp->setPitch(floatVal); + // cp->setRoll(floatVal); + // if (floatVal < 200) { + // cp->setColor(colors); + // } else { + // cp->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete cp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon"); + c.setBackgroundColor(BLACK); + c.run(convexPolygonFunction); +} \ No newline at end of file diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile new file mode 100644 index 000000000..9373a2ea4 --- /dev/null +++ b/src/tests/testCube/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCube + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCube + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCube/testCube.cpp b/src/tests/testCube/testCube.cpp new file mode 100644 index 000000000..44907768b --- /dev/null +++ b/src/tests/testCube/testCube.cpp @@ -0,0 +1,76 @@ +/* + * testCube.cpp + * + * Usage: ./testCube + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); + Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); + can.add(testCube); + + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(colors); + // printf("%f\n", testCube2->getAlpha()); + can.add(testCube2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { + testCube->setIsOutlined(boolean); + boolean = !boolean; + }); + + while (can.isOpen()) { + can.sleep(); + // testCube->setCenterX(sin(rotation)*200); + // testCube->setCenterY(cos(rotation)*200); + // testCube->setCenterZ(sin(rotation)*100); + // testCube->setYaw(rotation*45); + testCube->setPitch(rotation*45); + // testCube->setRoll(rotation*45); + // testCube->setSideLength(cos(rotation) * 100 +101); + // if(testCube->getSideLength() >= 2) { + // delta = -5; + // } + // if(testCube->getSideLength() <= 5) { + // delta = 5; + // } + // testCube->changeSideLengthBy(delta); + //testCube2->setRoll(rotation); + // if (rotation*45 >= 360) { + // if (boolean) { + // testCube->setColor(RED); + // } else { + // testCube->setColor(colors); + // } + // boolean = !boolean; + // rotation = 0; + // } + rotation+=0.01; + } + + delete testCube; + delete testCube2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cube"); + c.setBackgroundColor(BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile new file mode 100644 index 000000000..4a5120ec3 --- /dev/null +++ b/src/tests/testCuboid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCuboid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCuboid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCuboid/testCuboid.cpp b/src/tests/testCuboid/testCuboid.cpp new file mode 100644 index 000000000..b5893b27a --- /dev/null +++ b/src/tests/testCuboid/testCuboid.cpp @@ -0,0 +1,86 @@ +/* + * testCuboid.cpp + * + * Usage: ./testCuboid + */ + +#include +#include + +using namespace tsgl; + +void cuboidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); + Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(colors); + // printf("%f\n", testCuboid2->getAlpha()); + can.add(testCuboid); + can.add(testCuboid2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false;; + while (can.isOpen()) { + can.sleep(); + // testCuboid->setCenterX(sin(rotation)*200); + // testCuboid->setCenterY(cos(rotation)*200); + // testCuboid->setCenterZ(sin(rotation)*100); + // testCuboid->setYaw(rotation*45); + testCuboid->setPitch(rotation*45); + // testCuboid->setRoll(rotation*45); + // testCuboid->setWidth(cos(rotation)*100+101); + // testCuboid->setHeight(cos(rotation)*100+301); + // testCuboid->setLength(cos(rotation)*100+201); + // if(testCuboid->getWidth() >= 200) { + // delta = -5; + // } + // if(testCuboid->getWidth() <= 5) { + // delta = 5; + // } + // testCuboid->changeWidthBy(delta); + + // if(testCuboid->getHeight() >= 500) { + // delta = -5; + // } + // if(testCuboid->getHeight() <= 300) { + // delta = 5; + // } + // testCuboid->changeHeightBy(delta); + + // if(testCuboid->getLength() >= 300) { + // delta = -5; + // } + // if(testCuboid->getLength() <= 100) { + // delta = 5; + // } + // testCuboid->changeLengthBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCuboid->setColor(RED); + } else { + testCuboid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCuboid; + delete testCuboid2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cuboid"); + c.setBackgroundColor(BLACK); + c.run(cuboidFunction); +} \ No newline at end of file diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile new file mode 100644 index 000000000..aff15ef0d --- /dev/null +++ b/src/tests/testCylinder/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCylinder + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCylinder + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCylinder/testCylinder.cpp b/src/tests/testCylinder/testCylinder.cpp new file mode 100644 index 000000000..6e8075e45 --- /dev/null +++ b/src/tests/testCylinder/testCylinder.cpp @@ -0,0 +1,76 @@ +/* + * testCylinder.cpp + * + * Usage: ./testCylinder + */ + +#include +#include + +using namespace tsgl; + +void cylinderFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); + can.add(testCylinder); + can.add(testCylinder2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCylinder->setCenterX(sin(rotation)*2); + // testCylinder->setCenterY(cos(rotation)*2); + // testCylinder->setCenterZ(sin(rotation)); + // testCylinder->setYaw(rotation*45); + testCylinder->setPitch(rotation*45); + // testCylinder->setRoll(rotation*45); + // testCylinder->setHeight(sin(rotation)+1.01); + // testCylinder->setRadius(sin(rotation)+1.01); + // if(testCylinder->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeHeightBy(delta); + // if(testCylinder->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testCylinder->setColor(RED); + } else { + testCylinder->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCylinder; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cylinder"); + c.setBackgroundColor(BLACK); + c.run(cylinderFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile new file mode 100644 index 000000000..1e88f9d23 --- /dev/null +++ b/src/tests/testEllipse/Makefile @@ -0,0 +1,63 @@ +# Makefile for testEllipse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipse/testEllipse.cpp b/src/tests/testEllipse/testEllipse.cpp new file mode 100644 index 000000000..b64990098 --- /dev/null +++ b/src/tests/testEllipse/testEllipse.cpp @@ -0,0 +1,72 @@ +/* + * testEllipse.cpp + * + * Usage: ./testEllipse + */ + +#include +#include + +using namespace tsgl; + +void ellipseFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); + // ellipse->setCenterX(200); + // ellipse->setRotationPoint(0,0,0); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(colors); + // printf("%f\n", ellipse->getAlpha()); + can.add(ellipse); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // ellipse->setCenterX(sin(floatVal/90) * 100); + // ellipse->setCenterY(sin(floatVal/90) * 100); + // ellipse->setCenterZ(sin(floatVal/90) * 100); + // ellipse->setYaw(floatVal); + // ellipse->setPitch(floatVal); + // ellipse->setRoll(floatVal); + // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); + // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); + // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { + // delta *= -1; + // } + // ellipse->changeXRadiusBy(delta); + if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { + delta *= -1; + } + ellipse->changeYRadiusBy(delta); + if (delta > 0) { + ellipse->setColor(colors); + } else { + ellipse->setColor(RED); + } + floatVal += 1; + } + + delete ellipse; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipse"); + c.setBackgroundColor(BLACK); + c.run(ellipseFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile new file mode 100644 index 000000000..2b2ce5104 --- /dev/null +++ b/src/tests/testEllipsoid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testEllipsoid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipsoid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipsoid/testEllipsoid.cpp b/src/tests/testEllipsoid/testEllipsoid.cpp new file mode 100644 index 000000000..d317b523d --- /dev/null +++ b/src/tests/testEllipsoid/testEllipsoid.cpp @@ -0,0 +1,113 @@ +/* + * testEllipsoid.cpp + * + * Usage: ./testEllipsoid + */ + +#include +#include + +using namespace tsgl; + +void ellipsoidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); + // testEllipsoid->setIsFilled(false); + Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); + testEllipsoid2->setOutlineColor(BLUE); + + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(colors); + // printf("%f\n", testEllipsoid->getAlpha()); + can.add(testEllipsoid); + can.add(testEllipsoid2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = true; + bool b2 = true; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { + testEllipsoid->setIsOutlined(b2); + testEllipsoid2->setIsOutlined(b2); + b2 = !b2; + }); + + // testEllipsoid->setXRadius(150); + // testEllipsoid->setYRadius(150); + // testEllipsoid->setZRadius(150); + // testEllipsoid->changeXRadiusBy(140); + // testEllipsoid->changeYRadiusBy(140); + // testEllipsoid->changeZRadiusBy(140); + while (can.isOpen()) { + can.sleep(); + // testEllipsoid->setCenterX(sin(rotation)); + // testEllipsoid->setCenterY(cos(rotation)); + // testEllipsoid->setCenterZ(sin(rotation)); + // testEllipsoid->setYaw(rotation*45); + testEllipsoid->setPitch(rotation*45); + testEllipsoid2->setPitch(rotation*45); + // if(boolean) + // testEllipsoid->setRoll(rotation*45); + // testEllipsoid->setXRadius(cos(rotation) * 100 +101); + // testEllipsoid->setYRadius(sin(rotation) * 100 +201); + // testEllipsoid->setZRadius(sin(rotation) * 100 +301); + // if(testEllipsoid->getXRadius() >= 200) { + // delta = -5; + // } + // if(testEllipsoid->getXRadius() <= 5) { + // delta = 5; + // } + // testEllipsoid->changeXRadiusBy(delta); + + // if(testEllipsoid->getYRadius() >= 500) { + // delta = -5; + // } + // if(testEllipsoid->getYRadius() <= 300) { + // delta = 5; + // } + // testEllipsoid->changeYRadiusBy(delta); + + // if(testEllipsoid->getZRadius() >= 300) { + // delta = -5; + // } + // if(testEllipsoid->getZRadius() <= 100) { + // delta = 5; + // } + // testEllipsoid->changeZRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testEllipsoid->setColor(RED); + } else { + testEllipsoid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testEllipsoid; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid"); + c.setBackgroundColor(BLACK); + c.run(ellipsoidFunction); +} \ No newline at end of file diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile new file mode 100644 index 000000000..9a4b4e9de --- /dev/null +++ b/src/tests/testImage/Makefile @@ -0,0 +1,63 @@ +# Makefile for testImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImage/testImage.cpp b/src/tests/testImage/testImage.cpp new file mode 100644 index 000000000..117fb772f --- /dev/null +++ b/src/tests/testImage/testImage.cpp @@ -0,0 +1,101 @@ +/* + * testImage.cpp + * + * Usage: ./testImage + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a Canvas. + * \details Very basic test function showcasing image drawing capabilities. + * - The first 6 images are drawn opaque. + * - The 7th image is drawn across the entire Canvas with alpha transparency. + * . + * \param can Reference to the Canvas being drawn to. + */ +void imageFunction(Canvas& can) { + int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; + // Square * s = new Square(5,0,0,50,0,0,0,RED); + // can.add(s); + + // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); + // can.add(p); + + // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); + // can.add(image); + + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); + can.add(image); + Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); + can.add(image2); + Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); + can.add(image3); + Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); + can.add(image4); + Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); + can.add(image5); + Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); + can.add(image6); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { + image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); + }); + + // image->setHeight((GLfloat)image->getPixelHeight()); + // image->setWidth((GLfloat)image->getPixelWidth()); + + float floatVal = 0.0f; + GLfloat delta = 5; + bool ss = false; + while (can.isOpen()) { + can.sleep(); + image->setAlpha((sin(floatVal) + 1) / 2); + // image->setCenterX(sin(floatVal/90) * 100); + // image->setCenterY(sin(floatVal/90) * 100); + // image->setCenterZ(sin(floatVal/90) * 100); + // image->setYaw(floatVal); + image->setPitch(floatVal * 100); + // image->setRoll(floatVal); + // image->setWidth(sin(floatVal/90) * 100 + 400); + // image->setHeight(sin(floatVal/90) * 100 + 400); + // if (image->getWidth() > 500 || image->getWidth() < 300) { + // delta *= -1; + // } + // image->changeWidthBy(delta); + // if (image->getHeight() > 500 || image->getHeight() < 300) { + // delta *= -1; + // } + // image->changeHeightBy(delta); + // printf("%d\n", can.getFrameNumber()); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); + // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); + floatVal += 0.01; + } + + // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay + + delete image; + delete image2; + delete image3; + delete image4; + delete image5; + delete image6; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; + } + Canvas c(-1, -1, w, h ,"Images"); + c.run(imageFunction); +} diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile new file mode 100644 index 000000000..035a50499 --- /dev/null +++ b/src/tests/testLines/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLines + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLines + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp new file mode 100644 index 000000000..b51e3f340 --- /dev/null +++ b/src/tests/testLines/testLines.cpp @@ -0,0 +1,68 @@ +/** + * testLines.cpp tests displaying the Line and Polyline classes. + */ +#include +using namespace tsgl; + +void lineFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), + ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), + ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), + ColorFloat(0,0,1,0.7) }; + Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); + + // l->setColor(RED); + l->setColor(colors); + + float vertices[] = { -150,-100,-100, + -100,100,0, + -50,-100,100, + 0,-100,-100, + 50,100,0, + 100,-100,100, + 150,-100,-100 }; + + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); + + // printf("Line: %f\n", l->getAlpha()); + // printf("Pline: %f\n", p->getAlpha()); + + // p->setColor(BLUE); + p->setColor(colors); + c.add(l); + c.add(p); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while( c.isOpen() ) { + c.sleep(); + // l->setCenterX(sin(floatVal/90)); + // l->setCenterY(sin(floatVal/90)); + // l->setCenterZ(sin(floatVal/90)); + // l->setYaw(floatVal); + // l->setPitch(floatVal); + // l->setRoll(floatVal); + // l->setLength(sin(floatVal/90) + 2); + // if (l->getLength() > 3 || l->getLength() < 1) { + // delta *= -1; + // } + // l->changeLengthBy(delta); + // p->setCenterX(sin(floatVal/90)); + // p->setCenterY(sin(floatVal/90)); + // p->setCenterZ(sin(floatVal/90)); + // p->setYaw(floatVal); + // p->setPitch(floatVal); + p->setRoll(floatVal); + floatVal += 1; + } + + delete l; + delete p; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Lines"); + c.setBackgroundColor(BLACK); + c.run(lineFunction); +} \ No newline at end of file diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile new file mode 100644 index 000000000..7da1a87b9 --- /dev/null +++ b/src/tests/testPrism/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPrism + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPrism + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPrism/testPrism.cpp b/src/tests/testPrism/testPrism.cpp new file mode 100644 index 000000000..a07561a59 --- /dev/null +++ b/src/tests/testPrism/testPrism.cpp @@ -0,0 +1,85 @@ +/* + * testPrism.cpp + * + * Usage: ./testPrism + */ + +#include +#include + +using namespace tsgl; + +void prismFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); + + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(colors); + // printf("%f\n", testPrism2->getAlpha()); + can.add(testPrism); + can.add(testPrism2); + can.add(testPrism3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPrism->setCenterX(sin(rotation)*200); + // testPrism->setCenterY(cos(rotation)*200); + // testPrism->setCenterZ(sin(rotation)*100); + // testPrism->setYaw(rotation*45); + testPrism->setPitch(rotation*45); + // testPrism->setRoll(rotation*45); + // testPrism->setHeight(sin(rotation)*100+101); + // testPrism->setRadius(sin(rotation)*100+101); + // if(testPrism->getHeight() >= 200) { + // delta = -5; + // } + // if(testPrism->getHeight() <= 5) { + // delta = 5; + // } + // testPrism->changeHeightBy(delta); + // if(testPrism->getRadius() >= 200) { + // delta = -5; + // } + // if(testPrism->getRadius() <= 5) { + // delta = 5; + // } + // testPrism->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testPrism->setColor(RED); + } else { + testPrism->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPrism; + delete testPrism2; + delete testPrism3; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Prism"); + c.setBackgroundColor(BLACK); + c.run(prismFunction); +} \ No newline at end of file diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile new file mode 100644 index 000000000..c4721dd36 --- /dev/null +++ b/src/tests/testPyramid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPyramid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPyramid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPyramid/testPyramid.cpp b/src/tests/testPyramid/testPyramid.cpp new file mode 100644 index 000000000..ac0db8692 --- /dev/null +++ b/src/tests/testPyramid/testPyramid.cpp @@ -0,0 +1,79 @@ +/* + * testPyramid.cpp + * + * Usage: ./testPyramid + */ + +#include +#include + +using namespace tsgl; + +void pyramidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(colors); + // printf("%f\n", testPyramid2->getAlpha()); + can.add(testPyramid); + can.add(testPyramid2); + can.add(testPyramid3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPyramid->setCenterX(sin(rotation)*200); + // testPyramid->setCenterY(cos(rotation)*200); + // testPyramid->setCenterZ(sin(rotation)*100); + // testPyramid->setYaw(rotation*45); + testPyramid->setPitch(rotation*45); + testPyramid2->setPitch(rotation*45); + testPyramid3->setPitch(rotation*45); + // testPyramid->setRoll(sin(rotation*45)*100+101); + // testPyramid->setHeight(sin(rotation)*100+101); + // testPyramid->setRadius(sin(rotation)*100+101); + // if(testPyramid->getHeight() >= 200) { + // delta = -5; + // } + // if(testPyramid->getHeight() <= 5) { + // delta = 5; + // } + // testPyramid->changeHeightBy(delta); + // if(testPyramid->getRadius() >= 200) { + // delta = -5; + // } + // if(testPyramid->getRadius() <= 5) { + // delta = 5; + // } + // testPyramid->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testPyramid->setColor(RED); + } else { + testPyramid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPyramid; + delete testPyramid2; + delete testPyramid3; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Basic Pyramid"); + c.setBackgroundColor(BLACK); + c.run(pyramidFunction); +} \ No newline at end of file diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile new file mode 100644 index 000000000..5e0cf7fe5 --- /dev/null +++ b/src/tests/testRectangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRectangle/testRectangle.cpp b/src/tests/testRectangle/testRectangle.cpp new file mode 100644 index 000000000..89a6a9e46 --- /dev/null +++ b/src/tests/testRectangle/testRectangle.cpp @@ -0,0 +1,69 @@ +/* + * testRectangle.cpp + * + * Usage: ./testRectangle + */ + +#include +#include + +using namespace tsgl; + +void rectangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), + ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // rectangle->setCenterX(200); + // rectangle->setRotationPoint(0,0,0); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(colors); + // printf("%f\n", rectangle->getAlpha()); + can.add(rectangle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // rectangle->setCenterX(sin(floatVal/90)*100); + // rectangle->setCenterY(sin(floatVal/90)*100); + // rectangle->setCenterZ(sin(floatVal/90)*100); + // rectangle->setYaw(floatVal); + // rectangle->setPitch(floatVal); + // rectangle->setRoll(floatVal); + // rectangle->setWidth(sin(floatVal/90) *100 + 100); + // rectangle->setHeight(sin(floatVal/90) *100 + 200); + // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { + // delta *= -1; + // } + // rectangle->changeWidthBy(delta); + // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { + // delta *= -1; + // } + // rectangle->changeHeightBy(delta); + // if (delta > 0) { + // rectangle->setColor(colors); + // } else { + // rectangle->setColor(RED); + // } + floatVal += 1; + } + + delete rectangle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Rectangle"); + c.setBackgroundColor(BLACK); + c.run(rectangleFunction); +} \ No newline at end of file diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile new file mode 100644 index 000000000..9383cba89 --- /dev/null +++ b/src/tests/testRegularPolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testRegularPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRegularPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRegularPolygon/testRegularPolygon.cpp b/src/tests/testRegularPolygon/testRegularPolygon.cpp new file mode 100644 index 000000000..d3b7f54ef --- /dev/null +++ b/src/tests/testRegularPolygon/testRegularPolygon.cpp @@ -0,0 +1,64 @@ +/* + * testRegularPolygon.cpp + * + * Usage: ./testRegularPolygon + */ + +#include +#include + +using namespace tsgl; + +void rpFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); + // rp->setCenterX(200); + // rp->setRotationPoint(0,0,0); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(colors); + // printf("%f\n", rp->getAlpha()); + can.add(rp); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // rp->setCenterX(sin(floatVal/90)*100); + // rp->setCenterY(sin(floatVal/90)*100); + // rp->setCenterZ(sin(floatVal/90)*100); + // rp->setYaw(floatVal); + // rp->setPitch(floatVal); + // rp->setRoll(floatVal); + // rp->setRadius(sin(floatVal/90)*100 + 300); + if (rp->getRadius() > 300 || rp->getRadius() < 100) { + delta *= -1; + } + rp->changeRadiusBy(delta); + if (delta > 0) { + rp->setColor(colors); + } else { + rp->setColor(RED); + } + floatVal += 1; + } + + delete rp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon"); + c.setBackgroundColor(BLACK); + c.run(rpFunction); +} \ No newline at end of file diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile new file mode 100644 index 000000000..d7a7189d6 --- /dev/null +++ b/src/tests/testSphere/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSphere + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSphere + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSphere/testSphere.cpp b/src/tests/testSphere/testSphere.cpp new file mode 100644 index 000000000..e2e9a8600 --- /dev/null +++ b/src/tests/testSphere/testSphere.cpp @@ -0,0 +1,81 @@ +/* + * testSphere.cpp + * + * Usage: ./testSphere + */ + +#include +#include + +using namespace tsgl; + +void sphereFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); + Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); + testSphere->setIsOutlined(true); + testSphere2->setIsOutlined(true); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(colors); + // printf("%f\n", testSphere->getAlpha()); + can.add(testSphere); + can.add(testSphere2); + float rotation = 0.0f; + // GLfloat delta = 5; + bool boolean = true; + while (can.isOpen()) { + can.sleep(); + // testSphere->setCenterX(sin(rotation) * 100); + // testSphere->setCenterY(cos(rotation) * 100); + // testSphere->setCenterZ(sin(rotation) * 100); + // testSphere->setYaw(rotation*45); + // testSphere->setPitch(rotation*45); + testSphere->setRoll(rotation*45); + // testSphere->setRadius(cos(rotation) * 100 +101); + // if(testSphere->getRadius() >= 200) { + // delta = -5; + // } + // if(testSphere->getRadius() <= 500) { + // delta = 5; + // } + // testSphere->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + // printf("%f\n", rotation*45); + if (rotation*45 >= 360) { + if (boolean) { + testSphere->setColor(RED); + } else { + testSphere->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + + rotation+=0.01; + } + + delete testSphere; + delete testSphere2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Sphere"); + c.setBackgroundColor(BLACK); + c.run(sphereFunction); +} \ No newline at end of file diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile new file mode 100644 index 000000000..339f7d968 --- /dev/null +++ b/src/tests/testSquare/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSquare + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSquare + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSquare/testSquare.cpp b/src/tests/testSquare/testSquare.cpp new file mode 100644 index 000000000..666c9999b --- /dev/null +++ b/src/tests/testSquare/testSquare.cpp @@ -0,0 +1,62 @@ +/* + * testSquare.cpp + * + * Usage: ./testSquare + */ + +#include +#include + +using namespace tsgl; + +void squareFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Square * square = new Square(0,0,0,200,0,0,0,colors); + Square * square2 = new Square(-250,0,0,200,0,0,0,RED); + // square->setCenterX(200); + // square->setRotationPoint(0,0,0); + can.add(square); + can.add(square2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // square->setCenterX(sin(floatVal/90) * 100); + // square->setCenterY(sin(floatVal/90) * 100); + // square->setCenterZ(sin(floatVal/90) * 100); + // square->setYaw(floatVal); + // square->setPitch(floatVal); + // square->setRoll(floatVal); + // square->setSideLength(sin(floatVal/90) * 100 + 300); + // if (square->getSideLength() > 300 || square->getSideLength() < 100) { + // delta *= -1; + // } + // square->changeSideLengthBy(delta); + // if (delta > 0) { + // square->setColor(colors); + // } else { + // square->setColor(RED); + // } + floatVal += 1; + } + + delete square; + delete square2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Square"); + c.setBackgroundColor(BLACK); + c.run(squareFunction); +} \ No newline at end of file diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile new file mode 100644 index 000000000..90f33c627 --- /dev/null +++ b/src/tests/testStar/Makefile @@ -0,0 +1,63 @@ +# Makefile for testStar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testStar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testStar/testStar.cpp b/src/tests/testStar/testStar.cpp new file mode 100644 index 000000000..e7be6c610 --- /dev/null +++ b/src/tests/testStar/testStar.cpp @@ -0,0 +1,53 @@ +/** + * testStar.cpp tests displaying the Star class + * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. + */ +#include +using namespace tsgl; + +void starFunction(Canvas& c) { + ColorFloat * colors = new ColorFloat[400]; + colors[0] = ColorFloat(1,0,0,1); + for(int i = 1; i < 10; i ++) { + // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); + colors[i] = ColorFloat(0,0,1,1); + } + + Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); + // s1->setColor(RED); + c.add(s1); + + float floatVal = 0.0f; + GLfloat delta = 5; + while (c.isOpen()) { + c.sleep(); + // s1->setCenterX(sin(floatVal/90) * 100); + // s1->setCenterY(sin(floatVal/90) * 100); + // s1->setCenterZ(sin(floatVal/90) * 100); + // s1->setYaw(floatVal); + // s1->setPitch(floatVal); + // s1->setRoll(floatVal); + // s1->setRadius(sin(floatVal/90) * 100 + 300); + if (s1->getRadius() > 300 || s1->getRadius() < 100) { + delta *= -1; + } + s1->changeRadiusBy(delta); + if (delta > 0) { + s1->setColor(colors); + } else { + s1->setColor(RED); + } + floatVal += 1; + } + + delete[] colors; + // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Stars"); + c.setBackgroundColor(BLACK); + c.run(starFunction); +} \ No newline at end of file diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile new file mode 100644 index 000000000..41fa2cd44 --- /dev/null +++ b/src/tests/testText/Makefile @@ -0,0 +1,63 @@ +# Makefile for testText + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testText + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testText/testText.cpp b/src/tests/testText/testText.cpp new file mode 100644 index 000000000..1ca4b1422 --- /dev/null +++ b/src/tests/testText/testText.cpp @@ -0,0 +1,74 @@ +/* + * testText.cpp + * + * Usage: ./testSpectrum + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a Canvas. + * \details + * - We changed it so that now a default text font is loaded if one is not specified. + * - We draw a few lines of text in various colors using drawText(). + * . + * \param can Reference to the Canvas being drawn to. + * \param font The font of the text. + */ +void textFunction(Canvas& can, std::string font) { + // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); + // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + // 32, BLUE); + // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); + Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); + can.add(lowercase); + Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); + can.add(uppercase); + Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); + Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); + can.add(random); + can.add(rec); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { + random->setText(L"Glorgaborg"); + // random->setColor(RED); + // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); + // random->setFontSize(100); + }); + + float rotation = 0.0f; + while(can.isOpen()) { + can.sleep(); + // random->setCenterX(sin(rotation)*200); + // random->setCenterY(cos(rotation)*200); + // random->setCenterZ(sin(rotation)*100); + // random->setYaw(rotation*45); + random->setPitch(rotation*45); + // random->setRoll(rotation*45); + rotation+=0.01; + } + delete lowercase; + delete uppercase; + delete random; + +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; + std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 1.2f*Canvas::getDisplayHeight(); + h = 0.75f*w; + } + Canvas c(-1, -1, w, h, "Text on a Canvas"); + c.setBackgroundColor(BLACK); + c.run(textFunction, font); +} diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile new file mode 100644 index 000000000..44792324d --- /dev/null +++ b/src/tests/testTransparency/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTransparency + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTransparency + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTransparency/testTransparency.cpp b/src/tests/testTransparency/testTransparency.cpp new file mode 100644 index 000000000..c852b3e20 --- /dev/null +++ b/src/tests/testTransparency/testTransparency.cpp @@ -0,0 +1,32 @@ +/* + * testTransparency.cpp + * + * Usage: ./testTransparency + */ + +#include +#include + +using namespace tsgl; + +void transparencyFunction(Canvas& can) { + Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); + Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); + Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); + can.add(cube2); + can.add(cube); + can.add(rec); + + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + cube2->setCenterZ(150 * cos(rotation)); + rotation += 0.1; + } +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Transparency"); + c.setBackgroundColor(BLACK); + c.run(transparencyFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile new file mode 100644 index 000000000..53cee6da5 --- /dev/null +++ b/src/tests/testTriangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTriangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangle/testTriangle.cpp b/src/tests/testTriangle/testTriangle.cpp new file mode 100644 index 000000000..af80c2314 --- /dev/null +++ b/src/tests/testTriangle/testTriangle.cpp @@ -0,0 +1,60 @@ +/* + * testTriangle.cpp + * + * Usage: ./testTriangle + */ + +#include +#include + +using namespace tsgl; + +void triangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); + Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); + // triangle->setCenterX(200); + // triangle->setRotationPoint(0,0,0); + can.add(triangle); + can.add(triangle2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // triangle->setCenterX(sin(floatVal/90) * 100); + // triangle->setCenterY(sin(floatVal/90) * 100); + // triangle->setCenterZ(sin(floatVal/90) * 100); + // triangle->setYaw(floatVal); + // triangle->setPitch(floatVal); + // triangle->setRoll(floatVal); + if (floatVal < 200) { + triangle->setColor(colors); + } else { + triangle->setColor(RED); + if (floatVal > 400) { + floatVal = 0; + } + } + floatVal += 1; + } + + delete triangle; + delete triangle2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Triangle"); + c.setBackgroundColor(BLACK); + c.run(triangleFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile new file mode 100644 index 000000000..e5f78015b --- /dev/null +++ b/src/tests/testTriangleStrip/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTriangleStrip + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangleStrip + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangleStrip/testTriangleStrip.cpp b/src/tests/testTriangleStrip/testTriangleStrip.cpp new file mode 100644 index 000000000..ab27b3838 --- /dev/null +++ b/src/tests/testTriangleStrip/testTriangleStrip.cpp @@ -0,0 +1,61 @@ +/* + * testTriangleStrip.cpp + * + * Usage: ./testTriangleStrip + */ + +#include +#include + +using namespace tsgl; + +void triangleStripFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { 0,-50,50,-50,50,0 }; + float y[] = { -100,-50,-50,50,50,100 }; + float z[] = { 0,50,50,50,50,0 }; + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); + // ts->setIsOutlined(true); + // ts->setCenterX(2); + ts->setRotationPoint(0,0,0); + can.add(ts); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // ts->setCenterX(sin(floatVal/90) * 100); + // ts->setCenterY(sin(floatVal/90) * 100); + // ts->setCenterZ(sin(floatVal/90) * 100); + // ts->setYaw(floatVal); + ts->setPitch(floatVal); + // ts->setRoll(floatVal); + // if (floatVal < 200) { + // ts->setColor(colors); + // } else { + // ts->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete ts; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip"); + c.setBackgroundColor(BLACK); + c.run(triangleStripFunction); +} \ No newline at end of file From 6d594fe73c354982c47218f515c56870fe43fd7e Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:45:41 -0400 Subject: [PATCH 054/105] Add files via upload --- src/TSGL/TextureHandler.cpp | 11 +++++++++++ src/TSGL/Util.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/TSGL/TextureHandler.cpp b/src/TSGL/TextureHandler.cpp index 2e7d9ffcd..e880afac7 100644 --- a/src/TSGL/TextureHandler.cpp +++ b/src/TSGL/TextureHandler.cpp @@ -55,6 +55,17 @@ namespace tsgl { "C:\\Windows\\Fonts\\COURI.ttf" }; #endif +#ifdef __CYGWIN__ + const char* DEFAULTFONTPATHS[] = { + "../assets/freefont/FreeSerif.ttf", + "./assets/freefont/FreeSerif.ttf", + "./FreeSerif.ttf", + "C:\\Windows\\Fonts\\ARIALUNI.ttf", + "C:\\Windows\\Fonts\\ARIAL.ttf", + "C:\\Windows\\Fonts\\COUR.ttf", + "C:\\Windows\\Fonts\\COURI.ttf" + }; +#endif #ifdef __APPLE__ const char* DEFAULTFONTPATHS[] = { "../assets/freefont/FreeSerif.ttf", diff --git a/src/TSGL/Util.h b/src/TSGL/Util.h index 90ebace7a..65c0ee632 100644 --- a/src/TSGL/Util.h +++ b/src/TSGL/Util.h @@ -17,6 +17,9 @@ class CartesianCanvas; //Forward declaration for typedef #ifdef _WIN32 const double PI = 3.14159265358979323846; const double TWOPI = PI * 2; +#elif __CYGWIN__ +const double PI = 3.14159265358979323846; +const double TWOPI = PI * 2; #else const double PI = M_PI; const double TWOPI = PI * 2; From acf2aa823c80ef70534bf6efbcb6b53ace5c113e Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:53:16 -0400 Subject: [PATCH 055/105] Add files via upload --- src/tests/Makefile | 241 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 209 insertions(+), 32 deletions(-) diff --git a/src/tests/Makefile b/src/tests/Makefile index c4d9bb6eb..8e245b684 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,43 +1,220 @@ -# Master Makefile for Examples +# Master Makefile for TSGL # ***************************************************** +# Variables to control Makefile operation -SUBDIRS := $(wildcard */.) +AR=ar +CC=g++ +RM=rm -f +INSTALL=/usr/bin/install +PREFIX=/usr/local -all: $(SUBDIRS) +SRC_PATH=src/TSGL/ +TESTS_PATH=src/tests/ +EXAMPLES_PATH=src/examples/ +OBJ_PATH=build/ +VPATH=SRC_PATH:TESTS_PATH:OBJ_PATH -$(SUBDIRS): +HEADERS := $(wildcard src/TSGL/*.h) +SOURCES := $(wildcard src/TSGL/*.cpp) +OBJS := $(patsubst src/TSGL/%.cpp,build/TSGL/%.o,${SOURCES}) +NOWARN := -Wno-unused-parameter -Wno-unused-function -Wno-narrowing +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) + OS_LFLAGS := -lpthread + OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ + OS_EXTRA_LIB := -L/usr/lib + OS_GL := -lGL + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x +endif + +ifeq ($(UNAME), CYGWIN_NT-10.0) + OS_LFLAGS := -lpthread + OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ + OS_EXTRA_LIB := -L/usr/lib + OS_GL := -lGL + OS_OMP := -lgomp -fopenmp + OS_COMPILER := -std=gnu++11 +endif + +ifeq ($(UNAME), Darwin) + OS_LFLAGS := -framework Cocoa -framework OpenGl -framework IOKit -framework Corevideo + OS_LDIRS := + OS_EXTRA_LIB := + OS_GL := + OS_OMP := -fopenmp -lomp + OS_COMPILER := -std=c++0x +endif + +CXXFLAGS=-O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I${SRC_PATH}/ \ + -I/usr/include/ \ + -I/usr/local/include/ \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ + -I./ \ + $(OS_COMPILER) -fopenmp \ + ${NOWARN} -fpermissive + # -pedantic-errors + +LFLAGS=-Llib/ \ + -L/usr/local/lib \ + ${OS_EXTRA_LIB} \ + -L/usr/X11/lib/ \ + ${OS_LDIRS} \ + -ltsgl -lfreetype -lGLEW -lglfw \ + -lX11 ${OS_GL} -lXrandr -Xpreprocessor $(OS_OMP) -I"$(brew --prefix libomp)/include" \ + ${OS_LFLAGS} + +DEPFLAGS=-MMD -MP + +TESTFLAGS = -lsrc/TSGL/ + +# **************************************************** +# Targets needed to bring all files up to date + +#Use make tsgl to make only the library files +all: dif tsgl docs tutorial + +debug: dif tsgl tests + +dif: build/build + +#This may change (for the Mac installer)! +#tsgl +ifeq ($(UNAME), Linux) +tsgl: lib/libtsgl.a lib/libtsgl.so +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +tsgl: lib/libtsgl.a lib/libtsgl.dll +endif +ifeq ($(UNAME), Darwin) +tsgl: lib/libtsgl.a lib/libtsgl.so +endif + +# must run 'make' before 'make tests' and 'make examples' +tests: $(TESTS_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build + +examples: $(EXAMPLES_PATH) lib/libtsgl.a + $(MAKE) -C $< + @touch build/build + +docs: docs/html/index.html + +tutorial: tutorial/docs/html/index.html + +cleanall: clean cleandocs + +clean: + $(RM) -r bin/* build/* lib/* tutorial/docs/html/* *~ *# *.tmp + (cd $(TESTS_PATH) && $(MAKE) clean) + (cd $(EXAMPLES_PATH) && $(MAKE) clean) + +cleandocs: + $(RM) -r docs/html/* + +# -include build/*.d + +#install +ifeq ($(UNAME), Linux) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.so $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.dll $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif +ifeq ($(UNAME), Darwin) +install: + test -d $(PREFIX) || mkdir $(PREFIX) + test -d $(PREFIX)/lib || mkdir $(PREFIX) + test -d $(PREFIX)/include || mkdir $(PREFIX) + install -m 0644 lib/libtsgl.a $(PREFIX)/lib + install -m 0755 lib/libtsgl.so $(PREFIX)/lib + cp -r src/TSGL $(PREFIX)/include +endif + +build/build: ${HEADERS} ${SOURCES} ${TESTS} + @echo 'Files that changed:' + @echo $(patsubst src/%,%,$?) + +#lib/libtsgl.* +ifeq ($(UNAME), Linux) +lib/libtsgl.so: ${OBJS} + @echo 'Building $(patsubst lib/%,%,$@)' + $(CC) -shared -o $@ $? + @touch build/build +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +lib/libtsgl.dll: ${OBJS} + @echo 'Building $(patsubst lib/%,%,$@)' + $(CC) -shared -o $@ $? $(LFLAGS) + @touch build/build +endif +ifeq ($(UNAME), Darwin) +lib/libtsgl.so: ${OBJS} + @echo 'Building $(pathsubst lib/%,%,$@)' + $(CC) -shared -undefined suppress -flat_namespace -o $@ $? + @touch build/build +endif + +lib/libtsgl.a: ${OBJS} + @echo 'Building $(patsubst lib/%,%,$@)' + mkdir -p lib + $(AR) -r $@ $? + @touch build/build + +build/%.o: src/%.cpp @echo "" @tput setaf 3; - @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@)+++++++++++++++++" + @echo "+++++++++++++++++++ Building $@ +++++++++++++++++++" @tput sgr0; @echo "" - $(MAKE) -C $@ + mkdir -p ${@D} + $(CC) -c -fpic $(CXXFLAGS) $(DEPFLAGS) -o "$@" "$<" -.PHONY: all $(SUBDIRS) -clean: - (cd test3DRotation && $(MAKE) clean) - (cd testArrows && $(MAKE) clean) - (cd testCircle && $(MAKE) clean) - (cd testConcavePolygon && $(MAKE) clean) - (cd testCone && $(MAKE) clean) - (cd testConvexPolygon && $(MAKE) clean) - (cd testCube && $(MAKE) clean) - (cd testCuboid && $(MAKE) clean) - (cd testCylinder && $(MAKE) clean) - (cd testEllipse && $(MAKE) clean) - (cd testEllipsoid && ${MAKE} clean) - (cd testImage && $(MAKE) clean) - (cd testLines && $(MAKE) clean) - (cd testPrism && $(MAKE) clean) - (cd testPyramid && $(MAKE) clean) - (cd testRectangle && $(MAKE) clean) - (cd testRegularPolygon && $(MAKE) clean) - (cd testSphere && $(MAKE) clean) - (cd testSquare && $(MAKE) clean) - (cd testStar && $(MAKE) clean) - (cd testText && $(MAKE) clean) - (cd testTransparency && ${MAKE} clean) - (cd testTriangle && $(MAKE) clean) - (cd testTriangleStrip && ${MAKE} clean) \ No newline at end of file +#Doxygen stuff +docs/html/index.html: ${HEADERS} doxyfile + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++++ Generating Doxygen +++++++++++++++++++" + @tput sgr0; + @echo "" + mkdir -p docs + @doxygen doxyfile + +tutorial/docs/html/index.html: ${HEADERS} tutDoxyFile + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++++ Generating Doxygen +++++++++++++++++++" + @tput sgr0; + @echo "" + mkdir -p tutorial/docs + doxygen tutDoxyFile + +.PHONY: all debug clean tsgl docs tutorial dif +.SECONDARY: ${OBJS} ${TESTOBJS} $(OBJS:%.o=%.d) From 23530d76c2229ba8231055ef553d0fb10949320d Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:53:52 -0400 Subject: [PATCH 056/105] Add files via upload From 381410b366052ba91a8bd9fb8162981de06e7243 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:54:45 -0400 Subject: [PATCH 057/105] Add files via upload From 8e98b007daddf3efa261dffd72e54d1276927b79 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:56:24 -0400 Subject: [PATCH 058/105] Add files via upload --- src/tests/Makefile | 241 ++++++--------------------------------------- 1 file changed, 32 insertions(+), 209 deletions(-) diff --git a/src/tests/Makefile b/src/tests/Makefile index 8e245b684..807532b91 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,220 +1,43 @@ -# Master Makefile for TSGL +# Master Makefile for Examples # ***************************************************** -# Variables to control Makefile operation -AR=ar -CC=g++ -RM=rm -f -INSTALL=/usr/bin/install -PREFIX=/usr/local +SUBDIRS := $(wildcard test*/.) -SRC_PATH=src/TSGL/ -TESTS_PATH=src/tests/ -EXAMPLES_PATH=src/examples/ -OBJ_PATH=build/ -VPATH=SRC_PATH:TESTS_PATH:OBJ_PATH +all: $(SUBDIRS) -HEADERS := $(wildcard src/TSGL/*.h) -SOURCES := $(wildcard src/TSGL/*.cpp) -OBJS := $(patsubst src/TSGL/%.cpp,build/TSGL/%.o,${SOURCES}) -NOWARN := -Wno-unused-parameter -Wno-unused-function -Wno-narrowing -UNAME := $(shell uname) - -ifeq ($(UNAME), Linux) - OS_LFLAGS := -lpthread - OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ - OS_EXTRA_LIB := -L/usr/lib - OS_GL := -lGL - OS_OMP := -fopenmp -lomp - OS_COMPILER := -std=c++0x -endif - -ifeq ($(UNAME), CYGWIN_NT-10.0) - OS_LFLAGS := -lpthread - OS_LDIRS := -L/opt/AMDAPP/lib/x86_64/ - OS_EXTRA_LIB := -L/usr/lib - OS_GL := -lGL - OS_OMP := -lgomp -fopenmp - OS_COMPILER := -std=gnu++11 -endif - -ifeq ($(UNAME), Darwin) - OS_LFLAGS := -framework Cocoa -framework OpenGl -framework IOKit -framework Corevideo - OS_LDIRS := - OS_EXTRA_LIB := - OS_GL := - OS_OMP := -fopenmp -lomp - OS_COMPILER := -std=c++0x -endif - -CXXFLAGS=-O3 -g3 -ggdb3 \ - -Wall -Wextra \ - -D__GXX_EXPERIMENTAL_CXX0X__ \ - -I/usr/local/include/Cellar/glfw3/3.3/include/ \ - -I${SRC_PATH}/ \ - -I/usr/include/ \ - -I/usr/local/include/ \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - -I/opt/AMDAPP/include/ \ - -I/usr/include/c++/4.6/ \ - -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ - -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ - -I/usr/include/freetype2 \ - -I/usr/include/freetype2/freetype \ - -I./ \ - $(OS_COMPILER) -fopenmp \ - ${NOWARN} -fpermissive - # -pedantic-errors - -LFLAGS=-Llib/ \ - -L/usr/local/lib \ - ${OS_EXTRA_LIB} \ - -L/usr/X11/lib/ \ - ${OS_LDIRS} \ - -ltsgl -lfreetype -lGLEW -lglfw \ - -lX11 ${OS_GL} -lXrandr -Xpreprocessor $(OS_OMP) -I"$(brew --prefix libomp)/include" \ - ${OS_LFLAGS} - -DEPFLAGS=-MMD -MP - -TESTFLAGS = -lsrc/TSGL/ - -# **************************************************** -# Targets needed to bring all files up to date - -#Use make tsgl to make only the library files -all: dif tsgl docs tutorial - -debug: dif tsgl tests - -dif: build/build - -#This may change (for the Mac installer)! -#tsgl -ifeq ($(UNAME), Linux) -tsgl: lib/libtsgl.a lib/libtsgl.so -endif -ifeq ($(UNAME), CYGWIN_NT-10.0) -tsgl: lib/libtsgl.a lib/libtsgl.dll -endif -ifeq ($(UNAME), Darwin) -tsgl: lib/libtsgl.a lib/libtsgl.so -endif - -# must run 'make' before 'make tests' and 'make examples' -tests: $(TESTS_PATH) lib/libtsgl.a - $(MAKE) -C $< - @touch build/build - -examples: $(EXAMPLES_PATH) lib/libtsgl.a - $(MAKE) -C $< - @touch build/build - -docs: docs/html/index.html - -tutorial: tutorial/docs/html/index.html - -cleanall: clean cleandocs - -clean: - $(RM) -r bin/* build/* lib/* tutorial/docs/html/* *~ *# *.tmp - (cd $(TESTS_PATH) && $(MAKE) clean) - (cd $(EXAMPLES_PATH) && $(MAKE) clean) - -cleandocs: - $(RM) -r docs/html/* - -# -include build/*.d - -#install -ifeq ($(UNAME), Linux) -install: - test -d $(PREFIX) || mkdir $(PREFIX) - test -d $(PREFIX)/lib || mkdir $(PREFIX) - test -d $(PREFIX)/include || mkdir $(PREFIX) - install -m 0644 lib/libtsgl.a $(PREFIX)/lib - install -m 0755 lib/libtsgl.so $(PREFIX)/lib - cp -r src/TSGL $(PREFIX)/include -endif -ifeq ($(UNAME), CYGWIN_NT-10.0) -install: - test -d $(PREFIX) || mkdir $(PREFIX) - test -d $(PREFIX)/lib || mkdir $(PREFIX) - test -d $(PREFIX)/include || mkdir $(PREFIX) - install -m 0644 lib/libtsgl.a $(PREFIX)/lib - install -m 0755 lib/libtsgl.dll $(PREFIX)/lib - cp -r src/TSGL $(PREFIX)/include -endif -ifeq ($(UNAME), Darwin) -install: - test -d $(PREFIX) || mkdir $(PREFIX) - test -d $(PREFIX)/lib || mkdir $(PREFIX) - test -d $(PREFIX)/include || mkdir $(PREFIX) - install -m 0644 lib/libtsgl.a $(PREFIX)/lib - install -m 0755 lib/libtsgl.so $(PREFIX)/lib - cp -r src/TSGL $(PREFIX)/include -endif - -build/build: ${HEADERS} ${SOURCES} ${TESTS} - @echo 'Files that changed:' - @echo $(patsubst src/%,%,$?) - -#lib/libtsgl.* -ifeq ($(UNAME), Linux) -lib/libtsgl.so: ${OBJS} - @echo 'Building $(patsubst lib/%,%,$@)' - $(CC) -shared -o $@ $? - @touch build/build -endif -ifeq ($(UNAME), CYGWIN_NT-10.0) -lib/libtsgl.dll: ${OBJS} - @echo 'Building $(patsubst lib/%,%,$@)' - $(CC) -shared -o $@ $? $(LFLAGS) - @touch build/build -endif -ifeq ($(UNAME), Darwin) -lib/libtsgl.so: ${OBJS} - @echo 'Building $(pathsubst lib/%,%,$@)' - $(CC) -shared -undefined suppress -flat_namespace -o $@ $? - @touch build/build -endif - -lib/libtsgl.a: ${OBJS} - @echo 'Building $(patsubst lib/%,%,$@)' - mkdir -p lib - $(AR) -r $@ $? - @touch build/build - -build/%.o: src/%.cpp - @echo "" - @tput setaf 3; - @echo "+++++++++++++++++++ Building $@ +++++++++++++++++++" - @tput sgr0; - @echo "" - mkdir -p ${@D} - $(CC) -c -fpic $(CXXFLAGS) $(DEPFLAGS) -o "$@" "$<" - - -#Doxygen stuff -docs/html/index.html: ${HEADERS} doxyfile +$(SUBDIRS): @echo "" @tput setaf 3; - @echo "+++++++++++++++++++ Generating Doxygen +++++++++++++++++++" + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@)+++++++++++++++++" @tput sgr0; @echo "" - mkdir -p docs - @doxygen doxyfile + $(MAKE) -C $@ -tutorial/docs/html/index.html: ${HEADERS} tutDoxyFile - @echo "" - @tput setaf 3; - @echo "+++++++++++++++++++ Generating Doxygen +++++++++++++++++++" - @tput sgr0; - @echo "" - mkdir -p tutorial/docs - doxygen tutDoxyFile +.PHONY: all $(SUBDIRS) -.PHONY: all debug clean tsgl docs tutorial dif -.SECONDARY: ${OBJS} ${TESTOBJS} $(OBJS:%.o=%.d) +clean: + (cd test3DRotation && $(MAKE) clean) + (cd testArrows && $(MAKE) clean) + (cd testCircle && $(MAKE) clean) + (cd testConcavePolygon && $(MAKE) clean) + (cd testCone && $(MAKE) clean) + (cd testConvexPolygon && $(MAKE) clean) + (cd testCube && $(MAKE) clean) + (cd testCuboid && $(MAKE) clean) + (cd testCylinder && $(MAKE) clean) + (cd testEllipse && $(MAKE) clean) + (cd testEllipsoid && ${MAKE} clean) + (cd testImage && $(MAKE) clean) + (cd testLines && $(MAKE) clean) + (cd testPrism && $(MAKE) clean) + (cd testPyramid && $(MAKE) clean) + (cd testRectangle && $(MAKE) clean) + (cd testRegularPolygon && $(MAKE) clean) + (cd testSphere && $(MAKE) clean) + (cd testSquare && $(MAKE) clean) + (cd testStar && $(MAKE) clean) + (cd testText && $(MAKE) clean) + (cd testTransparency && ${MAKE} clean) + (cd testTriangle && $(MAKE) clean) + (cd testTriangleStrip && ${MAKE} clean) \ No newline at end of file From 000abca2ac0d6c2b9b7713ab7cf46973c1b5b9af Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 14 Jul 2020 17:36:04 -0400 Subject: [PATCH 059/105] Add files via upload --- src/examples/Pandemic/Pandemic.cpp | 124 +++++++++++++++++++++---- src/examples/Pandemic/Pandemic.h | 27 ++++-- src/examples/Pandemic/Person.cpp | 43 +++++++-- src/examples/Pandemic/Person.h | 7 +- src/examples/Pandemic/testPandemic.cpp | 30 ++++-- 5 files changed, 188 insertions(+), 43 deletions(-) diff --git a/src/examples/Pandemic/Pandemic.cpp b/src/examples/Pandemic/Pandemic.cpp index b799c8622..18148d2f2 100644 --- a/src/examples/Pandemic/Pandemic.cpp +++ b/src/examples/Pandemic/Pandemic.cpp @@ -1,42 +1,59 @@ #include "Pandemic.h" -#define RADIUS 5 +#define RADIUS 5 // radius for the Person circles +#define infection_radius 30 using namespace tsgl; -Pandemic::Pandemic(Canvas& can, unsigned numPeople){ +// Initializes the pandemic +Pandemic::Pandemic(Canvas& can, unsigned numPeople, unsigned numToInfect, unsigned infectionRate){ // current day current_day = 0; // people counters number_of_people = numPeople; - num_initially_infected = 0; + num_initially_infected = numToInfect; // states counters - num_infected = 0; - num_susceptible = numPeople; + num_infected = numToInfect; + num_susceptible = numPeople - numToInfect; num_immune = 0; num_dead = 0; // stats - num_infections = 0; + contagiousness_factor = infectionRate; + num_infections = numToInfect; num_infection_attempts = 0; num_deaths = 0; num_recoveries = 0; + // window dimensions + max_x = can.getWindowWidth()/2; + max_y = can.getWindowHeight()/2; + // Generate random seed srand( time(0) ); - // // Set radius - // float radius = 250/number_of_people; - // Fill vectors - for(unsigned i = 0; i < number_of_people; ++i){ - myPersons.push_back(new Person(rand()%(can.getWindowWidth())-(can.getWindowWidth())/2, - rand()%(can.getWindowHeight())-can.getWindowHeight()/2, + // Fill vectors with infected + for(unsigned i = 0; i < num_infected; ++i){ + myPersons.push_back(new Person(rand()%(can.getWindowWidth())-max_x, + rand()%(can.getWindowHeight())-max_y, + RADIUS, infected)); // myPersons + x_locations.push_back(myPersons[i]->getX()); // x_locations + y_locations.push_back(myPersons[i]->getY()); // y_locations + infected_x_locations.push_back(myPersons[i]->getX()); // infected_x_locations + infected_y_locations.push_back(myPersons[i]->getY()); // infected_y_locations + // states.push_back(infected); // states + // num_days_infected.push_back(0); // num_days_infected + } + // Fill vectors with susceptible + for(unsigned i = num_infected; i < number_of_people; ++i){ + myPersons.push_back(new Person(rand()%(can.getWindowWidth())-max_x, + rand()%(can.getWindowHeight())-max_y, RADIUS, susceptible)); // myPersons x_locations.push_back(myPersons[i]->getX()); // x_locations y_locations.push_back(myPersons[i]->getY()); // y_locations infected_x_locations.push_back(0); // infected_x_locations infected_y_locations.push_back(0); // infected_y_locations - states.push_back(susceptible); // states - num_days_infected.push_back(0); // num_days_infected + // states.push_back(susceptible); // states + // num_days_infected.push_back(0); // num_days_infected } } @@ -47,6 +64,81 @@ void Pandemic::draw(Canvas& can){ } } +void Pandemic::updateStatuses(){ + for(unsigned i = 0; i < number_of_people; ++i){ + myPersons[i]->updateColor(); + } +} + +// void Pandemic::findInfected(){ +// for(unsigned i = 0; i < number_of_people; ++i){ +// if(myPersons[i]->getStatus() == infected){ +// infected_x_locations[i] = myPersons[i]->getX(); +// infected_y_locations[i] = myPersons[i]->getY(); +// } +// } +// } + +void Pandemic::movePersons(Canvas& can){ + float x_move_direction, y_move_direction; + for(unsigned i = 0; i < number_of_people; ++i){ + if(myPersons[i]->getStatus() != dead){ + // x_move_direction = ((rand()%3) - 1) * 10; + // y_move_direction = ((rand()%3) - 1) * 10; + x_move_direction = ((rand()%301)-150)/10; + y_move_direction = ((rand()%301)-150)/10; + + // Check if move is valid (within the window) + if((x_locations[i] + x_move_direction > -max_x) && + (x_locations[i] + x_move_direction < max_x) && + (y_locations[i] + y_move_direction > -max_y) && + (y_locations[i] + y_move_direction < max_y)) + { + // Move Person + myPersons[i]->changeXYBy(x_move_direction, y_move_direction); + // Update locations + x_locations[i] += x_move_direction; + y_locations[i] += y_move_direction; + // findInfected(); + } + } + } +} + +void Pandemic::checkForInfection(){ + // For all people + for(unsigned i = 0; i < number_of_people; ++i){ + if(myPersons[i]->getStatus() == susceptible){ + // For those that are susceptible, check if there are any infected nearby + for(unsigned j = 0; j < number_of_people; ++j){ + if(myPersons[j]->getStatus() == infected){ + // Check if susceptible person is in infection radius + // printf("X: %f %f Y: %f %f\n", myPersons[i]->getX(), myPersons[j]->getX(), myPersons[i]->getY(), myPersons[j]->getY()); + if((myPersons[i]->getX() > myPersons[j]->getX() - infection_radius) && + (myPersons[i]->getX() < myPersons[j]->getX() + infection_radius) && + (myPersons[i]->getY() > myPersons[j]->getY() - infection_radius) && + (myPersons[i]->getY() < myPersons[j]->getY() + infection_radius)) + { // ISSUE IS WITH THE FOR LOOPS: SOMEHOW NOT EVERYTHING IS GETTING CHECKED, OR AT LEAST NOT GETTING CHECKED CORRECTLY + printf("AT RISK: PERSON %d\n", i); + ++num_infection_attempts; + // // Determine if person gets infected + // printf("RandNum: %d\n", randNum); + if(rand()%101 <= contagiousness_factor){ + printf("PERSON %d INFECTED\n", i); + myPersons[i]->setStatus(infected); + myPersons[i]->updateColor(); + ++num_infected; + // printf("num_infected increased to %d\n", num_infected); + --num_susceptible; + break; // to break out of the j for loop + } + } + } + } + } + } +} + /*! * \brief Destructor for Pandemic. */ @@ -59,6 +151,6 @@ Pandemic::~Pandemic(){ y_locations.clear(); infected_x_locations.clear(); infected_y_locations.clear(); - states.clear(); - num_days_infected.clear(); + // states.clear(); + // num_days_infected.clear(); } \ No newline at end of file diff --git a/src/examples/Pandemic/Pandemic.h b/src/examples/Pandemic/Pandemic.h index da12fb190..aee4f70de 100644 --- a/src/examples/Pandemic/Pandemic.h +++ b/src/examples/Pandemic/Pandemic.h @@ -31,17 +31,22 @@ class Pandemic { std::vector infected_x_locations; std::vector infected_y_locations; // state - std::vector states; + // std::vector states; // infected time - std::vector num_days_infected; + // std::vector num_days_infected; + + // window dimensions + float max_x; + float max_y; // stats + unsigned contagiousness_factor; unsigned num_infections; unsigned num_infection_attempts; unsigned num_deaths; unsigned num_recoveries; public: - Pandemic(Canvas& can, unsigned numPeople); + Pandemic(Canvas& can, unsigned numPeople, unsigned numToInfect, unsigned infectionRate); void draw(Canvas& can); @@ -70,11 +75,7 @@ class Pandemic { int getInfectedYLocation(unsigned i) { return infected_y_locations[i]; } - int getState(unsigned i) { return states[i]; } - - int getNumDaysInfected(unsigned i) { return num_days_infected[i]; } - - unsigned numInfections() { return num_infections; } + unsigned getNumInfections() { return num_infections; } unsigned getNumInfectionAttempts() { return num_infection_attempts; } @@ -82,6 +83,16 @@ class Pandemic { unsigned getNumRecoveries() { return num_recoveries; } + + // Utility + void updateStatuses(); + + // void findInfected(); + + void movePersons(Canvas& can); + + void checkForInfection(); + virtual ~Pandemic(); }; diff --git a/src/examples/Pandemic/Person.cpp b/src/examples/Pandemic/Person.cpp index d1afa89a4..628525d56 100644 --- a/src/examples/Pandemic/Person.cpp +++ b/src/examples/Pandemic/Person.cpp @@ -7,7 +7,9 @@ Person::Person(float x, float y, GLfloat radius, char status){ myY = y; myCircleRadius = radius; myStatus = status; + numInfectedNearby = 0; + // Determine color switch(myStatus){ case susceptible : myColor = ColorFloat(1,1,0,1); @@ -25,6 +27,7 @@ Person::Person(float x, float y, GLfloat radius, char status){ myColor = ColorFloat(0,0,0,1); } + // Create visual representation myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); } @@ -37,6 +40,11 @@ void Person::draw(Canvas& can){ can.add(myCircle); } + +void Person::setStatus(char status){ + myStatus = status; +} + /** * \brief Sets the radius of the Person's Circle to a new radius. * \param radius The new radius. @@ -45,15 +53,32 @@ void Person::setCircleRadius(GLfloat radius){ myCircle->setRadius(radius); } -// /** -// * \brief Sets the Person's Cubes to a new color. -// * \param color The new ColorFloat. -// */ -// void Person::setColor(ColorFloat color){ -// for (Cube * c : myCubes){ -// c->setColor(color); -// } -// } +void Person::changeXYBy(float x, float y){ + myCircle->changeXBy(x); myCircle->changeYBy(y); +} + +/** + * \brief Sets the Person's Cubes to a new color. + */ +void Person::updateColor(){ + switch(myStatus){ + case susceptible : + myColor = ColorFloat(1,1,0,1); + break; + case infected : + myColor = ColorFloat(1,0,0,1); + break; + case immune : + myColor = ColorFloat(0,1,0,1); + break; + case dead : + myColor = ColorFloat(0.5,0.5,0.5,1); + break; + default: + myColor = ColorFloat(0,0,0,1); + } + myCircle->setColor(myColor); +} // /** // * \brief Sets the Person's Cubes to new colors. diff --git a/src/examples/Pandemic/Person.h b/src/examples/Pandemic/Person.h index 864292e64..e95f79cdd 100644 --- a/src/examples/Pandemic/Person.h +++ b/src/examples/Pandemic/Person.h @@ -17,6 +17,7 @@ class Person { // Pandemic data char myStatus; + unsigned numInfectedNearby; unsigned numDaysInfected; public: // Person(); @@ -41,9 +42,13 @@ class Person { // // Mutators - // int& operator[](unsigned i) { return myData[i]; } + void setStatus(char status); void setCircleRadius(GLfloat radius); + + void changeXYBy(float x, float y); + + void updateColor(); // void setColor(ColorFloat c); diff --git a/src/examples/Pandemic/testPandemic.cpp b/src/examples/Pandemic/testPandemic.cpp index 1c01f10bc..eeb2237dc 100644 --- a/src/examples/Pandemic/testPandemic.cpp +++ b/src/examples/Pandemic/testPandemic.cpp @@ -13,11 +13,12 @@ // disease constants #define INFECTION_RADIUS 10 +#define NUM_TO_INFECT 10 // #define DURATION_OF_DISEASE // #define contagiousness_factor; // #define deadliness_factor; // // time constants -#define NUM_DAYS 21 // total number of days for pandemic +#define NUM_DAYS 365 // total number of days for pandemic #define MS_PER_DAY 200000; // microseconds per day using namespace tsgl; @@ -27,16 +28,16 @@ void pandemicFunction(Canvas& can, unsigned numPersons, unsigned infectionRate) srand( time(0) ); // Create Pandemic - Pandemic * p = new Pandemic(can, numPersons); + Pandemic * p = new Pandemic(can, numPersons, NUM_TO_INFECT, infectionRate); - float sleepTime = 0.125; // initial number of seconds to sleep 0.5 + float sleepTime = 0.03125; // initial number of seconds to sleep 0.03125 // Key bindings to speed up/slow down animation can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ sleepTime /= 2; }); can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ - if(sleepTime < 8){ + if(sleepTime < 1){ sleepTime *= 2; } }); @@ -44,23 +45,34 @@ void pandemicFunction(Canvas& can, unsigned numPersons, unsigned infectionRate) p->draw(can); unsigned complete = 0; // ensures simulation only runs once + printf("%d\n", infectionRate); while (can.isOpen()) { if(complete == 0){ for(unsigned currentDay = 0; currentDay < NUM_DAYS; ++currentDay){ - + printf("********Day %d********\n", currentDay+1); + p->updateStatuses(); + // p->findInfected(); + can.sleepFor(sleepTime); + p->movePersons(can); + can.sleepFor(sleepTime); + p->checkForInfection(); } complete = 1; } } // Output - printf("\nStatistics and data: \ + printf("\n***********************\ + \n* Statistics and data *\ + \n***********************\ + \n\ + \nInfection rate: %.2f\ \n\ \nSusceptible: %d\ \nInfected: %d\ \nImmune: %d\ \nDead: %d\ - \n", p->getNumSusceptible(), p->getNumInfected(), p->getNumImmune(), p->getNumDead()); + \n", infectionRate/100.0, p->getNumSusceptible(), p->getNumInfected(), p->getNumImmune(), p->getNumDead()); // Deallocate all object memory delete p; @@ -69,10 +81,10 @@ void pandemicFunction(Canvas& can, unsigned numPersons, unsigned infectionRate) int main(int argc, char* argv[]){ int numPersons = (argc > 1) ? atoi(argv[1]) : 50; - int infectionRate = (argc > 2) ? atoi(argv[2]) : 20; + int infectionRate = (argc > 2) ? atoi(argv[2]) : 100; // Checks validity of numPersons and infectionRate; if invalid, set to default - if((numPersons <= 0 or numPersons > 200)){ + if((numPersons <= 0 or numPersons > 200) || (infectionRate < 0 or infectionRate > 100)){ printf("Invalid argument(s).\ \nUsage: ./testPandemic [numPersons] [infectionRate]\n \ 1 <= numPersons <= 200\ From f7cad547468a640a425806bba2e9dd36dceaeb00 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:36:23 -0400 Subject: [PATCH 060/105] Add files via upload --- src/tests/test2Dvs3D/Makefile | 63 ++++ src/tests/test2Dvs3D/test2Dvs3D.cpp | 96 ++++++ src/tests/test3DRotation/test3DRotation.cpp | 3 +- src/tests/testAlphaRectangle/Makefile | 63 ++++ .../testAlphaRectangle/testAlphaRectangle.cpp | 49 +++ src/tests/testArrows/testArrows.cpp | 1 - src/tests/testAura/Makefile | 63 ++++ src/tests/testAura/testAura.cpp | 111 +++++++ src/tests/testBackground/Makefile | 63 ++++ src/tests/testBackground/testBackground.cpp | 70 ++++ src/tests/testBlurImage/Makefile | 63 ++++ src/tests/testBlurImage/testBlurImage.cpp | 62 ++++ src/tests/testCalcPi/Makefile | 63 ++++ src/tests/testCalcPi/testCalcPi.cpp | 76 +++++ src/tests/testCircle/testCircle.cpp | 3 +- src/tests/testColorWheel/Makefile | 63 ++++ src/tests/testColorWheel/testColorWheel.cpp | 75 +++++ .../testConcavePolygon/testConcavePolygon.cpp | 3 +- src/tests/testCone/testCone.cpp | 3 +- src/tests/testConstructors/Makefile | 63 ++++ .../testConstructors/testConstructors.cpp | 304 ++++++++++++++++++ .../testConvexPolygon/testConvexPolygon.cpp | 3 +- src/tests/testCosineIntegral/Makefile | 63 ++++ .../testCosineIntegral/testCosineIntegral.cpp | 84 +++++ src/tests/testCube/testCube.cpp | 8 +- src/tests/testCuboid/testCuboid.cpp | 3 +- src/tests/testCylinder/testCylinder.cpp | 3 +- src/tests/testDice/Makefile | 63 ++++ src/tests/testDice/testDice.cpp | 179 +++++++++++ src/tests/testDiorama/Makefile | 63 ++++ src/tests/testDiorama/testDiorama.cpp | 118 +++++++ src/tests/testEllipse/testEllipse.cpp | 3 +- src/tests/testEllipsoid/testEllipsoid.cpp | 3 +- src/tests/testFunction/Makefile | 63 ++++ src/tests/testFunction/testFunction.cpp | 51 +++ src/tests/testGetPixels/Makefile | 63 ++++ src/tests/testGetPixels/testGetPixels.cpp | 62 ++++ src/tests/testGradientWheel/Makefile | 63 ++++ .../testGradientWheel/testGradientWheel.cpp | 65 ++++ src/tests/testGraydient/Makefile | 63 ++++ src/tests/testGraydient/testGraydient.cpp | 52 +++ src/tests/testGreyscale/Makefile | 63 ++++ src/tests/testGreyscale/testGreyscale.cpp | 86 +++++ src/tests/testHighData/Makefile | 63 ++++ src/tests/testHighData/testHighData.cpp | 54 ++++ src/tests/testImage/testImage.cpp | 4 +- src/tests/testImageCart/Makefile | 63 ++++ src/tests/testImageCart/testImageCart.cpp | 37 +++ src/tests/testInverter/ImageInverter.cpp | 56 ++++ src/tests/testInverter/ImageInverter.h | 79 +++++ src/tests/testInverter/Makefile | 63 ++++ src/tests/testInverter/testInverter.cpp | 16 + src/tests/test_specs/Makefile | 63 ++++ src/tests/test_specs/test_specs.cpp | 31 ++ 54 files changed, 3090 insertions(+), 23 deletions(-) create mode 100644 src/tests/test2Dvs3D/Makefile create mode 100644 src/tests/test2Dvs3D/test2Dvs3D.cpp create mode 100644 src/tests/testAlphaRectangle/Makefile create mode 100644 src/tests/testAlphaRectangle/testAlphaRectangle.cpp create mode 100644 src/tests/testAura/Makefile create mode 100644 src/tests/testAura/testAura.cpp create mode 100644 src/tests/testBackground/Makefile create mode 100644 src/tests/testBackground/testBackground.cpp create mode 100644 src/tests/testBlurImage/Makefile create mode 100644 src/tests/testBlurImage/testBlurImage.cpp create mode 100644 src/tests/testCalcPi/Makefile create mode 100644 src/tests/testCalcPi/testCalcPi.cpp create mode 100644 src/tests/testColorWheel/Makefile create mode 100644 src/tests/testColorWheel/testColorWheel.cpp create mode 100644 src/tests/testConstructors/Makefile create mode 100644 src/tests/testConstructors/testConstructors.cpp create mode 100644 src/tests/testCosineIntegral/Makefile create mode 100644 src/tests/testCosineIntegral/testCosineIntegral.cpp create mode 100644 src/tests/testDice/Makefile create mode 100644 src/tests/testDice/testDice.cpp create mode 100644 src/tests/testDiorama/Makefile create mode 100644 src/tests/testDiorama/testDiorama.cpp create mode 100644 src/tests/testFunction/Makefile create mode 100644 src/tests/testFunction/testFunction.cpp create mode 100644 src/tests/testGetPixels/Makefile create mode 100644 src/tests/testGetPixels/testGetPixels.cpp create mode 100644 src/tests/testGradientWheel/Makefile create mode 100644 src/tests/testGradientWheel/testGradientWheel.cpp create mode 100644 src/tests/testGraydient/Makefile create mode 100644 src/tests/testGraydient/testGraydient.cpp create mode 100644 src/tests/testGreyscale/Makefile create mode 100644 src/tests/testGreyscale/testGreyscale.cpp create mode 100644 src/tests/testHighData/Makefile create mode 100644 src/tests/testHighData/testHighData.cpp create mode 100644 src/tests/testImageCart/Makefile create mode 100644 src/tests/testImageCart/testImageCart.cpp create mode 100644 src/tests/testInverter/ImageInverter.cpp create mode 100644 src/tests/testInverter/ImageInverter.h create mode 100644 src/tests/testInverter/Makefile create mode 100644 src/tests/testInverter/testInverter.cpp create mode 100644 src/tests/test_specs/Makefile create mode 100644 src/tests/test_specs/test_specs.cpp diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile new file mode 100644 index 000000000..2e37f36e4 --- /dev/null +++ b/src/tests/test2Dvs3D/Makefile @@ -0,0 +1,63 @@ +# Makefile for test2Dvs3D + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test2Dvs3D + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp new file mode 100644 index 000000000..2c47d5f79 --- /dev/null +++ b/src/tests/test2Dvs3D/test2Dvs3D.cpp @@ -0,0 +1,96 @@ +/* + * test2Dvs3D.cpp + * + * Usage: ./test2Dvs3D + */ + +#include +#include + +using namespace tsgl; + +void contrastFunction(Canvas& can) { + ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; + ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; + ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; + Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); + // can.add(testPyramid); + Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); + // can.add(triangle1); + Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); + // can.add(triangle2); + Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); + // can.add(triangle3); + Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); + // can.add(triangle4); + Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); + // can.add(triangle5); + Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); + // can.add(triangle6); + // testPyramid->setPitch(45); + int stepsTaken = 0; + while (can.isOpen()) { + can.sleep(); + if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { + can.add(triangle1); + stepsTaken++; + } + if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { + can.add(triangle2); + stepsTaken++; + } + if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { + can.add(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { + can.add(testPyramid); + stepsTaken++; + } + if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { + can.remove(triangle1); + can.remove(triangle2); + can.remove(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { + can.add(triangle4); + stepsTaken++; + } + if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { + can.add(triangle5); + stepsTaken++; + } + if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { + can.add(triangle6); + stepsTaken++; + } + if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { + if (testPyramid->getPitch() < 45) { + testPyramid->changePitchBy(0.5); + } else { + testPyramid->setPitch(45); + stepsTaken++; + } + } + } + + delete testPyramid; + delete triangle1; + delete triangle2; + delete triangle3; + delete triangle4; + delete triangle5; + delete triangle6; + +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing", BLACK); + c.run(contrastFunction); +} \ No newline at end of file diff --git a/src/tests/test3DRotation/test3DRotation.cpp b/src/tests/test3DRotation/test3DRotation.cpp index 44e2d82d9..1ed4e77bd 100644 --- a/src/tests/test3DRotation/test3DRotation.cpp +++ b/src/tests/test3DRotation/test3DRotation.cpp @@ -43,7 +43,6 @@ void cubeFunction(Canvas& can) { } int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "3D Rotation"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "3D Rotation", BLACK); c.run(cubeFunction); } \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile new file mode 100644 index 000000000..072c3514f --- /dev/null +++ b/src/tests/testAlphaRectangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAlphaRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAlphaRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/testAlphaRectangle.cpp b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp new file mode 100644 index 000000000..8721ee1ea --- /dev/null +++ b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp @@ -0,0 +1,49 @@ +/* + * testAlphaRectangle.cpp + * + * Usage: ./testAlphaRectangle + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws semi-transparent rectangles on a Canvas. + * \details + * - Store the Canvas' width and height in variables for easy reuse. + * - Set up the internal timer of the Canvas to expire once every \b FRAME / 10 seconds. + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - Select a random position on the Canvas for a corner of a rectangle. + * - Draw a rectangle stretching from the specified corner to another corner on the Canvas, + * with a random color and a transparency of 16 (~0.06). + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void alphaRectangleFunction(Canvas& can) { + Background * bg = can.getBackground(); + const int WW = can.getWindowWidth(), WH = can.getWindowHeight(); + int a, b, c, d, x, y, w, h; + while (can.isOpen()) { + can.sleep(); + a = saferand(-WW/2,WW/2); b = saferand(-WH/2, WH/2); + c = saferand(-WW/2,WW/2); d = saferand(-WH/2, WH/2); + x = (a + c) / 2; + y = (b + d) / 2; + w = abs(c - a); + h = abs(d - b); + bg->drawRectangle(x, y, 0, w, h, 0,0,0, ColorFloat(randfloat(), randfloat(), randfloat(), (float) 16/255)); + } +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Fancy Rectangles", BLACK); + c.run(alphaRectangleFunction); +} diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp index 4857daa1b..61b13731c 100644 --- a/src/tests/testArrows/testArrows.cpp +++ b/src/tests/testArrows/testArrows.cpp @@ -47,6 +47,5 @@ int main(int argc, char* argv[]) { int w = 1000; int h = 1000; Canvas c(-1, -1, w, h, "Arrows"); - c.setBackgroundColor(BLACK); c.run(arrowFunction); } \ No newline at end of file diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile new file mode 100644 index 000000000..f1487e646 --- /dev/null +++ b/src/tests/testAura/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAura + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAura + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAura/testAura.cpp b/src/tests/testAura/testAura.cpp new file mode 100644 index 000000000..5620f36d7 --- /dev/null +++ b/src/tests/testAura/testAura.cpp @@ -0,0 +1,111 @@ +/* + * testMouse.cpp + * + * Usage: ./testMouse + */ + +#include + +using namespace tsgl; + +inline float dist(float x1, float y1, float x2, float y2) { + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +inline void scatter(float& f, float max) { + float am = 1.0f - ((rand() % 20000) / 10000.0f); + f += max*am; +} + +/*! + * + */ +void auraFunction(Canvas& can, int segs) { + const float SR2 = sqrt(2); + const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); + const int ccw = CW/2, cch = CH/2; + const float ROT = 0.01f; + const float HUEDELTA = 0.01f; + const float OFF = (2*PI/segs); + const float START = PI/2; + + int mx, my; + ColorHSV *cf = new ColorHSV[segs]; + bool *drawn = new bool[segs]; + float *x1 = new float[segs], *y1 = new float[segs], + *x2 = new float[segs], *y2 = new float[segs]; + + float mangle = 0; + float mdist = 0; + + for (int i = 0; i < segs; ++i) { + cf[i] = Colors::highContrastColor(i); + cf[i].A = 0.01f; + } + + while(can.isOpen()) { + //Update mouse coordinates + scatter(mangle,0.02f); + scatter(mdist,2.0f); + if (mdist > 100) mdist *= 0.99f; + mx = can.getMouseX()+mdist*cos(mangle); + my = can.getMouseY()+mdist*sin(mangle); + + //Update positions of the edges of the triangles + float ang = START + ROT*can.getFrameNumber(); + for (int i = 0; i < segs; ++i) { + cf[i].H += HUEDELTA; + if (cf[i].H > 6.0f) cf[i].H = 0.0f; + float sang = sin(ang), cang = cos(ang); + if (fabs(cang) > fabs(sang)) { + x1[i] = (cang > 0) ? CW : 0; + y1[i] = cch+cch*sang*SR2; + } else { + y1[i] = (sang > 0) ? CH : 0; + x1[i] = ccw+ccw*cang*SR2; + } + ang += OFF; + } + for (int i = 0; i < segs; ++i) { + x2[i] = x1[(i+1)%segs]; + y2[i] = y1[(i+1)%segs]; + } + + //Draw the triangles + can.pauseDrawing(); + for (int i = 0; i < segs; drawn[i++] = false); + for (int i = 0; i < segs; ++i) { + int next = -1; + float bdist = 999999; + //Draw the triangles closest to the mouse first (lazy depth test) + for (int j = 0; j < segs; ++j) { + if (drawn[j]) + continue; + float d = dist(mx,my,x1[j],y1[j]) + dist(mx,my,x2[j],y2[j]); + if (d < bdist) { + bdist = d; + next = j; + } + } + if (next >= 0) { + can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); + drawn[next] = true; + } + } + can.resumeDrawing(); + can.sleep(); + } + + //Clean up + delete [] x1; delete [] y1; + delete [] x2; delete [] y2; + delete [] drawn; delete [] cf; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : -1; + int h = (argc > 2) ? atoi(argv[2]) : w; + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs()*2; + Canvas c(-1, -1, w, h, "Aura", BLACK); + c.run(auraFunction,t); +} diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile new file mode 100644 index 000000000..9389a941a --- /dev/null +++ b/src/tests/testBackground/Makefile @@ -0,0 +1,63 @@ +# Makefile for testBackground + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBackground + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBackground/testBackground.cpp b/src/tests/testBackground/testBackground.cpp new file mode 100644 index 000000000..58d1362bf --- /dev/null +++ b/src/tests/testBackground/testBackground.cpp @@ -0,0 +1,70 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include +#include + +using namespace tsgl; + +void backgroundFunction(Canvas& can) { + Background * bg = can.getBackground(); + Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); + float x = 0; + + can.bindToButton(TSGL_LEFT, TSGL_PRESS, [&cube]() { + cube->changeXBy(-10); + }); + + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeXBy(10); + }); + + can.bindToButton(TSGL_UP, TSGL_PRESS, [&cube]() { + cube->changeYBy(10); + }); + + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&cube]() { + cube->changeYBy(-10); + }); + + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&cube]() { + cube->changeZBy(-50); + }); + + can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeZBy(50); + }); + + // bg->drawSquare(0,0,0,200,0,0,0,RED); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&bg, &can]() { + bg->setClearColor(Colors::randomColor()); + // can.setBackgroundColor(Colors::randomColor()); + bg->clear(); + // can.clearBackground(); + // printf("%f, %f, %f, %f\n", can.getBackgroundColor().R, can.getBackgroundColor().G, can.getBackgroundColor().B, can.getBackgroundColor().A); + // printf("%f, %f, %f, %f\n", bg->getClearColor().R, bg->getClearColor().G, bg->getClearColor().B, bg->getClearColor().A); + }); + + can.add(cube); + while (can.isOpen()) { + can.sleep(); + // bg->clear(); + x = 200 * sin( (float) can.getFrameNumber()/90); + bg->drawSquare(x,0,0,200,0,0,0,RED, true); + // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); + } + delete cube; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Background", BLUE); + c.run(backgroundFunction); +} \ No newline at end of file diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile new file mode 100644 index 000000000..a41f766fc --- /dev/null +++ b/src/tests/testBlurImage/Makefile @@ -0,0 +1,63 @@ +# Makefile for testBlurImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBlurImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBlurImage/testBlurImage.cpp b/src/tests/testBlurImage/testBlurImage.cpp new file mode 100644 index 000000000..005d6399d --- /dev/null +++ b/src/tests/testBlurImage/testBlurImage.cpp @@ -0,0 +1,62 @@ +/* + * testBlurImage.cpp + * + * Usage: ./testBlurImage + */ + +#include +#include + +using namespace tsgl; + +int depthtest(int xmin, int ymin, int xmax, int ymax) { + int xd = 0, yd = 0; + for (float d = xmax-xmin; d > 1; d=ceil(d/2), ++xd); + for (float d = ymax-ymin; d > 1; d=ceil(d/2), ++yd); + return ((xd > yd) ? xd : yd); +} + +bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { + if (xmin > xmax || ymin > ymax) + return false; + if (depth > 0) { + int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; + blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); + blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); + blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); + blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); + return false; + } + ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); + ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); + for (int j = ymin; j <= ymax; ++j) + for (int i = xmin; i <= xmax; ++i) + can.drawPoint(i,j,Colors::blend(top,bot)); + return true; +} + +void blurImageFunction(Canvas& can, std::string fpath, int threads) { + int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + int side = sqrt(threads); //Square root of the number of threads, rounded down + can.drawImage(fpath, 0, 0, cww, cwh); + can.sleepFor(0.5f); + #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square + { + side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads + int tid = omp_get_thread_num(); + int ndrawn = 0, xblock = cww/side, yblock = cwh/side; + int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; + int xmax = xmin+xblock; clamp(xmax,0,cww-1); + int ymax = ymin+yblock; clamp(ymax,0,cwh-1); + int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); + for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); + } +} + +int main(int argc, char* argv[]) { + int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; + TextureHandler::getDimensions(fname,w,h); + Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); + c.run(blurImageFunction,fname,t); +} diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile new file mode 100644 index 000000000..4d79e6724 --- /dev/null +++ b/src/tests/testCalcPi/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCalcPi + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCalcPi + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCalcPi/testCalcPi.cpp b/src/tests/testCalcPi/testCalcPi.cpp new file mode 100644 index 000000000..6a3a6074c --- /dev/null +++ b/src/tests/testCalcPi/testCalcPi.cpp @@ -0,0 +1,76 @@ +/* + * testCalcPi.cpp + * + * Usage: ./testCalcPi + */ + +#include // printf(), ... +#include // stoll(), ... +#include // exit() +#include // OpenMP functions +#include // IntegralViewer + +using namespace tsgl; + +/*! + * \brief Compute a y-coordinate. + * \details Takes in an x-coordinate and calculates its corresponding y-coordinate. + * The IntegralViewer class then plots that point. + * \param x The x-coordinate to calculate the y-coordinate for. + * \return The calculated y-coordinate for the passed x value. + * \see IntegralViewer class. + */ +inline Decimal unitCircleFunction(Decimal x) { + return (fabs(x) < 1.0L) ? sqrt( 1.0L - (x*x) ) : 0.0L; +} + +/*! + * \brief Computes the Cosine value for an x-coordinate. + * \param x The x value to calculate the Cosine value for. + * \return The Cosine value for the passed x value. + */ +inline Decimal sineFunction(Decimal x) { + return cos(8*x); +} + +/*! + * \brief testCalcPi's main method. + * \details Everything that is needed in order to run testCalcPi is in this main method. + * - Handle command-line arguments that were passed. If more than 2 were passed, print an error message and + * exit the process. + * - Now, check and see if any command-line arguments were passed at all. If not, set default values + * for the number of intervals and the number of threads to use. + * - Setup the IntegralViewer object; set the number of threads to use and create the IntergralViewer + * object with the information given and calculated. + * - Evaluate the integral of the unit circle function using rectangles, then evaluate it using trapezoids. + * - Now evaluate the Cosine function integral using rectangles and trapezoids. + * . + */ +int main(int argc, char** argv) { + //Handle command line + if (argc > 3) { + fprintf(stderr, "\nUsage: calcPI2 [intervals] [numThreads]\n\n"); + exit(1); + } + + //Check if the number of intervals and the number of threads was passed + //If one was not, set it to a default value + long long numIntervals = (argc > 1) ? std::stoll(argv[1], 0, 10) : 1; + unsigned numThreads = (argc > 2) ? std::stoll(argv[2], 0, 10) : 1; + + //Setup + omp_set_num_threads(numThreads); + IntegralViewer i1(&unitCircleFunction, 800, 800, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); + + //Go! + printf("Reference pi: 3.141592653589793238462643383279...)\n"); + long double rectanglesPi = i1.rectangleEvaluate(numIntervals) * 4.0; + printf("Rectangles pi: %32.30Lf in %f secs\n", rectanglesPi, i1.getRecTime() ); + long double trapezoidsPi = i1.trapezoidEvaluate(numIntervals) * 4.0; + printf("Trapezoids pi: %32.30Lf in %f secs\n", trapezoidsPi, i1.getTrapTime() ); + + //Bonus! + IntegralViewer i2(&sineFunction, 1200, 800, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); + i2.rectangleEvaluate(numIntervals); + i2.trapezoidEvaluate(numIntervals); +} diff --git a/src/tests/testCircle/testCircle.cpp b/src/tests/testCircle/testCircle.cpp index 3017ff708..e1740776d 100644 --- a/src/tests/testCircle/testCircle.cpp +++ b/src/tests/testCircle/testCircle.cpp @@ -62,7 +62,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Basic Circle"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "Basic Circle", BLACK); c.run(circleFunction); } \ No newline at end of file diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile new file mode 100644 index 000000000..5fbc43185 --- /dev/null +++ b/src/tests/testColorWheel/Makefile @@ -0,0 +1,63 @@ +# Makefile for testColorWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testColorWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testColorWheel/testColorWheel.cpp b/src/tests/testColorWheel/testColorWheel.cpp new file mode 100644 index 000000000..3a7404d33 --- /dev/null +++ b/src/tests/testColorWheel/testColorWheel.cpp @@ -0,0 +1,75 @@ +/* + * testColorWheel.cpp + * + * Usage: ./testColorWheel + */ + +#include +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/*! + * \brief Draws a gradient color wheel using OMP with multiple threads per processor and private per-thread variables. + * \details + * - \b THREADS is set to a number greater than the number of physical processors. + * - The center of the canvas is computed and stored. + * - The radius of the wheel is computed (using the minimum of the Canvas width / height) and stored. + * - The size of the \b GRADIENT is computed and stored. + * - Variables for the second and third vertices of a triangle and the current shading are initialized. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - The predetermined number of parallel threads is forked off using OMP, pulling along the coordinate + * and shading variables. + * - The actual number of threads is stored in: \b nthreads. + * - A color \b delta is computed. + * - Each thread's thread id ( \b tid ) is stored. + * - Each thread's shading is computed using it's id and \b nthreads. + * - While the Canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - Each thread's \b start is computed using the timer's lifetime and it's current id. + * - The second and third coordinates of a triangle approximating an arc of a circle are + * computed using the \b GRADIENT and the thread's \b start position. + * - A triangle is drawn on the Canvas for each thread, with the first vertex in the center, and + * the second and third vertices as computed above, with a hue based on the precomputed \b start, + * full saturation, and a value of \b shading. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void colorWheelFunction(Canvas& can, int threads) { + const int CW = can.getWindowWidth() / 2, // Half the window's width + CH = can.getWindowHeight() / 2; // Half the window's height + const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel + GRADIENT = 2 * PI / NUM_COLORS; // Gap between wedges + #pragma omp parallel num_threads(threads) + { + float x2, x3, y2, y3, shading; + int tid = omp_get_thread_num(); + int delta = tid * NUM_COLORS / threads; // Distance between threads to compute + shading = 1 - (float) tid / threads; + while (can.isOpen()) { + can.sleep(); + int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; + x2 = CW + RADIUS * sin(GRADIENT * start); + y2 = CH + RADIUS * cos(GRADIENT * start); + x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); + y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); + can.drawTriangle(CW, CH, x2, y2, x3, y3, + ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); + } + } +} + + +//Takes command line arguments for the height and width of the window +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : 64; + Canvas c(-1, -1, w, h, "Color Wheel"); + c.run(colorWheelFunction,t); +} diff --git a/src/tests/testConcavePolygon/testConcavePolygon.cpp b/src/tests/testConcavePolygon/testConcavePolygon.cpp index 547c07364..00cf81104 100644 --- a/src/tests/testConcavePolygon/testConcavePolygon.cpp +++ b/src/tests/testConcavePolygon/testConcavePolygon.cpp @@ -86,7 +86,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Concave Polygons"); - c.setBackgroundColor(WHITE); + Canvas c(-1, -1, w, h, "Concave Polygons", WHITE); c.run(concavePolygonFunction); } diff --git a/src/tests/testCone/testCone.cpp b/src/tests/testCone/testCone.cpp index bcb7f9cab..951d05b18 100644 --- a/src/tests/testCone/testCone.cpp +++ b/src/tests/testCone/testCone.cpp @@ -83,7 +83,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cone"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Cone", BLACK); c.run(coneFunction); } \ No newline at end of file diff --git a/src/tests/testConstructors/Makefile b/src/tests/testConstructors/Makefile new file mode 100644 index 000000000..c01fe882d --- /dev/null +++ b/src/tests/testConstructors/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConstructors + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConstructors + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConstructors/testConstructors.cpp b/src/tests/testConstructors/testConstructors.cpp new file mode 100644 index 000000000..062fa79e5 --- /dev/null +++ b/src/tests/testConstructors/testConstructors.cpp @@ -0,0 +1,304 @@ +/* + * testConcavePolygon.cpp + * + * Usage: ./testConcavePolygon + */ + +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/** + * \brief Draw Concave polygons, which have one or more interior angles > 180 + * \note See http://www.mathopenref.com/polygonconcave.html + * \details + * - Initialize a constant \b PSIZE. + * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. + * - Create an empty array of colors of size \b PSIZE and fill it with random colors. + * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). + * - Fill the other arrays of integers, \b xx and \b yy, with specific values. + * - While the Canvas is open: + * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. + * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. + * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void constructorFunction(Canvas& can) { + // srand(time(NULL)); + const int PSIZE = 50; + + ColorFloat fillColor[PSIZE]; + ColorFloat outlineColor[PSIZE]; + for (unsigned i = 0; i < PSIZE; ++i) { + fillColor[i] = Colors::randomColor(1.0f); + outlineColor[i] = Colors::randomColor(1.0f); + } + + can.drawRectangle(15, 5, 70, 95, fillColor[0], true); + can.drawRectangle(115, 5, 70, 95, fillColor[0], false); + can.drawRectangle(215, 5, 70, 95, fillColor, true); + can.drawRectangle(315, 5, 70, 95, fillColor, false); + + can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); + can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); + can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); + can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); + + can.drawSquare(5, 105, 90, fillColor[0], true); + can.drawSquare(105, 105, 90, fillColor[0], false); + can.drawSquare(205, 105, 90, fillColor, true); + can.drawSquare(305, 105, 90, fillColor, false); + + can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); + can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); + can.drawSquare(605, 105, 90, fillColor[0], outlineColor); + can.drawSquare(705, 105, 90, fillColor, outlineColor); + + can.drawStar(50, 250, 45, 6, fillColor[0], true, false); + can.drawStar(150, 250, 45, 6, fillColor[0], false, true); + can.drawStar(250, 250, 45, 6, fillColor, true, false); + can.drawStar(350, 250, 45, 6, fillColor, false, true); + + can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); + can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); + can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); + can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); + + can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); + can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); + can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); + can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); + + can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); + can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); + can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); + can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); + + can.drawEllipse(50, 450, 35, 45, fillColor[0], true); + can.drawEllipse(150, 450, 35, 45, fillColor[0], false); + can.drawEllipse(250, 450, 35, 45, fillColor, true); + can.drawEllipse(350, 450, 35, 45, fillColor, false); + + can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); + can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); + can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); + can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); + + can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); + can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); + can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); + can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); + + can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); + can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); + can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); + can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); + + can.drawCircle(50, 650, 45, fillColor[0], true); + can.drawCircle(150, 650, 45, fillColor[0], false); + can.drawCircle(250, 650, 45, fillColor, true); + can.drawCircle(350, 650, 45, fillColor, false); + + can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); + can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); + can.drawCircle(650, 650, 45, fillColor[0], outlineColor); + can.drawCircle(750, 650, 45, fillColor, outlineColor); + + int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; + + x1[0] = x1[1] = 5; + x1[2] = 50; + x1[3] = x1[4] = 95; + + x2[0] = x2[1] = 105; + x2[2] = 150; + x2[3] = x2[4] = 195; + + x3[0] = x3[1] = 205; + x3[2] = 250; + x3[3] = x3[4] = 295; + + x4[0] = x4[1] = 305; + x4[2] = 350; + x4[3] = x4[4] = 395; + + x5[0] = x5[1] = 405; + x5[2] = 450; + x5[3] = x5[4] = 495; + + x6[0] = x6[1] = 505; + x6[2] = 550; + x6[3] = x6[4] = 595; + + x7[0] = x7[1] = 605; + x7[2] = 650; + x7[3] = x7[4] = 695; + + x8[0] = x8[1] = 705; + x8[2] = 750; + x8[3] = x8[4] = 795; + + y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; + y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; + y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; + y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; + y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; + + can.drawTriangleStrip(5, x1, y1, fillColor[0], true); + can.drawTriangleStrip(5, x2, y2, fillColor[0], false); + can.drawTriangleStrip(5, x3, y3, fillColor, true); + can.drawTriangleStrip(5, x4, y4, fillColor, false); + + can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); + can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); + can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); + can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); + + int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], + y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; + + x9[0] = x9[1] = 5; + x9[2] = x9[5] = 50; + x9[3] = x9[4] = 95; + + x10[0] = x10[1] = 105; + x10[2] = x10[5] = 150; + x10[3] = x10[4] = 195; + + x11[0] = x11[1] = 205; + x11[2] = x11[5] = 250; + x11[3] = x11[4] = 295; + + x12[0] = x12[1] = 305; + x12[2] = x12[5] = 350; + x12[3] = x12[4] = 395; + + x13[0] = x13[1] = 405; + x13[2] = x13[5] = 450; + x13[3] = x13[4] = 495; + + x14[0] = x14[1] = 505; + x14[2] = x14[5] = 550; + x14[3] = x14[4] = 595; + + x15[0] = x15[1] = 605; + x15[2] = x15[5] = 650; + x15[3] = x15[4] = 695; + + x16[0] = x16[1] = 705; + x16[2] = x16[5] = 750; + x16[3] = x16[4] = 795; + + y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; + y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; + y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; + y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; + y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; + y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; + + can.drawConvexPolygon(6, x9, y9, fillColor[0], true); + can.drawConvexPolygon(6, x10, y10, fillColor[0], false); + can.drawConvexPolygon(6, x11, y11, fillColor, true); + can.drawConvexPolygon(6, x12, y12, fillColor, false); + + can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); + can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); + can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); + can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); + + int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], + y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; + + x17[0] = x17[1] = 5; + x17[2] = x17[5] = 50; + x17[3] = x17[4] = 95; + + x18[0] = x18[1] = 105; + x18[2] = x18[5] = 150; + x18[3] = x18[4] = 195; + + x19[0] = x19[1] = 205; + x19[2] = x19[5] = 250; + x19[3] = x19[4] = 295; + + x20[0] = x20[1] = 305; + x20[2] = x20[5] = 350; + x20[3] = x20[4] = 395; + + x21[0] = x21[1] = 405; + x21[2] = x21[5] = 450; + x21[3] = x21[4] = 495; + + x22[0] = x22[1] = 505; + x22[2] = x22[5] = 550; + x22[3] = x22[4] = 595; + + x23[0] = x23[1] = 605; + x23[2] = x23[5] = 650; + x23[3] = x23[4] = 695; + + x24[0] = x24[1] = 705; + x24[2] = x24[5] = 750; + x24[3] = x24[4] = 795; + + y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; + y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; + y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; + y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; + y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; + y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; + + can.drawConcavePolygon(6, x17, y17, fillColor[0], true); + can.drawConcavePolygon(6, x18, y18, fillColor[0], true); + can.drawConcavePolygon(6, x19, y19, fillColor, true); + can.drawConcavePolygon(6, x20, y20, fillColor, true); + + can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); + can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); + can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); + can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); + + can.drawArrow(805, 5, 895, 95, fillColor[3], true); + can.drawArrow(805, 105, 895, 195, fillColor, true); + + can.drawLine(805, 205, 895, 295, fillColor[3]); + can.drawLine(805, 305, 895, 395, fillColor); + + int x25[5], x26[5], y25[5], y26[5]; + + x25[0] = x26[0] = 820; + x25[1] = x26[1] = 805; + x25[2] = x26[2] = 880; + x25[3] = x26[3] = 895; + x25[4] = x26[4] = 870; + + y25[0] = 450; + y25[1] = 405; + y25[2] = 420; + y25[3] = 460; + y25[4] = 495; + + y26[0] = 550; + y26[1] = 505; + y26[2] = 520; + y26[3] = 560; + y26[4] = 595; + + can.drawPolyline(5, x25, y25, fillColor[3]); + can.drawPolyline(5, x26, y26, outlineColor); + + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + + } +} + +int main(int argc, char* argv[]) { + int w = 0.9*Canvas::getDisplayHeight(); + int h = w; + Canvas c(-1, -1, w, h, "Constructors", WHITE); + c.run(constructorFunction); +} diff --git a/src/tests/testConvexPolygon/testConvexPolygon.cpp b/src/tests/testConvexPolygon/testConvexPolygon.cpp index 8e7b77932..43174f924 100644 --- a/src/tests/testConvexPolygon/testConvexPolygon.cpp +++ b/src/tests/testConvexPolygon/testConvexPolygon.cpp @@ -52,7 +52,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon", BLACK); c.run(convexPolygonFunction); } \ No newline at end of file diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile new file mode 100644 index 000000000..7190a88d7 --- /dev/null +++ b/src/tests/testCosineIntegral/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCosineIntegral + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCosineIntegral + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCosineIntegral/testCosineIntegral.cpp b/src/tests/testCosineIntegral/testCosineIntegral.cpp new file mode 100644 index 000000000..470c99be9 --- /dev/null +++ b/src/tests/testCosineIntegral/testCosineIntegral.cpp @@ -0,0 +1,84 @@ +/* + * testCosineIntegral.cpp + * + * Usage: ./testCosineIntegral + */ + +#include +#include +#include +#include +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/*! + * \brief Draws the area under a predefined function (the integral) using CartesianCanvas + * and takes a command line argument for the number of threads to use. + * \details + * - Use the number of threads passed via command-line arguments. + * - If that number is negative, just use one thread. + * - Set up the internal timer of the Canvas to expire once every \b FRAME / 2 seconds . + * - Draw axes through the origin, with spacing PI/4 between x ticks and 0.5 between y ticks. + * - Store the width of the canvas's pixel in \b pw to avoid thousands of multiple function calls. + * - Initialize and draw a CosineFunction using the currently rendered area of the CartesianCanvas. + * - Set the CartesianCanvas' font from an external font file using setFont(). + * - Draw some labels on the CartesianCanvas to make things look pretty. + * - Set up a parallel block with OMP using \b threads as the number of threads to use. + * - Set \b nthreads to the actual number of threads spawned. + * - Calculate each thread's share of the work and store it in: \b offset. + * - Calculate each thread's starting position and store it in: \b start. + * - Calculate each thread's stopping position and store it in: \b stop. + * - For each thread, from \b start to \b stop with step size \b pw: + * - If the Canvas was closed, break. + * - Sleep the internal timer until it's ready to render. + * - Draw a line from x,0 to x,f(x) for the current x. + * . + * . + * \param can Reference to the CartesianCanvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void cosineIntegralFunction(Cart& can, int numberOfThreads) { + int threads = numberOfThreads; + if (threads <= 0) { + threads = 1; + } + + can.drawAxes(0, 0, PI/4, .5); + long double pw = can.getPixelWidth(); + CosineFunction function1; + can.drawFunction(function1); + + //\u03C0 = Ï€ + can.setFont("../assets/freefont/FreeSerif.ttf"); + can.drawText(L"-1.5\u03C0", -1.5 * PI - .1, .25, 20); // Note the important capital L, used to support Unicode. + can.drawText(L"1.5\u03C0", 1.5 * PI - .2, .25, 20); + can.drawText(L"1", .1, 1.05, 20); + can.drawText(L"-1", .1, -1.1, 20); + +#pragma omp parallel num_threads(threads) + { + threads = omp_get_num_threads(); + long double offset = 3*PI / threads; + long double start = -1.5*PI + omp_get_thread_num() * offset; + long double stop = start + offset; + for (long double i = start; i < stop; i += pw) { + if (!can.isOpen()) break; + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + can.drawLine(i, 0, i, function1.valueAt(i), Colors::highContrastColor(omp_get_thread_num())); + } + } +} + +//Takes in command line arguments for the width and height of the window +//as well as the number of threads to use +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads to use + Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", WHITE, FRAME / 2); + c.run(cosineIntegralFunction,t); +} diff --git a/src/tests/testCube/testCube.cpp b/src/tests/testCube/testCube.cpp index 44907768b..30b640e4b 100644 --- a/src/tests/testCube/testCube.cpp +++ b/src/tests/testCube/testCube.cpp @@ -32,6 +32,7 @@ void cubeFunction(Canvas& can) { boolean = !boolean; }); + bool ss = false; while (can.isOpen()) { can.sleep(); // testCube->setCenterX(sin(rotation)*200); @@ -58,6 +59,10 @@ void cubeFunction(Canvas& can) { // boolean = !boolean; // rotation = 0; // } + if (can.getFrameNumber() > 50 && !ss) { + can.takeScreenShot(); + ss = true; + } rotation+=0.01; } @@ -70,7 +75,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cube"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Cube", BLACK); c.run(cubeFunction); } \ No newline at end of file diff --git a/src/tests/testCuboid/testCuboid.cpp b/src/tests/testCuboid/testCuboid.cpp index b5893b27a..ac407e5e9 100644 --- a/src/tests/testCuboid/testCuboid.cpp +++ b/src/tests/testCuboid/testCuboid.cpp @@ -80,7 +80,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cuboid"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Cuboid", BLACK); c.run(cuboidFunction); } \ No newline at end of file diff --git a/src/tests/testCylinder/testCylinder.cpp b/src/tests/testCylinder/testCylinder.cpp index 6e8075e45..8df38a692 100644 --- a/src/tests/testCylinder/testCylinder.cpp +++ b/src/tests/testCylinder/testCylinder.cpp @@ -70,7 +70,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cylinder"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); c.run(cylinderFunction); } \ No newline at end of file diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile new file mode 100644 index 000000000..eef80cbac --- /dev/null +++ b/src/tests/testDice/Makefile @@ -0,0 +1,63 @@ +# Makefile for testDice + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDice + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDice/testDice.cpp b/src/tests/testDice/testDice.cpp new file mode 100644 index 000000000..5d674296b --- /dev/null +++ b/src/tests/testDice/testDice.cpp @@ -0,0 +1,179 @@ +/* + * testDice.cpp + * + * Usage: ./testDice + * Note: currently has some interesting rotation issues that mean that the + * API will probably have to be updated. Not compiling since it won't + * really work, alter the Makefile to understand the issue. Has to do with composite + * Euler angles. + */ + +#include +#include + +using namespace tsgl; + +void diceFunction(Canvas& can) { + Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); + can.add(die); + + RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); + can.add(spot1); + spot1->setRotationPoint(0,0,0); + + + RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_1->setRotationPoint(0,0,0); + can.add(spot2_1); + RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_2->setRotationPoint(0,0,0); + can.add(spot2_2); + + RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); + spot3_1->setRotationPoint(0,0,0); + can.add(spot3_1); + RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); + spot3_2->setRotationPoint(0,0,0); + can.add(spot3_2); + RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); + spot3_3->setRotationPoint(0,0,0); + can.add(spot3_3); + + // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_1->setRotationPoint(0,0,0); + // can.add(spot4_1); + // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_2->setRotationPoint(0,0,0); + // can.add(spot4_2); + // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_3->setRotationPoint(0,0,0); + // can.add(spot4_3); + // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_4->setRotationPoint(0,0,0); + // can.add(spot4_4); + + RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); + spot5_1->setRotationPoint(0,0,0); + can.add(spot5_1); + RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_2->setRotationPoint(0,0,0); + can.add(spot5_2); + RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_3->setRotationPoint(0,0,0); + can.add(spot5_3); + RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_4->setRotationPoint(0,0,0); + can.add(spot5_4); + RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_5->setRotationPoint(0,0,0); + can.add(spot5_5); + + RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_1); + RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_2); + RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_3); + RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_4); + RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_5); + RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_6); + spot6_1->setRotationPoint(0,0,0); + spot6_2->setRotationPoint(0,0,0); + spot6_3->setRotationPoint(0,0,0); + spot6_4->setRotationPoint(0,0,0); + spot6_5->setRotationPoint(0,0,0); + spot6_6->setRotationPoint(0,0,0); + + // die->setRoll(45); + // spot1->setRoll(45); + // spot2_1->setRoll(45-90); + // spot2_2->setRoll(45-90); + // spot3_1->setRoll(180); + // spot3_2->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot4_1->setRoll(45); + // spot4_2->setRoll(45); + // spot4_3->setRoll(45); + // spot4_4->setRoll(45); + // spot5_1->setRoll(45+90); + // spot5_2->setRoll(45+90); + // spot5_3->setRoll(45+90); + // spot5_4->setRoll(45+90); + // spot5_5->setRoll(45+90); + // spot6_1->setRoll(45+180); + // spot6_2->setRoll(45+180); + // spot6_3->setRoll(45+180); + // spot6_4->setRoll(45+180); + // spot6_5->setRoll(45+180); + // spot6_6->setRoll(45+180); + + float rotation = 0; + while (can.isOpen()) { + can.sleep(); + // die->setRoll(rotation); + // spot1->setRoll(rotation); + // spot2_1->setRoll(rotation-90); + // spot2_2->setRoll(rotation-90); + // spot3_1->setPitch(rotation); + // spot3_2->setPitch(rotation); + // spot3_3->setPitch(rotation); + // spot4_1->setRoll(rotation); + // spot4_2->setRoll(rotation); + // spot4_3->setRoll(rotation); + // spot4_4->setRoll(rotation); + // spot5_1->setRoll(rotation+90); + // spot5_2->setRoll(rotation+90); + // spot5_3->setRoll(rotation+90); + // spot5_4->setRoll(rotation+90); + // spot5_5->setRoll(rotation+90); + // spot6_1->setRoll(rotation+180); + // spot6_2->setRoll(rotation+180); + // spot6_3->setRoll(rotation+180); + // spot6_4->setRoll(rotation+180); + // spot6_5->setRoll(rotation+180); + // spot6_6->setRoll(rotation+180); + + die->setPitch(rotation); + spot1->setPitch(rotation); + spot2_1->setPitch(rotation); + spot2_2->setPitch(rotation); + spot3_1->setPitch(rotation-90); + spot3_2->setPitch(rotation-90); + spot3_3->setPitch(rotation-90); + // spot4_1->setPitch(rotation+90); + // spot4_2->setPitch(rotation+90); + // spot4_3->setPitch(rotation+90); + // spot4_4->setPitch(rotation+90); + spot5_1->setPitch(rotation); + spot5_2->setPitch(rotation); + spot5_3->setPitch(rotation); + spot5_4->setPitch(rotation); + spot5_5->setPitch(rotation); + spot6_1->setPitch(rotation); + spot6_2->setPitch(rotation); + spot6_3->setPitch(rotation); + spot6_4->setPitch(rotation); + spot6_5->setPitch(rotation); + spot6_6->setPitch(rotation); + rotation += 1; + } + + delete die; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Dice Rolling"); + c.run(diceFunction); +} \ No newline at end of file diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile new file mode 100644 index 000000000..1b880fb14 --- /dev/null +++ b/src/tests/testDiorama/Makefile @@ -0,0 +1,63 @@ +# Makefile for testDiorama + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDiorama + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDiorama/testDiorama.cpp b/src/tests/testDiorama/testDiorama.cpp new file mode 100644 index 000000000..82214f2f6 --- /dev/null +++ b/src/tests/testDiorama/testDiorama.cpp @@ -0,0 +1,118 @@ +/* + * testDiorama.cpp + * + * Usage: ./testDiorama + */ + +#include +#include + +using namespace tsgl; + +void dioramaFunction(Canvas& can) { + Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); + // can.add(blankCanvas); + + Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaLeft); + Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaRight); + Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaTop); + Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaBottom); + + Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunk); + + Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); + // can.add(leaves); + + Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunkFlat); + + Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); + // can.add(leavesFlat); + + float counter = 0; + while (can.isOpen()) { + // can.sleepFor(0.5); + can.sleep(); + if (can.getFrameNumber() > 700 && counter < 1) { + can.add(blankCanvas); + counter++; + } + if(can.getFrameNumber() > 1700 && counter < 2) { + can.add(trunkFlat); + counter++; + } + if(can.getFrameNumber() > 1800 && counter < 3) { + can.add(leavesFlat); + counter++; + } + if(can.getFrameNumber() > 2300 && counter < 4) { + can.add(emptyDioramaLeft); + can.add(emptyDioramaRight); + can.add(emptyDioramaTop); + can.add(emptyDioramaBottom); + counter++; + } + if(can.getFrameNumber() > 3500 && counter < 5) { + can.add(trunk); + counter++; + } + if(can.getFrameNumber() > 3600 && counter < 6) { + can.add(leaves); + counter++; + } + if(can.getFrameNumber() > 4000 && counter < 7) { + if(emptyDioramaLeft->getWidth() > 15) { + emptyDioramaLeft->changeWidthBy(-270/20); + emptyDioramaRight->changeWidthBy(-270/20); + emptyDioramaTop->changeHeightBy(-270/20); + emptyDioramaBottom->changeHeightBy(-270/20); + emptyDioramaTop->changeZBy(135/20); + emptyDioramaBottom->changeZBy(135/20); + emptyDioramaLeft->changeZBy(135/20); + emptyDioramaRight->changeZBy(135/20); + trunk->changeLengthBy(-25/20); + trunk->changeZBy(135/20); + leaves->changeZRadiusBy(-40/20); + leaves->changeZBy(135/20); + } else { + emptyDioramaLeft->setWidth(1); + emptyDioramaRight->setWidth(1); + emptyDioramaTop->setHeight(1); + emptyDioramaBottom->setHeight(1); + emptyDioramaTop->setCenterZ(135); + emptyDioramaBottom->setCenterZ(135); + emptyDioramaLeft->setCenterZ(135); + emptyDioramaRight->setCenterZ(135); + trunk->setLength(1); + trunk->setCenterZ(135); + leaves->setZRadius(1); + leaves->setCenterZ(135); + counter++; + } + } + } + + delete blankCanvas; + delete emptyDioramaLeft; + delete emptyDioramaRight; + delete emptyDioramaTop; + delete emptyDioramaBottom; + delete leaves; + delete trunkFlat; + delete leavesFlat; + +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting", WHITE); + c.run(dioramaFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipse/testEllipse.cpp b/src/tests/testEllipse/testEllipse.cpp index b64990098..dacee93d4 100644 --- a/src/tests/testEllipse/testEllipse.cpp +++ b/src/tests/testEllipse/testEllipse.cpp @@ -66,7 +66,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipse"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Ellipse", BLACK); c.run(ellipseFunction); } \ No newline at end of file diff --git a/src/tests/testEllipsoid/testEllipsoid.cpp b/src/tests/testEllipsoid/testEllipsoid.cpp index d317b523d..69d279ebb 100644 --- a/src/tests/testEllipsoid/testEllipsoid.cpp +++ b/src/tests/testEllipsoid/testEllipsoid.cpp @@ -107,7 +107,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid", BLACK); c.run(ellipsoidFunction); } \ No newline at end of file diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile new file mode 100644 index 000000000..94991da39 --- /dev/null +++ b/src/tests/testFunction/Makefile @@ -0,0 +1,63 @@ +# Makefile for testFunction + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testFunction + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testFunction/testFunction.cpp b/src/tests/testFunction/testFunction.cpp new file mode 100644 index 000000000..a3511f8e6 --- /dev/null +++ b/src/tests/testFunction/testFunction.cpp @@ -0,0 +1,51 @@ +/* + * testFunction.cpp + * + * Usage: ./testFunction + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws the outputs of some functions using CartesianCanvas. + * \details + * - Draw axes through the origin, with spacing 1.0 between x ticks and 5.0 between y ticks. + * - Initialize a CosineFunction, and draw it using the currently rendered area of the CartesianCanvas. + * - Initialize a PowerFunction with argument 2 (square), and draw it using + * the currently rendered area of the CartesianCanvas. + * - Declare a new function that computes some bizarre polynomial. + * - Initialize the new function, and draw it using the currently rendered area of the CartesianCanvas. + * . + * \param can Reference to the CartesianCanvas being drawn to. + */ +void functionFunction(CartesianCanvas& can) { + can.drawAxes(0, 0, 1, 5); + + CosineFunction function1; + can.drawFunction(function1,FRAME/5); + + PowerFunction function2(2); + can.drawFunction(function2,FRAME/5); + + class myFunction : public Function { + public: + long double valueAt(long double x) const { + return 5 * pow(x, 4) + 2 * pow(x, 3) + x + 15; + } + }; + + myFunction function3; + can.drawFunction(function3,FRAME/5); +} + +//Takes command line arguments for the window width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 1000; //If not, set the width and height to a default value + Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting", WHITE); + c.run(functionFunction); +} diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile new file mode 100644 index 000000000..072c3514f --- /dev/null +++ b/src/tests/testGetPixels/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAlphaRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAlphaRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGetPixels/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp new file mode 100644 index 000000000..a3b2e55e9 --- /dev/null +++ b/src/tests/testGetPixels/testGetPixels.cpp @@ -0,0 +1,62 @@ +/* + * testGetPixels.cpp + * + * Usage: ./testGetPixels + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Grabs the pixels from an image on the Canvas and plays with them. + * \details + * - Set a predetermined number of threads and store it in: \b THREADS. + * - Store the Canvas' dimensions for easy use. + * - Draw an image on the initially blank Canvas, stretched to fill it. + * - Set up a parallel OMP block with \b THREADS threads. + * - Set up the internal timer of the Canvas to expire every 1/100th of a second. + * - Determine a block size for each thread based on the Canvas' height and the number + * of spawned threads. + * - Determine a starting row for each thread based on \b blocksize and the thread's id. + * - While the Canvas is open: + * - For each row: + * - For each column: + * - Over each old pixel, draw a new pixel with each of the RGB components incremented + * and wrapped. + * . + * . + * - Sleep until the Canvas is ready to draw again. + * - Print the time between sleeps of the Canvas' internal timer. + * . + * . + * + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void getPixelsFunction(Canvas& can, int threads) { + unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); + can.drawImage("../assets/pics/test.png", 0, 0, width, height); + can.sleepFor(0.5f); + #pragma omp parallel num_threads(threads) + { + unsigned blocksize = (double)height / omp_get_num_threads(); + unsigned row = blocksize * omp_get_thread_num(); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (unsigned y = row; y < row + blocksize; y++) { + for (unsigned x = 0; x < width; x++) { + ColorInt c = can.getPoint(x,y); + can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); + } + } + } + } +} + +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + Canvas c(-1, -1, 800, 600, "Pixel Shifter", .01); + c.run(getPixelsFunction,t); +} diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile new file mode 100644 index 000000000..cdc77e86f --- /dev/null +++ b/src/tests/testGradientWheel/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGradientWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGradientWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGradientWheel/testGradientWheel.cpp b/src/tests/testGradientWheel/testGradientWheel.cpp new file mode 100644 index 000000000..9e590ab01 --- /dev/null +++ b/src/tests/testGradientWheel/testGradientWheel.cpp @@ -0,0 +1,65 @@ +/* + * testGradientWheel.cpp + * + * Usage: ./testGradientWheel + */ + +#include +#include +#include "Util.h" + +using namespace tsgl; + +/*! + * \brief Draws a gradient color wheel using OMP with multiple threads per processor and TSGL's colored polygons. + * \details Same principle as colorWheelFunction(). Since colored polygons take arrays as parameters + * to allow for arbitrary-length polygons, there are some key differences: + * - Colors, x and y coordinates are declared within the \#pragma omp block so they can be + * declared as an array. + * - At the end, drawColoredPolygon() is called on a polygon with 3 vertices, with arrays for the + * x coordinates, y coordinates, and color. + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void gradientWheelFunction(Canvas& can, int threads) { + const int CW = can.getWindowWidth() / 2, // Half the window's width + CH = can.getWindowHeight() / 2; // Half the window's height + const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel + ARCLENGTH = 2 * PI / NUM_COLORS; // Gap between wedges + #pragma omp parallel num_threads(threads) + { + threads = omp_get_num_threads(); // Actual number of threads + int tid = omp_get_thread_num(); // Thread ID + int delta = (NUM_COLORS / threads); // Distance between threads to compute + float shading = 1 - (float)tid / threads; // Shading based on thread ID + ColorFloat color[3]; // RGB color to build + int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices + while (can.isOpen()) { + can.sleep(); + start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment + end = ((start+delta) % NUM_COLORS); + color[0] = ColorHSV(start / (float)NUM_COLORS * 6, 0.0f, shading, 1.0f); + color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); + color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); + + xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen + xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle + yy[1] = CH + RADIUS * cos(ARCLENGTH * start); + xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); + yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); + + can.drawTriangleStrip(3, xx, yy, color, true); + } + } +} + +//Takes command line arguments for the width and height of the window +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid + w = h = 960; // If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : 256; + Canvas c(-1, -1, w, h, "Gradient Color Wheel", BLACK); + c.run(gradientWheelFunction,t); +} diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile new file mode 100644 index 000000000..72b5e97cf --- /dev/null +++ b/src/tests/testGraydient/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGraydient + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGraydient + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGraydient/testGraydient.cpp b/src/tests/testGraydient/testGraydient.cpp new file mode 100644 index 000000000..4d3a2af77 --- /dev/null +++ b/src/tests/testGraydient/testGraydient.cpp @@ -0,0 +1,52 @@ +/* + * testGraydient.cpp + * + * Usage: ./testGraydient + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command-line argument for the + * number of threads to use. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed as a command-line argument. + * - The outer for loop is set up in a striping pattern, and the inner for loop runs from 0 to the Canvas height. + * - If the Canvas is not open anymore, break out of the function. + * - The color ( \b color ) is set to a shade of gray based on its distance from the top left of the canvas. + * - The point is drawn to the Canvas. + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void graydientFunction(Canvas& can, int threads) { + #pragma omp parallel num_threads(threads) + { + for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { + if (!can.isOpen()) break; + for (int j = 0; j < can.getWindowHeight(); j++) { + int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); + can.drawPoint(i, j, ColorInt(color, color, color)); + } + can.sleep(); + } + } +} + +//Takes in the window width and height as command-line arguments for the Canvas +//as well as for the number of threads to use +//( see http://www.cplusplus.com/articles/DEN36Up4/ ) +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid + w = h = 960; // If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Black-white Gradient"); + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + c.run(graydientFunction,t); +} diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile new file mode 100644 index 000000000..6ef2c993b --- /dev/null +++ b/src/tests/testGreyscale/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGreyscale + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGreyscale + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGreyscale/testGreyscale.cpp b/src/tests/testGreyscale/testGreyscale.cpp new file mode 100644 index 000000000..f62b7cfbc --- /dev/null +++ b/src/tests/testGreyscale/testGreyscale.cpp @@ -0,0 +1,86 @@ +/* + * testGreyScale.cpp + * + * Usage: ./testGreyScale + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Grabs the pixels from an image on the Canvas and converts them to grayscale. + * \details + * - Predetermine the number of threads and line thickness and store them in variables. + * - Check if the passed parameter for the number of threads is valid: + * - If its a negative value, change the sign to be positive. + * - If its greater than 30, assign 30 to the number of threads to use. + * - Else, assign the passed parameter to the number of threads to use. + * . + * - Set up the internal timer of the Canvas to expire every ( \b FRAME * 2 ) seconds. + * - Store the Canvas' dimensions for ease of use. + * - Stretch a fancy image over the Canvas. + * - Tell the internal timer to manually sleep for a quarter of a second (to assure the draw buffer is filled). + * - Initialize a pointer to the Canvas' screen buffer. + * - Set up a parallel OMP block with \b threads threads. + * - Get the actual number of spawned threads and store it in: \b nthreads. + * - Compute the \b blocksize based on the Canvas height and \b nthreads. + * - Compute the current thread's row based on \b blocksize and the thread's id. + * - Generate a nice color based on the thread's id. + * - Set a grayscale color variable to 0. + * - For each row: + * - For each column: + * - Get the pixel color of a point of the Canvas. + * - Set a gray color variable to the average of the RGB components. + * - Draw the grayed point over the old point, and increment the index by one pixel. + * . + * - Break if the Canvas was closed. + * - Sleep until the Canvas is ready to render again. + * . + * - Once a thread is finished grayscaling, draw a box around its rendered area using + * the predetermined high contrast color. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void greyScaleFunction(Canvas& can, int numberOfThreads) { + int threads = numberOfThreads; + clamp(threads,1,30); + const unsigned thickness = 3; + const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); + can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); + can.sleepFor(0.25f); + #pragma omp parallel num_threads(threads) + { + int nthreads = omp_get_num_threads(); + unsigned int blocksize = WH / nthreads; + unsigned int row = blocksize * omp_get_thread_num(); + ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); + for (unsigned int y = row; y < row + blocksize; y++) { + for (unsigned int x = 0; x < WW; x++) { + ColorInt pixelColor = can.getPoint(x, y); + int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; + can.drawPoint(x, y, ColorInt(gray, gray, gray)); + } + if (! can.isOpen()) break; + can.sleep(); + } + for (unsigned int i = 0; i < thickness; i++) { + can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); + // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); + } + } +} + +//Takes command line arguments for the width and height of the window +//as well as for the number of threads to use +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Image Greyscaling"); + int numberOfThreads = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads + c.run(greyScaleFunction,numberOfThreads); +} diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile new file mode 100644 index 000000000..cc93c6633 --- /dev/null +++ b/src/tests/testHighData/Makefile @@ -0,0 +1,63 @@ +# Makefile for testHighData + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testHighData + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testHighData/testHighData.cpp b/src/tests/testHighData/testHighData.cpp new file mode 100644 index 000000000..43ce27f05 --- /dev/null +++ b/src/tests/testHighData/testHighData.cpp @@ -0,0 +1,54 @@ +/* + * testHighData.cpp + * + * Usage: ./testHighData + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a large number of pixels on a Canvas at a high framerate. + * \details Very basic stress test for the Canvas' drawPoint() function. + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - Set Local variables to track the internal timer's repetitions, and the Canvas' dimensions. + * - While the Canvas is open: + * - Set \b reps to the timer's current number of repetitions. + * - Compute the blue component of the current color based on reps. + * - Attempt to draw every pixel with the current 1.0,1.0,blue. + * - Sleep the timer until the Canvas is ready to draw again. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void highData(Canvas& can, unsigned threads) { + const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values + const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); + #pragma omp parallel num_threads(threads) + { + float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); + int offset = (MAX_COLOR*tid)/nthreads; + unsigned bstart = tid*(width/nthreads); + unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; + ColorHSV tcol= Colors::highContrastColor(tid); + while (can.isOpen()) { + tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); + for (unsigned i = bstart; i <= bend; i++) + for (unsigned int j = 0; j < height; j++) + can.drawPoint(i, j, tcol); + can.handleIO(); + } + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = 1.2*Canvas::getDisplayHeight(), h = 0.75*w; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Pixel Drawing Load Test"); + c.run(highData,t); +} diff --git a/src/tests/testImage/testImage.cpp b/src/tests/testImage/testImage.cpp index 117fb772f..3de6187c7 100644 --- a/src/tests/testImage/testImage.cpp +++ b/src/tests/testImage/testImage.cpp @@ -27,7 +27,7 @@ void imageFunction(Canvas& can) { // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); // can.add(image); - Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/test.png", ww,hh, 0,0,0); + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); can.add(image); Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); can.add(image2); @@ -96,6 +96,6 @@ int main(int argc, char * argv[]) { if(w <= 0 || h <= 0) { //Check width and height validity w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; } - Canvas c(-1, -1, w, h ,"Images"); + Canvas c(-1, -1, w, h ,"Images", WHITE); c.run(imageFunction); } diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile new file mode 100644 index 000000000..eddf3e4c3 --- /dev/null +++ b/src/tests/testImageCart/Makefile @@ -0,0 +1,63 @@ +# Makefile for testImageCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImageCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImageCart/testImageCart.cpp b/src/tests/testImageCart/testImageCart.cpp new file mode 100644 index 000000000..a7e4aead0 --- /dev/null +++ b/src/tests/testImageCart/testImageCart.cpp @@ -0,0 +1,37 @@ +/* + * testImageCart.cpp + * + * Usage: ./testImageCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a CartesianCanvas. + * \details Same as imageFunction, but on a CartesianCanvas. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + */ +void imageCartFunction(Cart& can) { + can.drawImage("../assets/pics/test.png", 0, 3, 2, 1.5); + can.drawImage("../assets/pics/ship.bmp", 2, 3, 2, 1.5); // possibly lost + can.drawImage("../assets/pics/shiprgb.bmp", 4, 3, 2, 1.5); // definitely lost + can.drawImage("../assets/pics/sky_main.jpg", 0, 1.5, 2, 1.5); + can.drawImage("../assets/pics/cow.jpg", 2, 1.5, 2, 1.5); + can.drawImage("../assets/pics/colorfulKeyboard.jpg", 4, 1.5, 2, 1.5); + + can.drawImage("../assets/pics/colorful-cars-circle.jpg", 1, 3, 4, 3, 0.25f); //Overlay +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2 * Canvas::getDisplayHeight(); + h = 0.5 * w; + } + Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); + c.run(imageCartFunction); +} diff --git a/src/tests/testInverter/ImageInverter.cpp b/src/tests/testInverter/ImageInverter.cpp new file mode 100644 index 000000000..f559065b1 --- /dev/null +++ b/src/tests/testInverter/ImageInverter.cpp @@ -0,0 +1,56 @@ +/* + * ImageInverter.cpp + */ + +#include "ImageInverter.h" + +ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsigned height) + : myCanvas1(0, 0, width, height, fileName), + myCanvas2(-1, -1, width, height, fileName), + myWidth(width), myHeight(height), myFileName(fileName) +{ + myCanvas1.start(); + myCanvas1.drawImage(fileName, 0, 0, width, height); + // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); + sleep(1); + myCanvas2.start(); +} + +void ImageInverter::run(unsigned numThreads) { + invertImage(numThreads); + stop(); +} + +void ImageInverter::invertImage(unsigned numThreads) { + ColorInt pixelColor; + // #pragma omp parallel for num_threads(numThreads) + const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); + #pragma omp parallel num_threads(numThreads) + { + int nthreads = omp_get_num_threads(); + unsigned int blocksize = WH / nthreads; + unsigned int row = blocksize * omp_get_thread_num(); + for (unsigned int x = row; x < row + blocksize; x++) { + for (unsigned int y = 0; y < WW; y++) { + pixelColor = myCanvas1.getPixel(x, y); + int invertedR = 255 - pixelColor.R; + int invertedG = 255 - pixelColor.G; + int invertedB = 255 - pixelColor.B; + myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); + } + myCanvas1.sleep(); + myCanvas2.sleep(); + } + } +} + +void ImageInverter::stop() { + myCanvas2.wait(); + myCanvas1.wait(); +} + +ImageInverter::~ImageInverter() { +// delete myCanvas1; +// delete myCanvas2; +// std::cout << "ImageInverter terminated normally.\n" << std::endl; +} diff --git a/src/tests/testInverter/ImageInverter.h b/src/tests/testInverter/ImageInverter.h new file mode 100644 index 000000000..6906b31b6 --- /dev/null +++ b/src/tests/testInverter/ImageInverter.h @@ -0,0 +1,79 @@ +/* + * ImageInverter.h declares the ImageInverter class. + */ + +#ifndef IMAGEINVERTER_H_ +#define IMAGEINVERTER_H_ + +#include // Canvas, ColorInt, etc. +#include + +#ifdef _WIN32 + #include +#else + #include // sleep() +#endif + +using namespace tsgl; + +class ImageInverter { +private: + Canvas myCanvas1; + Canvas myCanvas2; + int myWidth; + int myHeight; + std::string myFileName; + #ifdef _WIN32 + void sleep(unsigned seconds) { Sleep(seconds * 1000); } + #endif +protected: + + /* invertImage inverts the image using a given number of threads + * @param: numThreads, the number of threads to use + * when inverting the image (default 1). + * Postcondition: myCanvas2 contains an image that is the + * inverse of the image in myCanvas1. + */ + virtual void invertImage(unsigned numThreads = 1); + + /* helper method to keep Canvases up until the user + * clicks their window-frame's close button. + * + * Postcondition: myCanvas1 and myCanvas2 have been closed. + */ + virtual void stop(); + +public: + + /* explicit constructor + * @param fileName, a string. + * @param width, an unsigned. + * @param height, an unsigned. + * Precondition: fileName contains the name of a valid image file + * && width contains the number of columns in that image + * && height contains the number of rows in the image. + * Postcondition: myCanvas1 contains the image from fileName + * && myCanvas2 is ready for drawing its inverse + * && myWidth = width + * && myHeight = height. + */ + ImageInverter(const std::string& fileName, unsigned width, unsigned height); + + /* destructor + * Postcondition: myCanvas1 and myCanvas2 have been closed + * && myCanvas1 and myCanvas2 have been deallocated + * && glfwTerminate() has shut down GLFW + * && a termination message was written to the console. + */ + virtual ~ImageInverter(); + + /* method to coordinate the image inversion + * @param: numThreads, the number of threads to use + * when inverting the image (default 1). + * PostCondition: myCanvas2 contains the inverse + * of the image in myCanvas1. + */ + virtual void run(unsigned numThreads = 1); +}; + +#endif /* IMAGEINVERTER_H_ */ diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile new file mode 100644 index 000000000..27d4cd03e --- /dev/null +++ b/src/tests/testInverter/Makefile @@ -0,0 +1,63 @@ +# Makefile for testInverter + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testInverter + +# Object files +ODIR = obj +_OBJ = ImageInverter.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testInverter/testInverter.cpp b/src/tests/testInverter/testInverter.cpp new file mode 100644 index 000000000..370b4f62f --- /dev/null +++ b/src/tests/testInverter/testInverter.cpp @@ -0,0 +1,16 @@ +/* + * testInverter.cpp + * + * Usage: ./testInverter + */ + +#include +#include "ImageInverter/ImageInverter.h" + +using namespace tsgl; + +int main(int argc, char* argv[]) { + int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); + ii.run(numThreads); +} diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile new file mode 100644 index 000000000..d5cb2797a --- /dev/null +++ b/src/tests/test_specs/Makefile @@ -0,0 +1,63 @@ +# Makefile for test_specs + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test_specs + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test_specs/test_specs.cpp b/src/tests/test_specs/test_specs.cpp new file mode 100644 index 000000000..367badcb1 --- /dev/null +++ b/src/tests/test_specs/test_specs.cpp @@ -0,0 +1,31 @@ +#include "tsgl.h" + +int main(int argc, char* argv[]) { + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL); + if (!window) { + fprintf(stderr, "GLFW window creation failed."); + exit(100); + } + glfwMakeContextCurrent(window); + const GLubyte* gfxVendor = glGetString(GL_VENDOR); + std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); + + FT_Library flib = NULL; + FT_Init_FreeType(&flib); + FT_Int fmaj = 0, fmin = 0, fpatch = 0; + FT_Library_Version(flib,&fmaj,&fmin,&fpatch); + + printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + printf("GLFW version: %s\n", glfwGetVersionString()); + printf("GLEW version: %s\n", glewGetString(GLEW_VERSION)); + printf("Freetype version: %d.%d.%d\n", (int)fmaj,(int)fmin,(int)fpatch); + + glfwTerminate(); +} From 54e36509d8d4c81ab11b5bacc34839ff8a3cf42c Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:38:25 -0400 Subject: [PATCH 061/105] Add files via upload --- src/tests/Makefile | 103 ++++++++++----- src/tests/testLineChain/Makefile | 63 +++++++++ src/tests/testLineChain/testLineChain.cpp | 82 ++++++++++++ src/tests/testLineFan/Makefile | 63 +++++++++ src/tests/testLineFan/testLineFan.cpp | 66 +++++++++ src/tests/testLines/testLines.cpp | 1 - src/tests/testMouse/Makefile | 63 +++++++++ src/tests/testMouse/testMouse.cpp | 103 +++++++++++++++ src/tests/testPixels/Makefile | 63 +++++++++ src/tests/testPixels/testPixels.cpp | 103 +++++++++++++++ src/tests/testPrism/testPrism.cpp | 3 +- src/tests/testProcedural/Makefile | 63 +++++++++ src/tests/testProcedural/testProcedural.cpp | 125 ++++++++++++++++++ src/tests/testProgressBar/Makefile | 63 +++++++++ src/tests/testProgressBar/testProgressBar.cpp | 58 ++++++++ src/tests/testProjectiles/Makefile | 63 +++++++++ src/tests/testProjectiles/testProjectiles.cpp | 121 +++++++++++++++++ src/tests/testPyramid/testPyramid.cpp | 3 +- src/tests/testRectangle/testRectangle.cpp | 3 +- .../testRegularPolygon/testRegularPolygon.cpp | 3 +- src/tests/testScreenshot/Makefile | 63 +++++++++ src/tests/testScreenshot/testScreenshot.cpp | 54 ++++++++ src/tests/testSpectrogram/Makefile | 63 +++++++++ src/tests/testSpectrogram/testSpectrogram.cpp | 85 ++++++++++++ src/tests/testSpectrum/Makefile | 63 +++++++++ src/tests/testSpectrum/testSpectrum.cpp | 61 +++++++++ src/tests/testSphere/testSphere.cpp | 3 +- src/tests/testSquare/testSquare.cpp | 8 +- src/tests/testStar/testStar.cpp | 1 - src/tests/testText/testText.cpp | 10 +- src/tests/testTextCart/Makefile | 63 +++++++++ src/tests/testTextCart/testTextCart.cpp | 41 ++++++ src/tests/testTextTwo/Makefile | 63 +++++++++ src/tests/testTextTwo/testTextTwo.cpp | 41 ++++++ .../testTransparency/testTransparency.cpp | 3 +- src/tests/testTriangle/testTriangle.cpp | 3 +- .../testTriangleStrip/testTriangleStrip.cpp | 3 +- src/tests/testUnits/Makefile | 63 +++++++++ src/tests/testUnits/testUnits.cpp | 27 ++++ 39 files changed, 1878 insertions(+), 55 deletions(-) create mode 100644 src/tests/testLineChain/Makefile create mode 100644 src/tests/testLineChain/testLineChain.cpp create mode 100644 src/tests/testLineFan/Makefile create mode 100644 src/tests/testLineFan/testLineFan.cpp create mode 100644 src/tests/testMouse/Makefile create mode 100644 src/tests/testMouse/testMouse.cpp create mode 100644 src/tests/testPixels/Makefile create mode 100644 src/tests/testPixels/testPixels.cpp create mode 100644 src/tests/testProcedural/Makefile create mode 100644 src/tests/testProcedural/testProcedural.cpp create mode 100644 src/tests/testProgressBar/Makefile create mode 100644 src/tests/testProgressBar/testProgressBar.cpp create mode 100644 src/tests/testProjectiles/Makefile create mode 100644 src/tests/testProjectiles/testProjectiles.cpp create mode 100644 src/tests/testScreenshot/Makefile create mode 100644 src/tests/testScreenshot/testScreenshot.cpp create mode 100644 src/tests/testSpectrogram/Makefile create mode 100644 src/tests/testSpectrogram/testSpectrogram.cpp create mode 100644 src/tests/testSpectrum/Makefile create mode 100644 src/tests/testSpectrum/testSpectrum.cpp create mode 100644 src/tests/testTextCart/Makefile create mode 100644 src/tests/testTextCart/testTextCart.cpp create mode 100644 src/tests/testTextTwo/Makefile create mode 100644 src/tests/testTextTwo/testTextTwo.cpp create mode 100644 src/tests/testUnits/Makefile create mode 100644 src/tests/testUnits/testUnits.cpp diff --git a/src/tests/Makefile b/src/tests/Makefile index 807532b91..183246145 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,43 +1,82 @@ -# Master Makefile for Examples +# Master Makefile for Tests # ***************************************************** -SUBDIRS := $(wildcard test*/.) +# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the tests +SUBDIRS_TO_BUILD := test_specs \ + test2Dvs3D \ + test3DRotation \ + testAlphaRectangle \ + testArrows \ + testBackground \ + testCircle \ + testConcavePolygon \ + testCone \ + testConvexPolygon \ + testCube \ + testCuboid \ + testCylinder \ + testDice \ + testDiorama \ + testEllipse \ + testEllipsoid \ + testImage \ + testLines \ + testPrism \ + testProcedural \ + testPyramid \ + testRectangle \ + testRegularPolygon \ + testSphere \ + testSquare \ + testStar \ + testText \ + testTransparency \ + testTriangle \ + testTriangleStrip \ +# testAura \ +# testBlurImage \ +# testCalcPi \ +# testColorWheel \ +# testConstructors \ +# testCosineIntegral \ +# testFunction \ +# testGetPixels \ +# testGradientWheel \ +# testGraydient \ +# testGreyscale \ +# testHighData \ +# testImageCart \ +# testInverter \ +# testLineChain \ +# testLineFan \ +# testMouse \ +# testPixels \ +# testProgressBar \ +# testProjectiles \ +# testScreenshot \ +# testSpectrogram \ +# testSpectrum \ +# testTextCart \ +# testTextTwo \ +# testUnits \ -all: $(SUBDIRS) +SUBDIRS_TO_CLEAN := $(subst test,..., $(SUBDIRS_TO_BUILD)) # Used to clean the tests -$(SUBDIRS): + +all: $(SUBDIRS_TO_BUILD) + +$(SUBDIRS_TO_BUILD): @echo "" @tput setaf 3; - @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@)+++++++++++++++++" + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" @tput sgr0; @echo "" $(MAKE) -C $@ -.PHONY: all $(SUBDIRS) - -clean: - (cd test3DRotation && $(MAKE) clean) - (cd testArrows && $(MAKE) clean) - (cd testCircle && $(MAKE) clean) - (cd testConcavePolygon && $(MAKE) clean) - (cd testCone && $(MAKE) clean) - (cd testConvexPolygon && $(MAKE) clean) - (cd testCube && $(MAKE) clean) - (cd testCuboid && $(MAKE) clean) - (cd testCylinder && $(MAKE) clean) - (cd testEllipse && $(MAKE) clean) - (cd testEllipsoid && ${MAKE} clean) - (cd testImage && $(MAKE) clean) - (cd testLines && $(MAKE) clean) - (cd testPrism && $(MAKE) clean) - (cd testPyramid && $(MAKE) clean) - (cd testRectangle && $(MAKE) clean) - (cd testRegularPolygon && $(MAKE) clean) - (cd testSphere && $(MAKE) clean) - (cd testSquare && $(MAKE) clean) - (cd testStar && $(MAKE) clean) - (cd testText && $(MAKE) clean) - (cd testTransparency && ${MAKE} clean) - (cd testTriangle && $(MAKE) clean) - (cd testTriangleStrip && ${MAKE} clean) \ No newline at end of file +.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) + +clean: $(SUBDIRS_TO_CLEAN) + +$(SUBDIRS_TO_CLEAN): + cd $(subst ...,test,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile new file mode 100644 index 000000000..48304e949 --- /dev/null +++ b/src/tests/testLineChain/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLineChain + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineChain + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineChain/testLineChain.cpp b/src/tests/testLineChain/testLineChain.cpp new file mode 100644 index 000000000..8a2b390ad --- /dev/null +++ b/src/tests/testLineChain/testLineChain.cpp @@ -0,0 +1,82 @@ +/* + * testLineChain.cpp + * + * Usage: ./testLineChain + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a spirograph on a given Canvas using the specified number of threads. + * \details + * - The number of iterations, center of the spirograph, distance between threads, and spin are stored in constants. + * - A parallel block is made and the process is forked using the passed number of threads: \b t. + * - The actual number of threads spawned is stored in the constant: \b NTHREADS. + * - The rate at which the spirograph fades is calculated and stored in: \b FADERATE. + * - The current thread's id is stored in: \b TID. + * - \b xOld and \b yOld represent the old x and y-coordinates of the line, + * \b xNew and \b yNew represent the new ones. + * - \b xNew is set to the width of the Canvas, \b yNew is set to the middle of the canvas. + * - Set a variable, \b next, which will be used to determine the next \b xNew and \b yNew and set \b s to \b next. + * - Get a color based off of the thread's id number. + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - While the canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - For 0 to the number of iterations per frame: + * - \b next is incremented by the spacing in between the threads, and \b s is incremented by the spin factor. + * - \b xOld and \b yOld are set to \b xNew and \b yNew. + * - The size of the line is determined by \b s. + * - \b xNew and \b yNew are calculated and set. + * - The line is drawn to the Canvas. + * . + * - If we are working with the main thread, draw a rectangle that is the size of the Canvas and has an alpha transparency + * of: \b FADERATE. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param t The number of threads to use in the function. + */ +void lineChainFunction(Canvas& can, int t) { + const int IPF = 3; + const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; + const float ARC = 2.3f, SPIN = 0.01f; + #pragma omp parallel num_threads(t) + { + const float NTHREADS = omp_get_num_threads(); + const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; + const int TID = omp_get_thread_num(); + int xOld, yOld, xNew = CWW*2, yNew = CWH; + float next = (ARC*TID)/NTHREADS, s = next; + ColorFloat c = Colors::highContrastColor(TID); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = 0; i < IPF; ++i) { + next += ARC; s += SPIN; + xOld = xNew; yOld = yNew; + float size = cos(s); + xNew = CWW + CWW*size*cos(next); + yNew = CWH + CWH*size*sin(next); + can.drawLine(xOld, yOld, xNew, yNew, c); + } + if (TID == 0) + can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); + #pragma omp barrier + } + } +} + +//Takes command line arguments for the window width and height as well as for the number of threads +//to use in the function +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 900; //If not, set the width and height to a default value + unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use + if (t == 0) + t = omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Spirograph", BLACK); + c.run(lineChainFunction,t); +} diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile new file mode 100644 index 000000000..8f2cb68e6 --- /dev/null +++ b/src/tests/testLineFan/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLineFan + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineFan + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineFan/testLineFan.cpp b/src/tests/testLineFan/testLineFan.cpp new file mode 100644 index 000000000..74aaf0d4a --- /dev/null +++ b/src/tests/testLineFan/testLineFan.cpp @@ -0,0 +1,66 @@ +/* + * testLineFan.cpp + * + * Usage: ./testLineFan + */ + +#include +#include +#include "Util.h" + +using namespace tsgl; + +/*! + * \brief Draws a fan of randomly colored lines at the target framerate and a dynamic number of threads using OMP. + * \details + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - The spacing in between the arcs of the fan is stored in the constant: \b ARC . + * - While the canvas is open: + * - The number of threads to use is recalculated, and the process is forked based off of the passed number of threads: \b t. + * - The internal timer sleeps on each thread until the next frame is ready to be drawn. + * - An offset is calculated based on the thread's ID and a predefined arc-length. + * - An angle is then calculated using the offset and the Canvas' current lifespan ( as calculated by \b can.getReps() ). + * - The vertices of the lines to be drawn are chosen using the sines and cosines of the predetermined angle. + * - A random color is chosen. + * - The line is draw to the Canvas. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param t The number of threads to use in the function. + */ +void lineFanFunction(Canvas& can, int t) { + const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan + while (can.isOpen()) { + #pragma omp parallel num_threads(t) + { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + int a, b, c, d, red, green, blue; + double angle, offset = omp_get_thread_num() * ARC; + angle = offset + can.getReps() * RAD; + a = can.getWindowWidth() / 2 * (1 + sin(angle)); + b = can.getWindowHeight() / 2 * (1 + cos(angle)); + c = can.getWindowWidth() / 2 * (1 - sin(angle)); + d = can.getWindowHeight() / 2 * (1 - cos(angle)); + red = (a + can.getReps()) % NUM_COLORS; + green = (b + can.getReps()) % NUM_COLORS; + blue = (a * b + can.getReps()) % NUM_COLORS; + can.drawLine(a, b, c, d, ColorInt(red, green, blue)); + } + } +} + +//Takes command-line arguments for the width and height of the screen as well as for the +//number of threads to use in the function +int main(int argc, char** argv) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid + w = 1200; + h = 900; //If not, set the width and height to a default value + } + unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use + if (t == 0) + t = omp_get_num_procs(); + Canvas c(-1,-1,w,h,"Line Fan"); + c.run(lineFanFunction,t); +} diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp index b51e3f340..625f32b79 100644 --- a/src/tests/testLines/testLines.cpp +++ b/src/tests/testLines/testLines.cpp @@ -63,6 +63,5 @@ int main(int argc, char* argv[]) { int w = 1000; int h = 1000; Canvas c(-1, -1, w, h, "Lines"); - c.setBackgroundColor(BLACK); c.run(lineFunction); } \ No newline at end of file diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile new file mode 100644 index 000000000..404a455c4 --- /dev/null +++ b/src/tests/testMouse/Makefile @@ -0,0 +1,63 @@ +# Makefile for testMouse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMouse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testMouse/testMouse.cpp b/src/tests/testMouse/testMouse.cpp new file mode 100644 index 000000000..e37e49c34 --- /dev/null +++ b/src/tests/testMouse/testMouse.cpp @@ -0,0 +1,103 @@ +/* + * testMouse.cpp + * + * Usage: ./testMouse + */ + +#include + +using namespace tsgl; + +inline float dist(float x1, float y1, float x2, float y2) { + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +inline float angle(float x1, float y1, float x2, float y2) { + return atan2(y1 - y2, x1 - x2); +} + +inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { + float scale = cy/cx; + float stretchy = cy + yy/scale - cx; + float mydist = dist(xx,stretchy,cx,cy); + float newang = angle(xx,stretchy,cx,cy)+rot; + xx = cx + mydist*cos(newang); + yy = cy + mydist*sin(newang)*scale; +} + +/*! + * \brief Tiny little painting function for drawing with the mouse. + * \details + * - Initialize and unset a flag for whether the mouse is pressed. + * - Allocate some large arrays for x,y coordinates and colors. + * - Set an array index variable to 0. + * - Declare variables for last x and y coordinates. + * - Bind the spacebar on-press event to clearing the Canvas. + * - Bind the left mouse on-press event to setting the lastX, lastY, and first x,y array + * coordinate to the mouse's current position, and the first color to a random color; also, + * set the array index to 1, and set the mouseDown flag. + * - Bind the left mouse on-release event to draw a Concave & Convex polygon with the built-up vertices, + * and to unset the mouseDown flag. + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - While the Canvas is open: + * - If the mouse is down: + * - Draw a line from the mouse's last coordinates to the current ones. + * - Set the coordinates at position \b index to the mouse's current position. + * - Set the corresponding color randomly. + * - Increment the index. + * . + * - Sleep the timer until the Canvas is ready to draw again. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void mouseFunction(Canvas& can, int threads) { + const int CX = can.getWindowWidth() / 2, CY = can.getWindowHeight() / 2; + int x[3], y[3], index = 0; + bool mouseDown = false; + ColorFloat color[3]; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { + can.clearProcedural(); + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown, &can, &index, &x, &y, &color]() { + x[0] = can.getMouseX(); + y[0] = can.getMouseY(); + color[0] = Colors::randomColor(1.0f); + index = 0; + mouseDown = true; + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown, &can, &index, &x, &y, &color]() { + mouseDown = false; + }); + + while (can.isOpen()) { + if (mouseDown) { + color[1] = color[2]; + color[2] = Colors::randomColor(1.0f); + x[1] = x[2]; y[1] = y[2]; + x[2] = can.getMouseX(); y[2] = can.getMouseY(); + if (++index > 2) + #pragma omp parallel num_threads (threads) + { + float tdelta = (2*PI*omp_get_thread_num())/omp_get_num_threads(); + int myx[3], myy[3]; + for (int i = 0; i < 3; ++i) { + myx[i] = x[i]; myy[i] = y[i]; + rotate(CX,CY,myx[i],myy[i],tdelta); + } + can.drawConvexPolygon(3,myx,myy,color,true); + } + } + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : -1; + int h = (argc > 2) ? atoi(argv[2]) : w; + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Draw With Your Mouse!", WHITE); + c.run(mouseFunction,t); +} diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile new file mode 100644 index 000000000..d89316619 --- /dev/null +++ b/src/tests/testPixels/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPixels + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPixels + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp new file mode 100644 index 000000000..c4b05bbef --- /dev/null +++ b/src/tests/testPixels/testPixels.cpp @@ -0,0 +1,103 @@ +/* + * testColorPoints.cpp + * + * Usage: ./testColorPoints + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line + * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. + * - The actual number of threads created is stored in: \b nthreads . + * - The number of lines per thread is calculated and stored in: \b myPart . + * - The starting position of each given thread is calculated and stored in: \b myStart . + * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. + * - The color for a thread is calculated. + * - If the point's coordinate is even: + * - Draw a point on the Canvas in the thread's color. + * - Else: + * - Draw the point normally. + * . + * - The function breaks from the outer for loop if the Canvas is closed. + * . + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Number of threads to use. + */ +void colorPointsFunction(Canvas& can, int numberOfThreads) { + // Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); + // can.setBackground(background); + Background * background = can.getBackground(); + + /* this is the part of the test for drawPixel */ + #pragma omp parallel num_threads(numberOfThreads) + { + int nthreads = omp_get_num_threads(); //Actual number of threads to use + // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. + // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. + int myPart = can.getWindowHeight() / nthreads; + int myStart = myPart * omp_get_thread_num(); + for (int i = myStart; i < myStart + myPart; i++) { + for (int j = 0; j < can.getWindowWidth(); j++) { + // int id = omp_get_thread_num(); + if (i % 2 == 0) { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, BLACK); + } else { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(i % 255, j % 255, (i*j) % 255)); + } + } + if (!can.isOpen()) break; + } + } + + /* end drawPixel. while loop only contains can.sleep() */ + + /* the getPixel portion of the test */ + // bool print = false; + // int mouseX = 0; + // int mouseY = 0; + + // background->drawSquare(-100,100,0,100,0,0,0,RED); + // background->drawSquare(-100,-100,0,100,0,0,0,GREEN); + // background->drawSquare(100,100,0,100,0,0,0,BLUE); + // background->drawSquare(100,-100,0,100,0,0,0,ORANGE); + + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { + // print = true; + // }); + + // ColorInt c; + /* end getPixel(). uncomment entirety of while loop besides can.sleep */ + + while (can.isOpen()) { + can.sleep(); + // mouseX = can.getMouseX(); + // mouseY = can.getMouseY(); + // if (print) { + // background->drawPixel(mouseY, mouseX, RED); + // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. + // printf("%d, %d - ", mouseY, mouseX); + // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); + // print = false; + // } + } +} + +//Takes in command line arguments for the window width and height as well +//as for the number of threads to use +int main(int argc, char* argv[]) { + int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); + int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Dithered Points", BLACK); + c.run(colorPointsFunction,t); +} diff --git a/src/tests/testPrism/testPrism.cpp b/src/tests/testPrism/testPrism.cpp index a07561a59..3be365eff 100644 --- a/src/tests/testPrism/testPrism.cpp +++ b/src/tests/testPrism/testPrism.cpp @@ -79,7 +79,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Prism"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Prism", BLACK); c.run(prismFunction); } \ No newline at end of file diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile new file mode 100644 index 000000000..0373a8e25 --- /dev/null +++ b/src/tests/testProcedural/Makefile @@ -0,0 +1,63 @@ +# Makefile for testProcedural + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProcedural + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProcedural/testProcedural.cpp b/src/tests/testProcedural/testProcedural.cpp new file mode 100644 index 000000000..2fe19cfc3 --- /dev/null +++ b/src/tests/testProcedural/testProcedural.cpp @@ -0,0 +1,125 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include + +using namespace tsgl; + +void testSuite1(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawSquare(-400, 225, 0, 100, 0,0,0, RED); + bg->drawSquare(-400, 100, 0, 100, 0,0,0, colors); + bg->drawCircle(-400, -100, 0, 50, 0,0,0, RED); + bg->drawCircle(-400, -225, 0, 50, 0,0,0, colors); + bg->drawEllipse(-225, 225, 0, 75,50, 0,0,0, RED); + bg->drawEllipse(-225, 100, 0, 75,50, 0,0,0, colors); + bg->drawRectangle(-225, -100, 0, 150,100, 0,0,0, RED); + bg->drawRectangle(-225, -225, 0, 150,100, 0,0,0, colors); + bg->drawImage(0,225,0,"./assets/pics/launch.bmp",100,100,0,0,0); + bg->drawText(0,100,0,L"ü^xdog","./assets/freefont/FreeMono.ttf",50,0,0,0,RED); + bg->drawRegularPolygon(0,-100,0,50,5,0,0,0,RED); + bg->drawRegularPolygon(0,-225,0,50,7,0,0,0,colors); + bg->drawTriangle(225,275,0,275,175,0,175,175,0,0,0,0,RED); + bg->drawTriangle(225,50,0,275,150,0,175,150,0,0,0,0,colors); + float x1[4] = { 160, 225, 225, 290 }; + float y1[4] = {-100, -50,-150,-100 }; + float z1[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-100,0,4,x1,y1,z1,0,0,0,RED); + float x2[4] = { 160, 225, 225, 290 }; + float y2[4] = {-225,-175,-275,-225 }; + float z2[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-225,0,4,x2,y2,z2,0,0,0,colors); + bg->drawArrow(400,225,0,100,10,45,0,0,RED,true); + bg->drawArrow(400,100,0,100,10,-45,0,0,colors); + bg->drawLine(400,-50,0,100,20,0,0,RED); + bg->drawLine(400,-150,0,100,-20,0,0,colors); + float vertices1[12] = { 350,-175,0, + 350,-200,0, + 450,-250,0, + 450,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices1,0,0,0,RED); + float vertices2[12] = { 450,-175,0, + 450,-200,0, + 350,-250,0, + 350,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices2,0,0,0,colors); +} + +void testSuite2(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawStar(-400,225,0,50,5,0,0,0,RED,false); + bg->drawStar(-400,100,0,50,7,0,0,0,colors,false); + float x1[6] = { -450,-400,-375,-350,-400,-450 }; + float y1[6] = { -50, -50, -60,-150,-150,-100 }; + // renders incorrectly + bg->drawConcavePolygon(-400,-100,0,6,x1,y1,0,0,0,RED); + float x2[6] = { -450,-400,-375,-350,-400,-450 }; + float y2[6] = { -175,-175,-185,-275,-275,-225 }; + // renders correctly, due to shifted vertices + bg->drawConcavePolygon(-400,-225,0,6,x2,y2,0,0,0,colors); + float x3[6] = { -275,-175,-200,-175,-275,-250 }; + float y3[6] = { 275, 275, 225, 175, 175, 225 }; + bg->drawConvexPolygon(-400,225,0,6,x3,y3,0,0,0,RED); + float x4[6] = { -250,-275,-175,-200,-175,-275 }; + float y4[6] = { 100, 150, 150, 100, 50, 50 }; + bg->drawConvexPolygon(-400,100,0,6,x4,y4,0,0,0,colors); + + +} + +void proceduralFunction(Canvas& can) { + Background * bg = can.getBackground(); + // float x1[6] = { -275,-175,-200,-175,-275,-250 }; + // float y1[6] = { 275, 275, 225, 175, 175, 225 }; + // ConcavePolygon * c = new ConcavePolygon(0,0,0,6,x1,y1,0,0,0,RED); + // can.add(c); + + // Star * s = new Star(0,0,0,50,7,0,0,0,RED,false); + // can.add(s); + + // can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&c]() { + // c->changeXBy(10); + // }); + + bool flip = true; + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg, &flip]() { + if (flip) { + testSuite1(bg); + } else { + testSuite2(bg); + } + flip = !flip; + }); + + while (can.isOpen()) { + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.9*Canvas::getDisplayWidth(); + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Procedural Background", BLACK); + c.run(proceduralFunction); +} \ No newline at end of file diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile new file mode 100644 index 000000000..8f0f83322 --- /dev/null +++ b/src/tests/testProgressBar/Makefile @@ -0,0 +1,63 @@ +# Makefile for testProgressBar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProgressBar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProgressBar/testProgressBar.cpp b/src/tests/testProgressBar/testProgressBar.cpp new file mode 100644 index 000000000..fc7e8bd98 --- /dev/null +++ b/src/tests/testProgressBar/testProgressBar.cpp @@ -0,0 +1,58 @@ +/* + * testProgressBar.cpp + * + * Usage: ./testProgressBar + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command line argument for the + * number of threads to use. + * \details + * - Compute and store the necessary information in order to draw the ProgressBar object + * (x-coordinate, y-coordinate, width, height, minimum, maximum, and the number of segments). + * - Create the ProgressBar object with the information calculated in the previous step. + * - Set the progress of drawing the ProgressBar object and store it in: \b progress. + * - While the Canvas is open: + * - Sleep the Canvas' internal timer until the next draw cycle. + * - Increment the progress so far. + * - For 0 to the number of segments: + * - Update the ProgressBar object. + * . + * - Draw the ProgressBar onto the Canvas. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void progressBarFunction(Canvas& can, int numThreads) { + const int X = 100, Y = X, W = can.getWindowWidth()-X*2, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; + ProgressBar pb(X,Y,W,H,MIN,MAX,SEGS); + int progress = 0; + for (int i = 0; i < SEGS; ++i) + can.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + ++progress; + for (int i = 0; i < SEGS; ++i) + pb.update(progress+i*(MAX/SEGS),i); + can.drawProgress(&pb); + } +} + +//Takes in the number of threads to use as a command line argument for the Canvas, defaulting to 8. +//( see http://www.cplusplus.com/articles/DEN36Up4/ ) +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : 8; + int w; + int h; + if (t <= 0 || 10 < t) //Checked the passed threadNumber if it is valid + t = 8; //If not, set numThreads to a default value + w = (t+2)*100; + h = 200; + Canvas c(-1, -1, w, h, "Progress Bar Example"); + c.run(progressBarFunction, t); +} diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile new file mode 100644 index 000000000..68e0bf69a --- /dev/null +++ b/src/tests/testProjectiles/Makefile @@ -0,0 +1,63 @@ +# Makefile for Projectiles + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProjectiles + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProjectiles/testProjectiles.cpp b/src/tests/testProjectiles/testProjectiles.cpp new file mode 100644 index 000000000..1b3c0dd35 --- /dev/null +++ b/src/tests/testProjectiles/testProjectiles.cpp @@ -0,0 +1,121 @@ +/* + * testProjectiles.cpp + * + * Usage: ./testProjectiles + */ + +#include "tsgl.h" + +using namespace tsgl; + +/*! + * \brief Target practice mini-game! + * \details Creates the target practice mini-game in this way: + * - Get coordinates for the target based off of the window size. + * - Set a coordinate changer for the target's x coordinate (so that it moves from left to right on the screen). + * - Get the center of the Canvas. + * - Get the number of targets (10). + * - Get the score counter. + * - Get the colors for the target (outer, middle, and bulls-eye center). + * - Bind the mouse so that when one clicks and hits the target in the middle then + * the score counter goes up. + * - While the Canvas is still open: + * - Sleep the internal timer of the Canvas until the next drawing loop is ready to be drawn. + * - Increment the target's x-coordinate by the coordinate changer. + * - Move the target up vertically by coordinate changer for its y-coordinate. + * - Draw the actual target. + * - If the target hits the middle of the screen: + * - Invert the y change so that the target moves downward. + * . + * - If the target goes off screen to the right: + * - Decrement the number of targets left. + * - Reset the targetX, targetY, and the coordinate changer for y. + * . + * - If we hit a target in the middle: + * - Increment the score. + * - Change the hit to false; + * - Move the target off of the screen. + * . + * - If the number of targets is less than 5: + * - Speed up the movement of the remaining targets. + * . + * - If the number of targets left is 0: + * - Print out the score, clear the Canvas one last time, and get out of the drawing loop. + * . + * . + * . + * \param can Reference to the Canvas being drawn on. + */ +void projectileFunction(Canvas& can) { + const int WINDOW_W = can.getWindowWidth(); + int targetX = 0, targetY = WINDOW_W / 2, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion + int centerX = WINDOW_W / 2;// centerY = WINDOW_H / 2; //Center of screen + int numberOfTargets = 10; //Number of targets + bool hit = false; //Determine if the target has been hit + int score = 0; //Score + ColorInt blueTarget(0, 0, 255); + ColorInt redTarget(255, 0, 0); //Color for targets + ColorInt yellowTarget(255, 255, 0); + //binding to left mouse button + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&hit, &can, &targetX, &targetY]() { + if((can.getMouseX() <= targetX && can.getMouseY() <= targetY) || can.getMouseY() == targetY) { + hit = true; //We hit the target + } + }); + + //Create circles of target and add to Canvas + Circle * blueCircle = new Circle(targetX, targetY, 50, BLUE); //Outer circle + Circle * redCircle = new Circle(targetX, targetY, 30, RED); //Middle + Circle * yellowCircle = new Circle(targetX, targetY, 10, YELLOW); //Inner + can.add(blueCircle); can.add(redCircle); can.add(yellowCircle); + + //Draw loop + while(can.isOpen()) { + can.sleep(); + can.clearProcedural(); + + targetX += coordinateChangerX; //Horizontal movement + targetY -= coordinateChangerY; //Vertical movement + + if(hit) { //If we hit a target.... + score++; + targetX = WINDOW_W + 60; + hit = false; + } + if(targetX >= centerX) { //If it hits the middle of the screen, invert the vertical direction + coordinateChangerY = -1; + } + if(targetX > WINDOW_W + 60) { //If the target is off the screen + numberOfTargets--; //Decrement the number of targets left + targetX = 0; //Reset the target and inverter + targetY = 200; + coordinateChangerY = 1; + } + if(numberOfTargets <= 5) { //Mix it up if there are only five targets left (speed up the targets) + coordinateChangerX = 6; + } + //Move each circle to the target's location + blueCircle->setCenter(targetX, targetY); + redCircle->setCenter(targetX, targetY); + yellowCircle->setCenter(targetX, targetY); + if(numberOfTargets == 0) { //End game + std::cout << "Your score: " << score << std::endl; + can.remove(redCircle); + can.remove(blueCircle); + can.remove(yellowCircle); + numberOfTargets--; + } + } + + delete redCircle; + delete blueCircle; + delete yellowCircle; +} + +//Takes command-line arguments for the width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + Canvas c(-1, -1, w, h, "Click the Target!", BLACK); //Can change the size of the window + c.run(projectileFunction); +} diff --git a/src/tests/testPyramid/testPyramid.cpp b/src/tests/testPyramid/testPyramid.cpp index ac0db8692..fdbf30f6a 100644 --- a/src/tests/testPyramid/testPyramid.cpp +++ b/src/tests/testPyramid/testPyramid.cpp @@ -73,7 +73,6 @@ void pyramidFunction(Canvas& can) { } int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Basic Pyramid"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Pyramid", BLACK); c.run(pyramidFunction); } \ No newline at end of file diff --git a/src/tests/testRectangle/testRectangle.cpp b/src/tests/testRectangle/testRectangle.cpp index 89a6a9e46..c83e94fa6 100644 --- a/src/tests/testRectangle/testRectangle.cpp +++ b/src/tests/testRectangle/testRectangle.cpp @@ -63,7 +63,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Rectangle"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Rectangle", BLACK); c.run(rectangleFunction); } \ No newline at end of file diff --git a/src/tests/testRegularPolygon/testRegularPolygon.cpp b/src/tests/testRegularPolygon/testRegularPolygon.cpp index d3b7f54ef..9a4dd7ea9 100644 --- a/src/tests/testRegularPolygon/testRegularPolygon.cpp +++ b/src/tests/testRegularPolygon/testRegularPolygon.cpp @@ -58,7 +58,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon", BLACK); c.run(rpFunction); } \ No newline at end of file diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile new file mode 100644 index 000000000..bfc7c5018 --- /dev/null +++ b/src/tests/testScreenshot/Makefile @@ -0,0 +1,63 @@ +# Makefile for testScreenshot + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testScreenshot + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testScreenshot/testScreenshot.cpp b/src/tests/testScreenshot/testScreenshot.cpp new file mode 100644 index 000000000..96ce86a03 --- /dev/null +++ b/src/tests/testScreenshot/testScreenshot.cpp @@ -0,0 +1,54 @@ +/* + * testScreenshot.cpp + * + * Usage: ./testScreenshot + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a bunch of triangles and outputs each frame to an image. + * \details + * - Declare and initialize variables to keep track of each of three vertices for a triangle. + * - Set the Canvas to record screenshots for 30 seconds (1800 frames). + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - Set the old coordinates to last frame's middle ones. + * - Set the middle coordinates to last frame's new ones. + * - Set the new coordinates to a random position on the Canvas. + * - Draw a triangle on the canvas with the given coordinates and a random color. + * . + * . + * \note The details of the recordForNumFrames() function are handled automatically in Canvas, and + * are by default written to the i frames/ directory. + * \param can Reference to the Canvas being drawn to. + */ +void screenShotFunction(Cart& can) { + int xNew = can.getWindowWidth() / 2, yNew = can.getWindowHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; + can.recordForNumFrames(FPS * 30); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + xOld = xMid; + yOld = yMid; + xMid = xNew; + yMid = yNew; + xNew = rand() % can.getWindowWidth(); + yNew = rand() % can.getWindowHeight(); + can.drawTriangle(xOld, yOld, xMid, yMid, xNew, yNew, Colors::randomColor(), true); + } +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 800; //Width and height + int h = (argc > 2) ? atoi(argv[2]) : 600; + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 800; + h = 600; + } + Cart c(-1, -1, w, h, 0, 0, 800, 600,"Screenshot Test"); + c.run(screenShotFunction); +} diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile new file mode 100644 index 000000000..dfaa0fba6 --- /dev/null +++ b/src/tests/testSpectrogram/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSpectrogram + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrogram + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrogram/testSpectrogram.cpp b/src/tests/testSpectrogram/testSpectrogram.cpp new file mode 100644 index 000000000..99eb133ae --- /dev/null +++ b/src/tests/testSpectrogram/testSpectrogram.cpp @@ -0,0 +1,85 @@ +/* + * testSpectrogram.cpp + * + * Usage: ./testSpectrogram + */ + +#include + +#include +using namespace tsgl; + +/*! + * \brief Displays a spectrogram. + * \details Shows a spectrogram for the colors of a chosen photo. + * - The window width and height are stored for ease of use. + * - The image is drawn onto the Canvas. + * - A Spectrogram object is created which will display the spectrogram. + * - Sleep the Canvas for 1/10th of a second. + * - Have a counter that keeps track of the number of pixels that we have checked (for their color). + * - A parallel block is created and the process is forked. + * - The thread id and the actual number of threads spawned are stored. + * - Start and stopping points for the thread are calculated and stored. + * - For the starting point to the ending point of rendering: + * - If the Canvas is open: + * - Sleep the internal timer until the next draw cycle. + * - For 0 to the width of the Canvas: + * - Get a hue color based off of the current pixel. + * - Check for a weird case where we can end up with a NaN error (Not a Number). + * - Draw the point onto the Canvas. + * . + * - Update the number of pixels checked in an parallel atomic block (to avoid conflicts). + * - Draw the results on the Spectrogram object. + * . + * . + * - Have the Canvas sleep for: FRAME seconds. + * - Draw the chosen image onto the Canvas. + * - Close the Spectrogram object. + * . + * \param can Reference to the Canvas object to draw to. + * \param fname The name of the file to get the image from. + */ +void spectrogramFunction(Canvas& can, std::string fname) { + const int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + can.drawImage(fname, 0, 0, cww, cwh); + Spectrogram sp(VERTICAL,500); + can.sleepFor(0.1f); +// can.recordForNumFrames(FPS); + unsigned numChecked = 0; + #pragma omp parallel num_threads(omp_get_num_procs()) + { + int tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); + int blockSize = cwh / nthreads; + int start = tid * blockSize; + int end = (tid == (nthreads-1)) ? cwh : (tid+1) * blockSize; + for (int j = start; j < end; ++j) { + if (can.isOpen()) { + can.sleep(); + ColorHSV hsv; + for (int i = 0; i < cww; ++i) { + hsv = can.getPoint(i,j); + if (hsv.H == hsv.H) { //Check for NAN + sp.updateLocked(MAX_COLOR*hsv.H/6,1.0f,0.8f); + sp.updateCritical(MAX_COLOR*hsv.H/6,1.0f,0.8f); + } + can.drawPoint(i,j,ColorHSV(0.0f,0.0f,hsv.V)); + } + #pragma omp atomic + ++numChecked; + sp.draw((float)(1.0f*numChecked)/cwh); + } + } + } + // can.sleepFor(FRAME); + can.drawImage(fname, 0, 0, cww, cwh); + sp.finish(); +} + +//Takes command-line arguments for the file name of the picture to use in the spectrogram function +int main(int argc, char* argv[]) { + std::string fname = argc > 1 ? argv[1] : "../assets/pics/colorful_cars.jpg"; + int w, h; + TextureHandler::getDimensions(fname,w,h); + Canvas c(-1, Canvas::getDisplayHeight()-h, w, h ,"Spectrogram"); + c.run(spectrogramFunction, fname); +} diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile new file mode 100644 index 000000000..760443e7b --- /dev/null +++ b/src/tests/testSpectrum/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSpectrum + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrum + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrum/testSpectrum.cpp b/src/tests/testSpectrum/testSpectrum.cpp new file mode 100644 index 000000000..63fb5f125 --- /dev/null +++ b/src/tests/testSpectrum/testSpectrum.cpp @@ -0,0 +1,61 @@ +/* + * testSpectrum.cpp + * + * Usage: ./testSpectrum + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws the full spectrum across the x, y, and time dimensions at the given framerate + * and a static number of threads using OMP and takes in a command line argument for the number of threads to use. + * \details + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - A parallel block is set up with OMP, using one thread per processor. + * - The actual number of threads spawned is stored in: \b nthreads. + * - Check if the argument for the number of threads is valid: + * - If it is less than or equal to 0, use the number of threads that we can use with OMP. + * - If it is greater than the number of threads that we can use, use only the number of threads that we can use with OMP. + * - Else, its valid and use that many threads. + * . + * - While the canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - An outer for loop from 0 to 255 is set up in a per-thread striping pattern. + * - An inner for loop runs from 0 to the 255 normally. + * - Each point is drawn to the canvas, with x, y, and time representing red, green, and blue respectively. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void spectrumFunction(Canvas& can, int numberOfThreads) { + #pragma omp parallel num_threads(omp_get_num_procs()) + { + int holder = omp_get_num_threads(); //Temp variable + int nthreads = 0; //Actual number of threads + if (numberOfThreads <= 0) { //Check if the argument for the number of threads is valid + nthreads = holder; //If not, use the number of threads that we can use with OMP + } else if(numberOfThreads > holder) { + nthreads = holder; + } else { + nthreads = numberOfThreads; //Else, use the argument as the number of threads + } + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = omp_get_thread_num(); i < NUM_COLORS; i += nthreads) + for (int j = 0; j < NUM_COLORS; j++) + can.drawPoint(i, j, ColorInt(i, j, can.getReps() % NUM_COLORS)); + } + } +} + +//Takes command-line arguments for the number of threads to use +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); //Number of threads to use + Canvas c(-1,-1,255,255,"The Color Spectrum"); + c.run(spectrumFunction, t); +} + diff --git a/src/tests/testSphere/testSphere.cpp b/src/tests/testSphere/testSphere.cpp index e2e9a8600..3d602168a 100644 --- a/src/tests/testSphere/testSphere.cpp +++ b/src/tests/testSphere/testSphere.cpp @@ -75,7 +75,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Sphere"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Sphere", BLACK); c.run(sphereFunction); } \ No newline at end of file diff --git a/src/tests/testSquare/testSquare.cpp b/src/tests/testSquare/testSquare.cpp index 666c9999b..56eaf740a 100644 --- a/src/tests/testSquare/testSquare.cpp +++ b/src/tests/testSquare/testSquare.cpp @@ -26,6 +26,7 @@ void squareFunction(Canvas& can) { can.add(square2); float floatVal = 0.0f; GLfloat delta = 0.05; + bool ss = false; while (can.isOpen()) { can.sleep(); // square->setCenterX(sin(floatVal/90) * 100); @@ -44,6 +45,10 @@ void squareFunction(Canvas& can) { // } else { // square->setColor(RED); // } + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } floatVal += 1; } @@ -56,7 +61,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Square"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Square", BLACK); c.run(squareFunction); } \ No newline at end of file diff --git a/src/tests/testStar/testStar.cpp b/src/tests/testStar/testStar.cpp index e7be6c610..14afe96c6 100644 --- a/src/tests/testStar/testStar.cpp +++ b/src/tests/testStar/testStar.cpp @@ -48,6 +48,5 @@ int main(int argc, char* argv[]) { int w = 1000; int h = 1000; Canvas c(-1, -1, w, h, "Stars"); - c.setBackgroundColor(BLACK); c.run(starFunction); } \ No newline at end of file diff --git a/src/tests/testText/testText.cpp b/src/tests/testText/testText.cpp index 1ca4b1422..fc07072d1 100644 --- a/src/tests/testText/testText.cpp +++ b/src/tests/testText/testText.cpp @@ -30,9 +30,9 @@ void textFunction(Canvas& can, std::string font) { Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); can.add(uppercase); Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); - Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); + // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); can.add(random); - can.add(rec); + // can.add(rec); can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { random->setText(L"Glorgaborg"); @@ -41,9 +41,14 @@ void textFunction(Canvas& can, std::string font) { // random->setFontSize(100); }); + bool ss = false; float rotation = 0.0f; while(can.isOpen()) { can.sleep(); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } // random->setCenterX(sin(rotation)*200); // random->setCenterY(cos(rotation)*200); // random->setCenterZ(sin(rotation)*100); @@ -69,6 +74,5 @@ int main(int argc, char * argv[]) { h = 0.75f*w; } Canvas c(-1, -1, w, h, "Text on a Canvas"); - c.setBackgroundColor(BLACK); c.run(textFunction, font); } diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile new file mode 100644 index 000000000..5963dd8bb --- /dev/null +++ b/src/tests/testTextCart/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTextCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextCart/testTextCart.cpp b/src/tests/testTextCart/testTextCart.cpp new file mode 100644 index 000000000..77f5956a7 --- /dev/null +++ b/src/tests/testTextCart/testTextCart.cpp @@ -0,0 +1,41 @@ +/* + * testTextCart.cpp + * + * Usage: ./testTextCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a CartesianCanvas. + * \details Same as textFunction, but with a CartesianCanvas and black text. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + * \param font The font of the text. + */ +void textCartFunction(Cart& can, std::string font) { + can.setFont(font); + can.drawText(L"A long time ago, in a galaxy far, far away.", 1, 2, 32, BLACK); + can.drawText(L"Something extraordinary happened.", 1, 1.9, 32, BLACK); + can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 1, 1.8, 32, BLACK); + can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 1, 1.7, + 32, BLACK); + can.drawText(L"Of *what* exactly that extraordinary event was.", 1, 1.6, 32, BLACK); + can.drawText(L"And to that I say...oh well.", 1, 1.5, 32, BLACK); +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font file for the text +int main(int argc, char * argv[]) { + //Width and height + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w - 200.0f; + std::string font = argv[3]; //Font + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 1.2 * Canvas::getDisplayHeight(); + h = 0.75 * w; + } + Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); + c.run(textCartFunction, font); +} diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile new file mode 100644 index 000000000..a230e8978 --- /dev/null +++ b/src/tests/testTextTwo/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTextTwo + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextTwo + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextTwo/testTextTwo.cpp b/src/tests/testTextTwo/testTextTwo.cpp new file mode 100644 index 000000000..b6ef8060e --- /dev/null +++ b/src/tests/testTextTwo/testTextTwo.cpp @@ -0,0 +1,41 @@ +/* + * testTextTwo.cpp + * + * Usage: ./testTextTwo + */ + +#include + +using namespace tsgl; + +/** + * \brief Tests to see if text is still drawn if a font is not specified. + * \details Same as textFunction, but with the setFont line deleted. + * \param can Reference to the Canvas being drawn to. + */ +void textFunctionTwo(Canvas& can) { + ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); + ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); + ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); + + can.drawText(L"A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + can.drawText(L"Something extraordinary happened.", 16, 150, 32, RED); + can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + 32, BLUE); + can.drawText(L"Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + can.drawText(L"And to that I say...oh well.", 16, 550, 32, WHITE); +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + //Width and height + int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 300.0f; + if(w <= 0 || h <= 0) { //Check the validity of the width and height + w = 1.2f*Canvas::getDisplayHeight(); + h = 0.75f*w; + } + Canvas c(-1, -1, w, h, "More Text on a Canvas"); + c.run(textFunctionTwo); +} diff --git a/src/tests/testTransparency/testTransparency.cpp b/src/tests/testTransparency/testTransparency.cpp index c852b3e20..efb7867d3 100644 --- a/src/tests/testTransparency/testTransparency.cpp +++ b/src/tests/testTransparency/testTransparency.cpp @@ -26,7 +26,6 @@ void transparencyFunction(Canvas& can) { } int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Transparency"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Transparency", BLACK); c.run(transparencyFunction); } \ No newline at end of file diff --git a/src/tests/testTriangle/testTriangle.cpp b/src/tests/testTriangle/testTriangle.cpp index af80c2314..f29e650cb 100644 --- a/src/tests/testTriangle/testTriangle.cpp +++ b/src/tests/testTriangle/testTriangle.cpp @@ -54,7 +54,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Triangle"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic Triangle", BLACK); c.run(triangleFunction); } \ No newline at end of file diff --git a/src/tests/testTriangleStrip/testTriangleStrip.cpp b/src/tests/testTriangleStrip/testTriangleStrip.cpp index ab27b3838..dc281cd33 100644 --- a/src/tests/testTriangleStrip/testTriangleStrip.cpp +++ b/src/tests/testTriangleStrip/testTriangleStrip.cpp @@ -55,7 +55,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip", BLACK); c.run(triangleStripFunction); } \ No newline at end of file diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile new file mode 100644 index 000000000..c0ec4da0b --- /dev/null +++ b/src/tests/testUnits/Makefile @@ -0,0 +1,63 @@ +# Makefile for testUnits + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testUnits + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testUnits/testUnits.cpp b/src/tests/testUnits/testUnits.cpp new file mode 100644 index 000000000..f62a3271a --- /dev/null +++ b/src/tests/testUnits/testUnits.cpp @@ -0,0 +1,27 @@ +/* + * testUnits.cpp + * + * Usage: ./testUnits + */ + +/* testUnits.cpp runs the unit tests for the TSGL library. */ + +#include "tsgl.h" + +using namespace tsgl; + +int main() { + //Quick note about the tests... + std::cout << "NOTE: " << std::endl; + TsglDebug("This color means either a set of tests is being initiated or tests have passed."); + TsglErr("This color means tests have failed."); + //Begin Unit testing + std::cout << "Begin unit testing...." << std::endl << std::endl; + Canvas::runTests(); // Canvas (Image test included) + TextureHandler::runTests(); // TextureHandler + ConcavePolygon::runTests(); // ConcavePolygon + ConvexPolygon::runTests(); // ConvexPolygon + CartesianCanvas::runTests(); // CartesianCanvas + std::cout << std::endl; + TsglDebug("All Unit Tests have completed!"); +} From a797e187bb5ac2714f374ab0bc4e0fd11ebd8c0c Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:39:32 -0400 Subject: [PATCH 062/105] Delete LifeFarm.cpp --- src/tests/Conway/LifeFarm.cpp | 359 ---------------------------------- 1 file changed, 359 deletions(-) delete mode 100644 src/tests/Conway/LifeFarm.cpp diff --git a/src/tests/Conway/LifeFarm.cpp b/src/tests/Conway/LifeFarm.cpp deleted file mode 100644 index bd6bb9ff5..000000000 --- a/src/tests/Conway/LifeFarm.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* - * LifeFarm.cpp - */ - -#include "LifeFarm.h" - -LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { - framecount = 0; - listend = 0; - width = w; - height = h; - size = w * h; - livelist = new int[size]; - int maxsize = 1+h*(1+w); - currentstate = new int[maxsize]; - for (int i = 0; i < maxsize; ++i) - currentstate[i] = 0; - nextstate = new int[maxsize]; - for (int i = 0; i < maxsize; ++i) - nextstate[i] = 0; - for (int i = 0; i < size; ++i) - livelist[i] = 0; - - currentstart = currentstate; //Pointers to the beginning of the arrays - nextstart = nextstate; - - alive = new bool*[h](); - for (int i = 0; i < h; ++i) { - alive[i] = new bool[w]; - for (int j = 0; j < w; ++j) - alive[i][j] = false; - } - if (randomize) { - for (int i = 9*h/10; i > h/10; --i) { - bool newrow = true; - for (int j = 9*w/10; j > w/10; --j) { - if ((rand() % 2) > 0) { - if (newrow) { - *currentstate = (i + 1); - ++currentstate; - newrow = false; - } - *currentstate = -(j + 1); - ++currentstate; - addAnt(j,i); - } - } - } - *currentstate = 0; - currentstate = currentstart; - } - else - initGun(); - can = c; - neighbors = new int*[h](); - for (int i = 0; i < h; ++i) - neighbors[i] = new int[w]; - bgcolor = c->getBackgroundColor(); - drawdead = false; -} - -void LifeFarm::initGun() { - int w = width/2, h = height/2; - currentstart = currentstate; - *currentstate++ = h+1; - *currentstate++ = -(w+25); - addAnt(w+25,h+1); - *currentstate++ = h+2; - *currentstate++ = -(w+25); - *currentstate++ = -(w+23); - addAnt(w+25,h+2); - addAnt(w+23,h+2); - *currentstate++ = h+3; - *currentstate++ = -(w+36); - *currentstate++ = -(w+35); - *currentstate++ = -(w+22); - *currentstate++ = -(w+21); - *currentstate++ = -(w+14); - *currentstate++ = -(w+13); - addAnt(w+36,h+3); - addAnt(w+35,h+3); - addAnt(w+22,h+3); - addAnt(w+21,h+3); - addAnt(w+14,h+3); - addAnt(w+13,h+3); - *currentstate++ = h+4; - *currentstate++ = -(w+36); - *currentstate++ = -(w+35); - *currentstate++ = -(w+22); - *currentstate++ = -(w+21); - *currentstate++ = -(w+16); - *currentstate++ = -(w+12); - addAnt(w+36,h+4); - addAnt(w+35,h+4); - addAnt(w+22,h+4); - addAnt(w+21,h+4); - addAnt(w+16,h+4); - addAnt(w+12,h+4); - *currentstate++ = h+5; - *currentstate++ = -(w+22); - *currentstate++ = -(w+21); - *currentstate++ = -(w+17); - *currentstate++ = -(w+11); - *currentstate++ = -(w+2); - *currentstate++ = -(w+1); - addAnt(w+22,h+5); - addAnt(w+21,h+5); - addAnt(w+17,h+5); - addAnt(w+11,h+5); - addAnt(w+2,h+5); - addAnt(w+1,h+5); - *currentstate++ = h+6; - *currentstate++ = -(w+25); - *currentstate++ = -(w+23); - *currentstate++ = -(w+18); - *currentstate++ = -(w+17); - *currentstate++ = -(w+15); - *currentstate++ = -(w+11); - *currentstate++ = -(w+2); - *currentstate++ = -(w+1); - addAnt(w+25,h+6); - addAnt(w+23,h+6); - addAnt(w+18,h+6); - addAnt(w+17,h+6); - addAnt(w+15,h+6); - addAnt(w+11,h+6); - addAnt(w+2,h+6); - addAnt(w+1,h+6); - *currentstate++ = h+7; - *currentstate++ = -(w+25); - *currentstate++ = -(w+17); - *currentstate++ = -(w+11); - addAnt(w+25,h+7); - addAnt(w+17,h+7); - addAnt(w+11,h+7); - *currentstate++ = h+8; - *currentstate++ = -(w+16); - *currentstate++ = -(w+12); - addAnt(w+16,h+8); - addAnt(w+12,h+8); - *currentstate++ = h+9; - *currentstate++ = -(w+14); - *currentstate++ = -(w+13); - addAnt(w+14,h+9); - addAnt(w+13,h+9); - *currentstate = 0; - currentstate = currentstart; -} - -LifeFarm::~LifeFarm() { - for (int i = 0; i < height; ++i) { - delete[] alive[i]; - delete[] neighbors[i]; - } - delete[] alive; - delete[] neighbors; - delete[] livelist; - delete[] currentstate; - delete[] nextstate; -} - -void LifeFarm::addAnt(int x, int y) { - livelist[listend++] = y*width+x; - alive[y][x] = true; -} - -void LifeFarm::moveAnts() { - moveAntsOld(); -// moveAntsNew(); -} - -void LifeFarm::moveAntsOld() { - //Compute this frame's color - const int P1 = 7, P2 = 11, P3 = 17; - // std::cout << ++framecount << std::endl; - int r = (framecount*P1/50 % 255); - if (r < 128) r = 255 - r; - int g = (framecount*P2/50 % 255); - if (g < 128) g = 255 - g; - int b = (framecount*P3/50 % 255); - if (b < 128) b = 255 - b; - ColorFloat fcolor = ColorInt(r,g,b,255); - - //Clear the each cell's neighbor list - for (int i = 0; i < height; ++i) - for (int j = 0; j < width; ++j) - neighbors[i][j] = 0; - - //Populate the neighbor list of each living cell - int tid = 0, nthreads = 1; - for (int i = tid; i < listend ; i += nthreads) { - int n = livelist[i]; - int row = n / width, col = n % width; - int xm = col - 1; - if (xm < 0) xm = width - 1; - int xp = col+1; - if (xp > width-1) xp = 0; - int ym = row-1; - if (ym < 0) ym = height - 1; - int yp = row+1; - if (yp > height-1) yp = 0; - ++neighbors[ym][xm]; - ++neighbors[row][xm]; - ++neighbors[yp][xm]; - ++neighbors[ym][col]; - ++neighbors[yp][col]; - ++neighbors[ym][xp]; - ++neighbors[row][xp]; - ++neighbors[yp][xp]; - } - - //Reset the end of the list for the next iteration - listend = 0; - - //Redraw any cell whose living status has changed, and repopulate the living list - bool lives, lived; - for (int row = 0; row < height; ++row) { - for (int col = 0; col < width; ++ col) { - lived = alive[row][col]; - lives = ( (neighbors[row][col] == 3) || ( lived && (neighbors[row][col] == 2) )); - if (lives != lived) { - if (lives) { - can->drawPoint(col, row, fcolor); - addAnt(col,row); - } - else if (drawdead) - can->drawPoint(col, row, bgcolor); - alive[row][col] = lives; - } else if (lives) - addAnt(col,row); - } - } -} - - -void LifeFarm::moveAntsNew() { - life(currentstate,nextstate); - //Swap pointers to the begnning of the current and next state arrays - int* temp = nextstart; - nextstart = currentstart; - currentstart = temp; - //Move the pointers to the beginning of the newly-swapped arrays - currentstate = currentstart; - nextstate = nextstart; - return; -} - -void LifeFarm::setDrawdead(bool b) { - drawdead = b; -} - - -void LifeFarm::life(int *current, int *fresh) { - //Compute this frame's color - const int P1 = 7, P2 = 11, P3 = 17; - std::cout << ++framecount << std::endl; - int r = (framecount*P1/50 % 255); - if (r < 128) r = 255 - r; - int g = (framecount*P2/50 % 255); - if (g < 128) g = 255 - g; - int b = (framecount*P3/50 % 255); - if (b < 128) b = 255 - b; - ColorFloat fcolor = ColorInt(r,g,b,255); - - unsigned bitmap; - int *next, *prev, *start; - start = fresh; - int x, y; - static bool state[1 << 9]; //Array of dead / alive states - static bool init = false; - - //Check for init [007 (octal) == 00000111 (binary) -> 3 neighbors] - if(!init) { - init = true; - //Populate a state bitmap - for(bitmap = 0; bitmap < (1<<9); bitmap++) { - for(x = y = 0; y < 9; y++) //For each cell in the 3x3 neighbor grid - if(bitmap & (1< center cell is alive] - if(x == 2 || x == 3) //If two neighbors or three neighbors, alive; else, dead - state[bitmap] = true; - else - state[bitmap] = false; - } else { //Else, bitmap is dead - if(x == 3) //If three neighbors, alive; else, dead - state[bitmap] = true; - else - state[bitmap] = false; - } - } - } - - x = y = 0; //ADDED - - prev = next = current; //Set the previous / next cell to the first cell of "this" (the old state) - bitmap = 0; //Set bitmap to 0 (empty) - *fresh = 0; //Set the first position of the new state to 0 (empty) - for(;;) { //For each row - /* did we write an X co-ordinate? */ - if(*fresh < 0) //If the next element in the new state is an x coordinate - fresh++; //Change new's pointer to the next element - if(prev == next) { //If the address of our previous and next cell are the same... - /* start a new group of rows */ - if(*next == 0) { //If out next cell is the terminator - *fresh = 0; //Set the next state of the new board to the terminator state as well - fresh = start; - return; //We're done! - } - y = *next++ + 1; //Set out y coordinate to 1 plus next's current value, and increment next (which is sorted desc.) - } else { //If our previous and next cells are different - /* move to next row and work out which ones to scan */ - if(*prev == y--) //Increment prev's pointer if it's the same as our y (after decrementing it) plus 1 - prev++; - if(*current == y) //Increment this's pointer if it's the same as our y - current++; - if(*next == y-1) //Increment next's pointer if it's the same as our y minus 1 - next++; - } - /* write new row co-ordinate */ - *fresh = y; //Write the new row coordinate - for(;;) { //For each column (cell) - /* skip to the leftmost cell */ - x = *prev; //Set our (negative) x coordinate to the max of the current values of prev, this, and next - if(x > *current) - x = *current; - if(x > *next) - x = *next; - /* end of line? */ - if(x >= 0) //If x is non-negative, this is a y coordinate; we're at the end of the line; move on! - break; - for(;;) { //For each consecutive cell - /* add a column to the bitmap */ - if(*prev == x) { //If the previous row's cell (the one directly above us) is alive - bitmap |= 0100; //OR the bitmap with 001000000 (topright) - prev++; //Increment the previous row's pointer - } - if(*current == x) { //If the current row's cell is alive - bitmap |= 0200; //OR the bitmap with 010000000 (midright) - current++; //Increment the current row's pointer - } - if(*next == x) { //If the next row's cell (the one directly below us) is alive - bitmap |= 0400; //OR the bitmap with 100000000 (bottomright) - next++; //Increment the next row's pointer - } - /* what does this bitmap indicate? */ - if(state[bitmap] && !(y > height-3 || y < 3) && !((-x) > width-3 || (-x) < 3)) { //If our bitmap is now alive - *(++fresh) = x - 1; //Increment the cell pointer of our new board, and set the next value to the current x-coordinate minus 1 - can->drawPoint(-(x), y, fcolor); //Draw it - } - else if(bitmap == 000) //If our bitmap is now empty... - break; //No more consecutive living cells; move on to the next explicitly stored pointer - /* move right */ - bitmap >>= 3; //Shave off the the leftmost three bits to move our bitmap to the right - x += 1; //Increment our x coordinate - } - } - } -} From ae1ba0af42cdc279bd190c227fbd3216221659dc Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:39:42 -0400 Subject: [PATCH 063/105] Delete LifeFarm.h --- src/tests/Conway/LifeFarm.h | 100 ------------------------------------ 1 file changed, 100 deletions(-) delete mode 100644 src/tests/Conway/LifeFarm.h diff --git a/src/tests/Conway/LifeFarm.h b/src/tests/Conway/LifeFarm.h deleted file mode 100644 index 5ba61d841..000000000 --- a/src/tests/Conway/LifeFarm.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * LifeFarm.h - */ - -#ifndef ANTFARM_H_ -#define ANTFARM_H_ - -#include -#include - -using namespace tsgl; - -/*! - * \class LifeFarm - * \brief Simulate Conway's Game of Life! - * \details Contains the data and methods needed in order to simulate Conway's Game of Life. - * \details see https://en.wikipedia.org/wiki/Conway's_Game_of_Life for more details on what Conway's Game of Life is. - */ -class LifeFarm { -private: - void initGun(); - - unsigned framecount; - bool **alive; - int **neighbors; - int *livelist; - int liststart, listend; - bool drawdead; - ColorFloat bgcolor; - - int *currentstate, *nextstate; - int *currentstart, *nextstart; -public: - int width, height, size; - Canvas* can; - - /*! - * \brief Explicitly constructs a LifeFarm object. - * \details Explicit constructor for the LifeFarm class. - * \param w The width of the LifeFarm object. - * \param h The height of the LifeFarm object. - * \param can Pointer to the Canvas to draw to. - * \param randomize Determines if we should randomize the motion of the ants that are currently in the LifeFarm object. - */ - LifeFarm(int w, int h, Canvas* can, bool randomize); - - /*! - * \brief Destroy a LifeFarm object. - * \details Destructor for the LifeFarm class. - * \return Frees up any allocated memory to a LifeFarm object. - */ - ~LifeFarm(); - - /*! - * \brief Add an ant. - * \details Adds an ant to the LifeFarm object. - * \param x The x coordinate of the ant in the LifeFarm object. - * \param y The y coordinate of the ant in the LifeFarm object. - */ - void addAnt(int x, int y); - - /*! - * \brief Move the ants. - * \details Move the ants that are currently in the LifeFarm object. - * \note This method class moveAntsOld(). - * \see moveAntsOld() - */ - void moveAnts(); - - /*! - * \brief Move the ants. - * \details This method is called first in order to move the ants around in the LifeFarm object. - * \see moveAntsNew() - */ - void moveAntsOld(); - - /*! - * \brief Move the ants. - * \details This method moves the ants around to new positions. - * \see moveAntsOld() - */ - void moveAntsNew(); - - /*! - * \brief Draw "dead" ants. - * \details Determines if we should draw ants that have "died" in the game. - * \param b A boolean that determines if we should draw the dead ants or not. - */ - void setDrawdead(bool b); - - /*! - * \brief Give life to the ants! - * \details Makes the ants come alive by keeping track of their current positions and next state positions. - * \param *current A pointer to an array of current states that the ants are in during the game. - * \param *fresh A pointer to an array of next states that the ants are going to be in during the game. - */ - void life(int *current, int *fresh); -}; - -#endif /* ANTFARM_H_ */ From 9c363bcc75019ced41e4f8972baf0739ad208d71 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:41:28 -0400 Subject: [PATCH 064/105] Delete Fork.h --- src/tests/DiningPhilosophers/Fork.h | 53 ----------------------------- 1 file changed, 53 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/Fork.h diff --git a/src/tests/DiningPhilosophers/Fork.h b/src/tests/DiningPhilosophers/Fork.h deleted file mode 100644 index cffb1d9ad..000000000 --- a/src/tests/DiningPhilosophers/Fork.h +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * \struct Fork - * \brief Struct for the forks in the Dining Philosophers' problem - */ - -#ifndef FORK_H_ -#define FORK_H_ - -#include -using namespace tsgl; - -struct Fork { - int user, id; - ConcavePolygon * myShape; - Fork() { - user = -1; id = 0; - - const int POINTS = 20; // number of vertices in polygon - const float HEIGHT = 42; // 42 is preferred, but can be changed - const float WIDTH = 12; // 12 is preferred, but can be changed - float xs[POINTS], ys[POINTS]; - - // scales (out of 100) for the dimensions of the fork - float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; - float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; - - // create the fork points from the scale arrays - for(int i = 0; i < POINTS; ++i) { - // scale the fork - xs[i] = WIDTH * xscale[i]; - ys[i] = HEIGHT * yscale[i]; - // xs[i] = xs[i]/100; - // ys[i] = ys[i]/100; - } - - //Add vertices - myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,ColorFloat(1,1,1,1)); - } - void setCanvas( Canvas* can) { - can->add(myShape); - } - void draw(float x, float y, double angle, ColorFloat c) { - angle -= PI/2; - myShape->setColor(c); - myShape->setCenter(x, y, 0); - myShape->setYaw(angle*180/PI); - } - ~Fork() { - delete myShape; - } -}; - -#endif /* FORK_H_ */ \ No newline at end of file From 6f62a3ad2b59b3ca2c00382d1ad45e32b8516a1c Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:43:41 -0400 Subject: [PATCH 065/105] Delete Philosopher.cpp --- src/tests/DiningPhilosophers/Philosopher.cpp | 112 ------------------- 1 file changed, 112 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/Philosopher.cpp diff --git a/src/tests/DiningPhilosophers/Philosopher.cpp b/src/tests/DiningPhilosophers/Philosopher.cpp deleted file mode 100644 index 2e7dc6432..000000000 --- a/src/tests/DiningPhilosophers/Philosopher.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "Philosopher.h" - -/*! - * \brief Explicitly constructs a new Philosopher. - * \details Explicit constructor for a new Philosopher object. - */ -Philosopher::Philosopher() { - setId(0,1); - myState = thinking; - myAction = doNothing; - myCircle = NULL; - numMeals = 0; -} - -Philosopher::~Philosopher() { - delete myCircle; - for (RegularPolygon * meal : meals) - { - delete meal; - } - meals.clear(); -} - -/** - * Adds Philosopher to Canvas or refreshes its color. - */ -void Philosopher::draw(Canvas& can, float x, float y) { - const float SIZE = 45; - if( !myCircle) { - myCircle = new Circle(x,y,0,SIZE,0,0,0,ColorFloat(1,0,0,1)); - can.add(myCircle); - } -} - -/** - * Updates the Philosopher's color based on its state - */ -void Philosopher::refreshColor() { - ColorFloat c; - switch(myState) { - case hasNone: c=RED; break; - case hasRight: c=ORANGE; break; - case hasLeft: c=PURPLE; break; - case hasBoth: c=GREEN; break; - case isFull: c=BLUE; break; - case thinking: c=BLUE; break; - } - myCircle->setColor(c); -} - -/** - * Adds a meal representation to meals and the Canvas - */ -void Philosopher::addMeal(float x, float y, float z) { - numMeals++; - meals.push_back(new RegularPolygon(x,y,z,3,3,0,0,0,ColorFloat(0.5,0.3,0,1))); -} - -RegularPolygon * Philosopher::getLastMeal() { - return meals.back(); -} - -/** - * Picks up a fork specified by its reference - */ -bool Philosopher::acquire(Fork& f) { - if (f.user >= 0) - return false; - if (f.id == myLeft) { - if (myState == hasNone) - myState = hasLeft; - else if (myState == hasRight) - myState = hasBoth; - else - return false; - f.user = id; - return true; - } - if (f.id == myRight) { - if (myState == hasNone) - myState = hasRight; - else if (myState == hasLeft) - myState = hasBoth; - else - return false; - f.user = id; - return true; - } - return false; -} - -/** - * Releases a fork specified by its reference - */ -bool Philosopher::release(Fork& f) { - if (f.user != id) - return false; - if (myState != isFull) - myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; - f.user = -1; - return true; -} - -/** - * Thinks and switches to hungry state if a random number is a multiple of 3. - */ -void Philosopher::think() { - if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state - setState(hasNone); - setAction(doNothing); - } -} From b7985b046abffe1e7b65062be14b2683fbecd5ad Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:43:48 -0400 Subject: [PATCH 066/105] Delete philEnums.h --- src/tests/DiningPhilosophers/philEnums.h | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/philEnums.h diff --git a/src/tests/DiningPhilosophers/philEnums.h b/src/tests/DiningPhilosophers/philEnums.h deleted file mode 100644 index 17390208e..000000000 --- a/src/tests/DiningPhilosophers/philEnums.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PHIL_ENUM_H_ -#define PHIL_ENUM_H_ - -/*! \brief Enum for valid states for the Dining Philosophers - */ -enum PhilState { - hasNone, hasRight, hasLeft, hasBoth, isFull, thinking -}; - -/*! \brief Enum for valid actions for the Dining Philosophers - */ -enum PhilAction { - doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth -}; - -/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem - */ -enum PhilMethod { - forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven -}; - -#endif /* PHIL_ENUM_H_ */ \ No newline at end of file From 45ae4df2cb3cbbbe61df3822e8a5bfa7500e5a2e Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:43:55 -0400 Subject: [PATCH 067/105] Delete Philosopher.h --- src/tests/DiningPhilosophers/Philosopher.h | 82 ---------------------- 1 file changed, 82 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/Philosopher.h diff --git a/src/tests/DiningPhilosophers/Philosopher.h b/src/tests/DiningPhilosophers/Philosopher.h deleted file mode 100644 index 222a4b97e..000000000 --- a/src/tests/DiningPhilosophers/Philosopher.h +++ /dev/null @@ -1,82 +0,0 @@ -/*! - * \class Philosopher - * \brief Object representing a philosopher in the Dining Philosophers' problem - * \details The Philosopher class contains variables and methods necessary for - * representing a philosopher at a table. Each Philosopher may acquire or release - * the fork to his left or to his right (or both), with his state changing - * accordingly. - */ - -#ifndef PHILOSOPHER_H_ -#define PHILOSOPHER_H_ - -#include -#include -#include "Fork.h" -#include "philEnums.h" - -class Philosopher { -private: - PhilState myState; - PhilAction myAction; - int id, myLeft, myRight; - unsigned int numMeals; - Circle *myCircle; - std::vector meals; -public: - Philosopher(); - ~Philosopher(); - void draw(Canvas& can, float x, float y); - void refreshColor(); - void addMeal(float x, float y, float z); - RegularPolygon * getLastMeal(); - bool acquire(Fork& f); - bool release(Fork& f); - void think(); - - // Mutators - /*! - * \brief Resets the Philosopher to thinking after he eats. - */ - void eat() { myState = thinking; myAction = doNothing;} - /*! - * \brief Mutator for myState - * \param s PhilState to set myState to. - */ - void setState(PhilState s) { myState = s; } - /*! - * \brief Mutator for myAction - * \param s PhilAction to set myAction to. - */ - void setAction(PhilAction a) { myAction = a; } - /*! - * \brief Mutator for id - * \param i Which philosopher id to mutate - * \param nphil Total number of philosophers. - */ - void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } - - //Accessors - /** - * Accessor for number of meals Philosopher has consumed. - */ - int getMeals() { return numMeals; } - /** - * Accessor for Philosopher's state. - */ - PhilState state() { return myState; } - /** - * Accessor for Philosopher's action. - */ - PhilAction action() { return myAction; } - /** - * Accessor for Philosopher's id. - */ - int getId() { return id; } - /** - * Accessor for Philosopher's circle. - */ - bool hasCircle() { return myCircle; } -}; - -#endif /* PHILOSOPHER_H_ */ \ No newline at end of file From 94c4a77c0336b07ef33fed6f743930e213376fbb Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:44:03 -0400 Subject: [PATCH 068/105] Delete Table.cpp --- src/tests/DiningPhilosophers/Table.cpp | 525 ------------------------- 1 file changed, 525 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/Table.cpp diff --git a/src/tests/DiningPhilosophers/Table.cpp b/src/tests/DiningPhilosophers/Table.cpp deleted file mode 100644 index 9bd781750..000000000 --- a/src/tests/DiningPhilosophers/Table.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include "Table.h" - -/*! - * \brief Creates a new Table of dining philosophers. - * \details Explicit constructor for a new Table object. - * \param can The Canvas on which the Table is to be drawn. - * \param p Integer denoting the number of Philosophers at the Table - * \param m PhilMethod denoting how the Philosophers should interact. - */ -Table::Table(Canvas& can, int p, PhilMethod m) { - numPhils = p; - myCan = &can; - myTable = new Circle(0,0,-1,175,0,0,0,ColorFloat(0.5,0.5,0.5,1)); - can.add(myTable); - // can.drawCircle(0,0,1,ColorFloat(0.5,0.5,0.5,1)); - phils = new Philosopher[numPhils]; - forks = new Fork[numPhils]; - for (int i = 0; i < numPhils; ++i) { - phils[i].setId(i,numPhils); - forks[i].id = i; - forks[i].setCanvas(myCan); - } - spaghettis = new Image*[numPhils](); - float delta = 2.0f / numPhils * PI; - for(int i = 0; i < numPhils; i++) { - spaghettis[i] = new Image(120 * cos(i*delta), 140 * sin(i*delta), -0.5, "./assets/pics/spaghet.png", 100, 50, 0,0,0); - can.add(spaghettis[i]); - // myCan->drawImage("../assets/pics/spaghet.png", -50+(200)*cos(i*delta), -25+(215)*sin(i*delta), 100, 50, 1.0f); - } - myMethod = m; - switch(myMethod) { - case forfeitWhenBlocked: - methodString = L"forfeit when blocked"; - break; - case waitWhenBlocked: - methodString = L"wait when blocked"; - break; - case nFrameRelease: - methodString = L"release on nth frame"; - break; - case resourceHierarchy: - methodString = L"hierarchical resources"; - break; - case oddEven: - methodString = L"odd-even check"; - break; - default: - break; - } - - myCan2 = new Canvas(0,0,300,300,"Legend"); - myCan2->start(); - myCan2->setBackgroundColor(GRAY); - - legendTexts = new Text*[9](); - legendTexts[0] = new Text(-134,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); - legendTexts[0]->changeXBy(legendTexts[0]->getWidth() / 2); - myCan2->add(legendTexts[0]); - legendTexts[1] = new Text(-118,96,0,L"\"" + methodString + L"\"","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); - legendTexts[1]->changeXBy(legendTexts[1]->getWidth() / 2); - myCan2->add(legendTexts[1]); - legendTexts[2] = new Text(-134,64,0,L"Legend:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLACK); - legendTexts[2]->changeXBy(legendTexts[2]->getWidth() / 2); - myCan2->add(legendTexts[2]); - legendTexts[3] = new Text(-118,32,0,L"Red: Hungry","./assets/freefont/FreeSerif.ttf",24,0,0,0,RED); - legendTexts[3]->changeXBy(legendTexts[3]->getWidth() / 2); - myCan2->add(legendTexts[3]); - legendTexts[4] = new Text(-118,0,0,L"Orange: Has Right Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,ORANGE); - legendTexts[4]->changeXBy(legendTexts[4]->getWidth() / 2); - myCan2->add(legendTexts[4]); - legendTexts[5] = new Text(-118,-32,0,L"Yellow: Has Left Fork","./assets/freefont/FreeSerif.ttf",24,0,0,0,YELLOW); - legendTexts[5]->changeXBy(legendTexts[5]->getWidth() / 2); - myCan2->add(legendTexts[5]); - legendTexts[6] = new Text(-118,-64,0,L"Green: Eating","./assets/freefont/FreeSerif.ttf",24,0,0,0,GREEN); - legendTexts[6]->changeXBy(legendTexts[6]->getWidth() / 2); - myCan2->add(legendTexts[6]); - legendTexts[7] = new Text(-118,-96,0,L"Blue: Thinking","./assets/freefont/FreeSerif.ttf",24,0,0,0,BLUE); - legendTexts[7]->changeXBy(legendTexts[7]->getWidth() / 2); - myCan2->add(legendTexts[7]); - legendTexts[8] = new Text(-118,-121,0,L"Meals eaten:","./assets/freefont/FreeSerif.ttf",24,0,0,0,BROWN); - legendTexts[8]->changeXBy(legendTexts[8]->getWidth() / 2); - myCan2->add(legendTexts[8]); - - exampleMeal = new RegularPolygon(15, -121,0,3,3,0,0,0, BROWN); - myCan2->add(exampleMeal); -} - -/*! - * \brief Destructor for Table. - */ -Table::~Table() { - if (myCan2->isOpen()) - myCan2->stop(); - delete myCan2; - for (int i = 0; i < 9; i++) { - delete legendTexts[i]; - } - delete[] legendTexts; - delete exampleMeal; - for (int i = 0; i < numPhils; i++) { - delete spaghettis[i]; - } - delete [] spaghettis; - delete myTable; - delete [] phils; - delete [] forks; -} - - /*! - * \brief Method for determining which fork a Philosopher should get. - * \details - * - Store the id numbers for the left and the right Philsopher's state. - * - Switch for the state of a Philosopher: - * - Philosopher has no fork: - * - If the right fork is free, try to get that fork. - * - Else, if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher has right fork: - * - If the left fork is free, try to get that fork. - * . - * - Philosopher has the left fork: - * - If the right fork is free, try to get that fork. - * - Else, release the left fork. - * . - * - Philosopher has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher. - * \note This is an example of Deadlock amongst threads. - */ -void Table::forfeitWhenBlockedMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(releaseRight); - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(releaseLeft); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].setState(hasNone); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher should get. - * \details - * - Store the states of the left and right Philosophers. - * - Switch for the state of the current Philosopher: - * - Philosopher has no forks: - * - If the right fork is free, try to get that fork. - * - Else if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher has right fork: - * - If the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher has the left fork: - * - If the right fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher. - * \note This is an example of Livelock amongst threads. - */ -void Table::waitWhenBlockedMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher should get. - * \details - * - Store the states of the left and right Philosophers. - * - Switch statement for the current Philosopher: - * - Philosopher has no forks: - * - If the right fork is free, try to get that fork. - * - Else, if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher has right fork: - * - If the left fork is free, try to get that fork. - * - Else, if the id of the current Philosopher is equal to the frame number of the Canvas - * modulo the number of Philosophers+1, then release the right fork. - * - Else, do nothing. - * . - * - Philosopher has the left fork: - * - If the right fork is free, try and get that fork. - * - Else, if the id of the current Philosopher is equal to the frame number of the Canvas - * modulo the number of Philosophers+1, then release the left fork. - * - Else, do nothing. - * . - * - Philosopher has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher. - */ -void Table::nFrameReleaseMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else { - if (id == (myCan->getFrameNumber() % numPhils+1)) - phils[id].setAction(releaseRight); - else - phils[id].setAction(doNothing); - } - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else { - if (id == (myCan->getFrameNumber() % numPhils+1)) - phils[id].setAction(releaseLeft); - else - phils[id].setAction(doNothing); - } - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher should get. - * \details - * - Store the states for the left and right Philosophers. - * - Switch statement for the state of the current Philosopher. - * - Philosopher has no forks: - * - If the right Philosopher's id is less than the left Philsopher's id: - * - If the right fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Else, if the left fork is free then try and get that fork. - * - Else, do nothing. - * . - * - Philosopher has the right fork: - * - If the left fork is free, try and get that fork. - * - Else, do nothing. - * . - * - Philosopher has the left fork: - * - If the right fork is free, try and get that fork. - * - Else, do nothing. - * . - * - Philosopher has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher. - */ -void Table::hierarchyMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (right < left) { - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - } else { - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - } - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else { - phils[id].setAction(doNothing); - } - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher should get. - * \details - * - Switch statement for the current Philosopher: - * - Philosopher has no forks: - * - If the Philosopher's id is even - * - Philosopher has right fork (odd id): - * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number - * modulo 2, then try and get the left fork. - * - Else, release the right fork. - * . - * - Philosopher has left fork (even id): - * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number - * modulo 2, then try and get the right fork. - * - Else, release the left fork. - * . - * - Philosopher has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher. - * \note This method is the one that works best. - */ -void Table::oddEvenMethod(int id) { - switch(phils[id].state()) { - case hasNone: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryBoth); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryLeft); - else { - phils[id].setAction(releaseRight); - } - break; - case hasLeft: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryRight); - else - phils[id].setAction(releaseLeft); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - -/*! - * \brief Method for determining which method of resolution the philosopher is using. - */ -void Table::checkStep() { - int i = omp_get_thread_num(); - if (phils[i].state() == isFull) { - phils[i].eat(); - return; - } - switch(myMethod) { - case forfeitWhenBlocked: - forfeitWhenBlockedMethod(i); - break; - case waitWhenBlocked: - waitWhenBlockedMethod(i); - break; - case nFrameRelease: - nFrameReleaseMethod(i); - break; - case resourceHierarchy: - hierarchyMethod(i); - break; - case oddEven: - oddEvenMethod(i); - break; - default: - break; - } -} - -/*! - * \brief Method for philosopher to act based on myAction. - */ -void Table::actStep() { - // myCan2->sleep(); - int i = omp_get_thread_num(); - int left = i, right = (i+numPhils-1)%numPhils; - switch(phils[i].action()) { - case tryLeft: - phils[i].acquire(forks[left]); - break; - case tryRight: - phils[i].acquire(forks[right]); - break; - case tryBoth: - phils[i].acquire(forks[left]); - phils[i].acquire(forks[right]); - break; - case releaseLeft: - phils[i].release(forks[left]); - break; - case releaseRight: - phils[i].release(forks[right]); - break; - case releaseBoth: - phils[i].release(forks[left]); - phils[i].release(forks[right]); - break; - default: - break; - } -} - -/*! - * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. - */ -void Table::drawStep() { - const float RAD = 225; - float FORK_RAD = 175; - const float ARC =2*PI/numPhils; - const float CLOSE = 0.15f; - const float BASEDIST = RAD+54; - - int i = omp_get_thread_num(); - float pangle = (i*2*PI)/numPhils; - ColorFloat fcolor = ColorFloat(1,1,1,1); - float fangle = (i+0.5f)*ARC; - - if( !phils[i].hasCircle() ) { - phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); - } - - phils[i].refreshColor(); - if( phils[i].state() == isFull ) { - int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/(RAD), dist = BASEDIST+8*(meals%10); - // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); - phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); - myCan->add(phils[i].getLastMeal()); - } - if (forks[i].user == i) { - fangle = i*ARC + CLOSE; - fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; - } - else if((forks[i].user == (i+1)%numPhils)) { - fangle = ((i+1)*ARC) - CLOSE; - fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; - } else { - FORK_RAD = 140; - fangle = pangle + PI / numPhils; - } - forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); -} \ No newline at end of file From fc0e37f207f5385da2de46054d86bbe15dc4aca8 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:44:09 -0400 Subject: [PATCH 069/105] Delete Table.h --- src/tests/DiningPhilosophers/Table.h | 58 ---------------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/tests/DiningPhilosophers/Table.h diff --git a/src/tests/DiningPhilosophers/Table.h b/src/tests/DiningPhilosophers/Table.h deleted file mode 100644 index c6ec53f5e..000000000 --- a/src/tests/DiningPhilosophers/Table.h +++ /dev/null @@ -1,58 +0,0 @@ -/*! - * \class Table - * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. - * \details The Table class keeps track of the forks and philosophers in the Dining - * Philosophers' problem; it additionally manages the actions of the philosophers. - * \details Each step of the problem is broken up into two phases. In the checking phase, - * the philosophers look at the table around them and, without communicating with the - * other philosophers, determine an action to take based on their state and the states - * of their adjacent forks. - * \details In the action phase, each philosopher attempts to execute the action previously - * determined in the checking phase. If unsuccessful, the philosopher does nothing; - * otherwise, the philosopher's state changes depending on the action taken. - */ - -#ifndef TABLE_H_ -#define TABLE_H_ - -#include -#include "Philosopher.h" - -using namespace tsgl; - -class Table { -private: - int numPhils; - PhilMethod myMethod; - std::wstring methodString; - Canvas *myCan, *myCan2; - Philosopher *phils; - Fork *forks; - Circle * myTable; - Image ** spaghettis; - Text ** legendTexts; - RegularPolygon * exampleMeal; - // TextureHandler loader; -public: - Table(Canvas& can, int p, PhilMethod m); - - ~Table(); - - void forfeitWhenBlockedMethod(int id); - - void waitWhenBlockedMethod(int id); - - void nFrameReleaseMethod(int id); - - void hierarchyMethod(int id); - - void oddEvenMethod(int id); - - void checkStep(); - - void actStep(); - - void drawStep(); -}; - -#endif /* TABLE_H_ */ \ No newline at end of file From 49e3c24e69e8ff1bc316f5fc04f29b36d1ae68c1 Mon Sep 17 00:00:00 2001 From: "U-CALVINAD\\zc26" Date: Mon, 27 Jul 2020 14:48:45 -0400 Subject: [PATCH 070/105] Remove directory with excess files --- src/tests/DiningPhilosophers3D/Fork3D.h | 53 -- .../DiningPhilosophers3D/Philosopher3D.cpp | 120 ----- .../DiningPhilosophers3D/Philosopher3D.h | 83 --- src/tests/DiningPhilosophers3D/Table3D.cpp | 489 ------------------ src/tests/DiningPhilosophers3D/Table3D.h | 55 -- src/tests/DiningPhilosophers3D/philEnums.h | 22 - src/tests/Fireworks/Arc.cpp | 108 ---- src/tests/Fireworks/Arc.h | 43 -- src/tests/Fireworks/Dot.cpp | 45 -- src/tests/Fireworks/Dot.h | 25 - src/tests/Fireworks/Firework.cpp | 57 -- src/tests/Fireworks/Firework.h | 29 -- src/tests/ImageInverter/ImageInverter.cpp | 56 -- src/tests/ImageInverter/ImageInverter.h | 79 --- src/tests/Langton/AntFarm.cpp | 72 --- src/tests/Langton/AntFarm.h | 86 --- src/tests/Langton/LangtonAnt.cpp | 47 -- src/tests/Langton/LangtonAnt.h | 84 --- src/tests/Makefile | 82 --- src/tests/Mandelbrot/Buddhabrot.cpp | 109 ---- src/tests/Mandelbrot/Buddhabrot.h | 55 -- src/tests/Mandelbrot/GradientMandelbrot.cpp | 43 -- src/tests/Mandelbrot/GradientMandelbrot.h | 43 -- src/tests/Mandelbrot/Julia.cpp | 59 --- src/tests/Mandelbrot/Julia.h | 41 -- src/tests/Mandelbrot/Mandelbrot.cpp | 161 ------ src/tests/Mandelbrot/Mandelbrot.h | 85 --- src/tests/Mandelbrot/Nova.cpp | 53 -- src/tests/Mandelbrot/Nova.h | 42 -- src/tests/Pong/Ball.cpp | 84 --- src/tests/Pong/Ball.h | 46 -- src/tests/Pong/Paddle.cpp | 86 --- src/tests/Pong/Paddle.h | 57 -- src/tests/Pong/Pong.cpp | 84 --- src/tests/Pong/Pong.h | 44 -- src/tests/ProducerConsumer/Consumer.cpp | 81 --- src/tests/ProducerConsumer/Consumer.h | 28 - src/tests/ProducerConsumer/PCThread.cpp | 88 ---- src/tests/ProducerConsumer/PCThread.h | 42 -- src/tests/ProducerConsumer/Producer.cpp | 102 ---- src/tests/ProducerConsumer/Producer.h | 33 -- src/tests/ProducerConsumer/Queue.h | 289 ----------- src/tests/ProducerConsumer/Thread.cpp | 53 -- src/tests/ProducerConsumer/Thread.h | 35 -- src/tests/ReaderWriter/FLock.cpp | 55 -- src/tests/ReaderWriter/FLock.h | 37 -- src/tests/ReaderWriter/Lock.cpp | 29 -- src/tests/ReaderWriter/Lock.h | 39 -- src/tests/ReaderWriter/RLock.cpp | 67 --- src/tests/ReaderWriter/RLock.h | 30 -- src/tests/ReaderWriter/RWDatabase.h | 85 --- src/tests/ReaderWriter/RWThread.cpp | 65 --- src/tests/ReaderWriter/RWThread.h | 46 -- src/tests/ReaderWriter/Reader.cpp | 71 --- src/tests/ReaderWriter/Reader.h | 32 -- src/tests/ReaderWriter/Thread.cpp | 53 -- src/tests/ReaderWriter/Thread.h | 37 -- src/tests/ReaderWriter/WLock.cpp | 66 --- src/tests/ReaderWriter/WLock.h | 28 - src/tests/ReaderWriter/Writer.cpp | 118 ----- src/tests/ReaderWriter/Writer.h | 38 -- src/tests/SeaUrchin/SeaUrchin.cpp | 33 -- src/tests/SeaUrchin/SeaUrchin.h | 56 -- src/tests/Voronoi/ShadedVoronoi.cpp | 63 --- src/tests/Voronoi/ShadedVoronoi.h | 46 -- src/tests/Voronoi/Voronoi.cpp | 65 --- src/tests/Voronoi/Voronoi.h | 56 -- src/tests/test2Dvs3D.cpp | 97 ---- src/tests/test2Dvs3D/Makefile | 63 --- src/tests/test2Dvs3D/test2Dvs3D.cpp | 96 ---- src/tests/test3DPhilosophers.cpp | 107 ---- src/tests/test3DRotation.cpp | 49 -- src/tests/test3DRotation/Makefile | 63 --- src/tests/test3DRotation/test3DRotation.cpp | 48 -- src/tests/testAlphaRectangle.cpp | 49 -- src/tests/testAlphaRectangle/Makefile | 63 --- .../testAlphaRectangle/testAlphaRectangle.cpp | 49 -- src/tests/testArrows.cpp | 51 -- src/tests/testArrows/Makefile | 63 --- src/tests/testArrows/testArrows.cpp | 51 -- src/tests/testAura.cpp | 112 ---- src/tests/testAura/Makefile | 63 --- src/tests/testAura/testAura.cpp | 111 ---- src/tests/testBG.cpp | 37 -- src/tests/testBackground.cpp | 110 ---- src/tests/testBackground/Makefile | 63 --- src/tests/testBackground/testBackground.cpp | 70 --- src/tests/testBallroom.cpp | 319 ------------ src/tests/testBlurImage.cpp | 62 --- src/tests/testBlurImage/Makefile | 63 --- src/tests/testBlurImage/testBlurImage.cpp | 62 --- src/tests/testCalcPi.cpp | 76 --- src/tests/testCalcPi/Makefile | 63 --- src/tests/testCalcPi/testCalcPi.cpp | 76 --- src/tests/testCircle.cpp | 68 --- src/tests/testCircle/Makefile | 63 --- src/tests/testCircle/testCircle.cpp | 67 --- src/tests/testClock.cpp | 108 ---- src/tests/testColorWheel.cpp | 75 --- src/tests/testColorWheel/Makefile | 63 --- src/tests/testColorWheel/testColorWheel.cpp | 75 --- src/tests/testConcavePolygon.cpp | 92 ---- src/tests/testConcavePolygon/Makefile | 63 --- .../testConcavePolygon/testConcavePolygon.cpp | 91 ---- src/tests/testCone.cpp | 89 ---- src/tests/testCone/Makefile | 63 --- src/tests/testCone/testCone.cpp | 88 ---- src/tests/testConstructors.cpp | 305 ----------- src/tests/testConstructors/Makefile | 63 --- .../testConstructors/testConstructors.cpp | 304 ----------- src/tests/testConvexPolygon.cpp | 58 --- src/tests/testConvexPolygon/Makefile | 63 --- .../testConvexPolygon/testConvexPolygon.cpp | 57 -- src/tests/testConway.cpp | 90 ---- src/tests/testCosineIntegral.cpp | 85 --- src/tests/testCosineIntegral/Makefile | 63 --- .../testCosineIntegral/testCosineIntegral.cpp | 84 --- src/tests/testCube.cpp | 81 --- src/tests/testCube/Makefile | 63 --- src/tests/testCube/testCube.cpp | 80 --- src/tests/testCuboid.cpp | 86 --- src/tests/testCuboid/Makefile | 63 --- src/tests/testCuboid/testCuboid.cpp | 85 --- src/tests/testCylinder.cpp | 76 --- src/tests/testCylinder/Makefile | 63 --- src/tests/testCylinder/testCylinder.cpp | 75 --- src/tests/testDice.cpp | 180 ------- src/tests/testDice/Makefile | 63 --- src/tests/testDice/testDice.cpp | 179 ------- src/tests/testDiorama.cpp | 119 ----- src/tests/testDiorama/Makefile | 63 --- src/tests/testDiorama/testDiorama.cpp | 118 ----- src/tests/testEllipse.cpp | 72 --- src/tests/testEllipse/Makefile | 63 --- src/tests/testEllipse/testEllipse.cpp | 71 --- src/tests/testEllipsoid.cpp | 113 ---- src/tests/testEllipsoid/Makefile | 63 --- src/tests/testEllipsoid/testEllipsoid.cpp | 112 ---- src/tests/testFireworks.cpp | 60 --- src/tests/testForestFire.cpp | 144 ------ src/tests/testFunction.cpp | 52 -- src/tests/testFunction/Makefile | 63 --- src/tests/testFunction/testFunction.cpp | 51 -- src/tests/testGetPixels.cpp | 62 --- src/tests/testGetPixels/Makefile | 63 --- src/tests/testGetPixels/testGetPixels.cpp | 62 --- src/tests/testGradientWheel.cpp | 66 --- src/tests/testGradientWheel/Makefile | 63 --- .../testGradientWheel/testGradientWheel.cpp | 65 --- src/tests/testGraydient.cpp | 52 -- src/tests/testGraydient/Makefile | 63 --- src/tests/testGraydient/testGraydient.cpp | 52 -- src/tests/testGreyscale.cpp | 86 --- src/tests/testGreyscale/Makefile | 63 --- src/tests/testGreyscale/testGreyscale.cpp | 86 --- src/tests/testHighData.cpp | 54 -- src/tests/testHighData/Makefile | 63 --- src/tests/testHighData/testHighData.cpp | 54 -- src/tests/testImage.cpp | 102 ---- src/tests/testImage/Makefile | 63 --- src/tests/testImage/testImage.cpp | 101 ---- src/tests/testImageCart.cpp | 37 -- src/tests/testImageCart/Makefile | 63 --- src/tests/testImageCart/testImageCart.cpp | 37 -- src/tests/testInverter.cpp | 16 - src/tests/testInverter/ImageInverter.cpp | 56 -- src/tests/testInverter/ImageInverter.h | 79 --- src/tests/testInverter/Makefile | 63 --- src/tests/testInverter/testInverter.cpp | 16 - src/tests/testLangton.cpp | 185 ------- src/tests/testLineChain.cpp | 83 --- src/tests/testLineChain/Makefile | 63 --- src/tests/testLineChain/testLineChain.cpp | 82 --- src/tests/testLineFan.cpp | 66 --- src/tests/testLineFan/Makefile | 63 --- src/tests/testLineFan/testLineFan.cpp | 66 --- src/tests/testLines.cpp | 67 --- src/tests/testLines/Makefile | 63 --- src/tests/testLines/testLines.cpp | 67 --- src/tests/testMandelbrot.cpp | 224 -------- src/tests/testMergeSort.cpp | 204 -------- src/tests/testMouse.cpp | 104 ---- src/tests/testMouse/Makefile | 63 --- src/tests/testMouse/testMouse.cpp | 103 ---- src/tests/testNewtonPendulum.cpp | 134 ----- src/tests/testPhilosophers.cpp | 107 ---- src/tests/testPixels/Makefile | 63 --- src/tests/testPixels/testPixels.cpp | 103 ---- src/tests/testPong.cpp | 73 --- src/tests/testPrism.cpp | 85 --- src/tests/testPrism/Makefile | 63 --- src/tests/testPrism/testPrism.cpp | 84 --- src/tests/testProcedural/Makefile | 63 --- src/tests/testProcedural/testProcedural.cpp | 125 ----- src/tests/testProducerConsumer.cpp | 172 ------ src/tests/testProgressBar.cpp | 58 --- src/tests/testProgressBar/Makefile | 63 --- src/tests/testProgressBar/testProgressBar.cpp | 58 --- src/tests/testProjectiles.cpp | 122 ----- src/tests/testProjectiles/Makefile | 63 --- src/tests/testProjectiles/testProjectiles.cpp | 121 ----- src/tests/testPyramid.cpp | 79 --- src/tests/testPyramid/Makefile | 63 --- src/tests/testPyramid/testPyramid.cpp | 78 --- src/tests/testReaderWriter.cpp | 137 ----- src/tests/testRectangle.cpp | 69 --- src/tests/testRectangle/Makefile | 63 --- src/tests/testRectangle/testRectangle.cpp | 68 --- src/tests/testRegularPolygon.cpp | 64 --- src/tests/testRegularPolygon/Makefile | 63 --- .../testRegularPolygon/testRegularPolygon.cpp | 63 --- src/tests/testScreenshot.cpp | 54 -- src/tests/testScreenshot/Makefile | 63 --- src/tests/testScreenshot/testScreenshot.cpp | 54 -- src/tests/testSeaUrchin.cpp | 65 --- src/tests/testShakerSort.cpp | 116 ----- src/tests/testSolarSystem.cpp | 76 --- src/tests/testSpectrogram.cpp | 85 --- src/tests/testSpectrogram/Makefile | 63 --- src/tests/testSpectrogram/testSpectrogram.cpp | 85 --- src/tests/testSpectrum.cpp | 61 --- src/tests/testSpectrum/Makefile | 63 --- src/tests/testSpectrum/testSpectrum.cpp | 61 --- src/tests/testSphere.cpp | 81 --- src/tests/testSphere/Makefile | 63 --- src/tests/testSphere/testSphere.cpp | 80 --- src/tests/testSquare.cpp | 67 --- src/tests/testSquare/Makefile | 63 --- src/tests/testSquare/testSquare.cpp | 66 --- src/tests/testStar.cpp | 52 -- src/tests/testStar/Makefile | 63 --- src/tests/testStar/testStar.cpp | 52 -- src/tests/testText.cpp | 78 --- src/tests/testText/Makefile | 63 --- src/tests/testText/testText.cpp | 78 --- src/tests/testTextCart.cpp | 41 -- src/tests/testTextCart/Makefile | 63 --- src/tests/testTextCart/testTextCart.cpp | 41 -- src/tests/testTextTwo.cpp | 41 -- src/tests/testTextTwo/Makefile | 63 --- src/tests/testTextTwo/testTextTwo.cpp | 41 -- src/tests/testTransparency.cpp | 32 -- src/tests/testTransparency/Makefile | 63 --- .../testTransparency/testTransparency.cpp | 31 -- src/tests/testTriangle.cpp | 60 --- src/tests/testTriangle/Makefile | 63 --- src/tests/testTriangle/testTriangle.cpp | 59 --- src/tests/testTriangleStrip.cpp | 61 --- src/tests/testTriangleStrip/Makefile | 63 --- .../testTriangleStrip/testTriangleStrip.cpp | 60 --- src/tests/testUnits.cpp | 27 - src/tests/testUnits/Makefile | 63 --- src/tests/testUnits/testUnits.cpp | 27 - src/tests/testVoronoi.cpp | 101 ---- src/tests/test_specs.cpp | 31 -- src/tests/test_specs/Makefile | 63 --- src/tests/test_specs/test_specs.cpp | 31 -- 257 files changed, 19435 deletions(-) delete mode 100644 src/tests/DiningPhilosophers3D/Fork3D.h delete mode 100644 src/tests/DiningPhilosophers3D/Philosopher3D.cpp delete mode 100644 src/tests/DiningPhilosophers3D/Philosopher3D.h delete mode 100644 src/tests/DiningPhilosophers3D/Table3D.cpp delete mode 100644 src/tests/DiningPhilosophers3D/Table3D.h delete mode 100644 src/tests/DiningPhilosophers3D/philEnums.h delete mode 100644 src/tests/Fireworks/Arc.cpp delete mode 100644 src/tests/Fireworks/Arc.h delete mode 100644 src/tests/Fireworks/Dot.cpp delete mode 100644 src/tests/Fireworks/Dot.h delete mode 100644 src/tests/Fireworks/Firework.cpp delete mode 100644 src/tests/Fireworks/Firework.h delete mode 100644 src/tests/ImageInverter/ImageInverter.cpp delete mode 100644 src/tests/ImageInverter/ImageInverter.h delete mode 100644 src/tests/Langton/AntFarm.cpp delete mode 100644 src/tests/Langton/AntFarm.h delete mode 100644 src/tests/Langton/LangtonAnt.cpp delete mode 100644 src/tests/Langton/LangtonAnt.h delete mode 100644 src/tests/Makefile delete mode 100644 src/tests/Mandelbrot/Buddhabrot.cpp delete mode 100644 src/tests/Mandelbrot/Buddhabrot.h delete mode 100644 src/tests/Mandelbrot/GradientMandelbrot.cpp delete mode 100644 src/tests/Mandelbrot/GradientMandelbrot.h delete mode 100644 src/tests/Mandelbrot/Julia.cpp delete mode 100644 src/tests/Mandelbrot/Julia.h delete mode 100644 src/tests/Mandelbrot/Mandelbrot.cpp delete mode 100644 src/tests/Mandelbrot/Mandelbrot.h delete mode 100644 src/tests/Mandelbrot/Nova.cpp delete mode 100644 src/tests/Mandelbrot/Nova.h delete mode 100644 src/tests/Pong/Ball.cpp delete mode 100644 src/tests/Pong/Ball.h delete mode 100644 src/tests/Pong/Paddle.cpp delete mode 100644 src/tests/Pong/Paddle.h delete mode 100644 src/tests/Pong/Pong.cpp delete mode 100644 src/tests/Pong/Pong.h delete mode 100644 src/tests/ProducerConsumer/Consumer.cpp delete mode 100644 src/tests/ProducerConsumer/Consumer.h delete mode 100644 src/tests/ProducerConsumer/PCThread.cpp delete mode 100644 src/tests/ProducerConsumer/PCThread.h delete mode 100644 src/tests/ProducerConsumer/Producer.cpp delete mode 100644 src/tests/ProducerConsumer/Producer.h delete mode 100644 src/tests/ProducerConsumer/Queue.h delete mode 100644 src/tests/ProducerConsumer/Thread.cpp delete mode 100644 src/tests/ProducerConsumer/Thread.h delete mode 100644 src/tests/ReaderWriter/FLock.cpp delete mode 100644 src/tests/ReaderWriter/FLock.h delete mode 100644 src/tests/ReaderWriter/Lock.cpp delete mode 100644 src/tests/ReaderWriter/Lock.h delete mode 100644 src/tests/ReaderWriter/RLock.cpp delete mode 100644 src/tests/ReaderWriter/RLock.h delete mode 100644 src/tests/ReaderWriter/RWDatabase.h delete mode 100644 src/tests/ReaderWriter/RWThread.cpp delete mode 100644 src/tests/ReaderWriter/RWThread.h delete mode 100644 src/tests/ReaderWriter/Reader.cpp delete mode 100644 src/tests/ReaderWriter/Reader.h delete mode 100644 src/tests/ReaderWriter/Thread.cpp delete mode 100644 src/tests/ReaderWriter/Thread.h delete mode 100644 src/tests/ReaderWriter/WLock.cpp delete mode 100644 src/tests/ReaderWriter/WLock.h delete mode 100644 src/tests/ReaderWriter/Writer.cpp delete mode 100644 src/tests/ReaderWriter/Writer.h delete mode 100644 src/tests/SeaUrchin/SeaUrchin.cpp delete mode 100644 src/tests/SeaUrchin/SeaUrchin.h delete mode 100644 src/tests/Voronoi/ShadedVoronoi.cpp delete mode 100644 src/tests/Voronoi/ShadedVoronoi.h delete mode 100644 src/tests/Voronoi/Voronoi.cpp delete mode 100644 src/tests/Voronoi/Voronoi.h delete mode 100644 src/tests/test2Dvs3D.cpp delete mode 100644 src/tests/test2Dvs3D/Makefile delete mode 100644 src/tests/test2Dvs3D/test2Dvs3D.cpp delete mode 100644 src/tests/test3DPhilosophers.cpp delete mode 100644 src/tests/test3DRotation.cpp delete mode 100644 src/tests/test3DRotation/Makefile delete mode 100644 src/tests/test3DRotation/test3DRotation.cpp delete mode 100644 src/tests/testAlphaRectangle.cpp delete mode 100644 src/tests/testAlphaRectangle/Makefile delete mode 100644 src/tests/testAlphaRectangle/testAlphaRectangle.cpp delete mode 100644 src/tests/testArrows.cpp delete mode 100644 src/tests/testArrows/Makefile delete mode 100644 src/tests/testArrows/testArrows.cpp delete mode 100644 src/tests/testAura.cpp delete mode 100644 src/tests/testAura/Makefile delete mode 100644 src/tests/testAura/testAura.cpp delete mode 100644 src/tests/testBG.cpp delete mode 100644 src/tests/testBackground.cpp delete mode 100644 src/tests/testBackground/Makefile delete mode 100644 src/tests/testBackground/testBackground.cpp delete mode 100644 src/tests/testBallroom.cpp delete mode 100644 src/tests/testBlurImage.cpp delete mode 100644 src/tests/testBlurImage/Makefile delete mode 100644 src/tests/testBlurImage/testBlurImage.cpp delete mode 100644 src/tests/testCalcPi.cpp delete mode 100644 src/tests/testCalcPi/Makefile delete mode 100644 src/tests/testCalcPi/testCalcPi.cpp delete mode 100644 src/tests/testCircle.cpp delete mode 100644 src/tests/testCircle/Makefile delete mode 100644 src/tests/testCircle/testCircle.cpp delete mode 100644 src/tests/testClock.cpp delete mode 100644 src/tests/testColorWheel.cpp delete mode 100644 src/tests/testColorWheel/Makefile delete mode 100644 src/tests/testColorWheel/testColorWheel.cpp delete mode 100644 src/tests/testConcavePolygon.cpp delete mode 100644 src/tests/testConcavePolygon/Makefile delete mode 100644 src/tests/testConcavePolygon/testConcavePolygon.cpp delete mode 100644 src/tests/testCone.cpp delete mode 100644 src/tests/testCone/Makefile delete mode 100644 src/tests/testCone/testCone.cpp delete mode 100644 src/tests/testConstructors.cpp delete mode 100644 src/tests/testConstructors/Makefile delete mode 100644 src/tests/testConstructors/testConstructors.cpp delete mode 100644 src/tests/testConvexPolygon.cpp delete mode 100644 src/tests/testConvexPolygon/Makefile delete mode 100644 src/tests/testConvexPolygon/testConvexPolygon.cpp delete mode 100644 src/tests/testConway.cpp delete mode 100644 src/tests/testCosineIntegral.cpp delete mode 100644 src/tests/testCosineIntegral/Makefile delete mode 100644 src/tests/testCosineIntegral/testCosineIntegral.cpp delete mode 100644 src/tests/testCube.cpp delete mode 100644 src/tests/testCube/Makefile delete mode 100644 src/tests/testCube/testCube.cpp delete mode 100644 src/tests/testCuboid.cpp delete mode 100644 src/tests/testCuboid/Makefile delete mode 100644 src/tests/testCuboid/testCuboid.cpp delete mode 100644 src/tests/testCylinder.cpp delete mode 100644 src/tests/testCylinder/Makefile delete mode 100644 src/tests/testCylinder/testCylinder.cpp delete mode 100644 src/tests/testDice.cpp delete mode 100644 src/tests/testDice/Makefile delete mode 100644 src/tests/testDice/testDice.cpp delete mode 100644 src/tests/testDiorama.cpp delete mode 100644 src/tests/testDiorama/Makefile delete mode 100644 src/tests/testDiorama/testDiorama.cpp delete mode 100644 src/tests/testEllipse.cpp delete mode 100644 src/tests/testEllipse/Makefile delete mode 100644 src/tests/testEllipse/testEllipse.cpp delete mode 100644 src/tests/testEllipsoid.cpp delete mode 100644 src/tests/testEllipsoid/Makefile delete mode 100644 src/tests/testEllipsoid/testEllipsoid.cpp delete mode 100644 src/tests/testFireworks.cpp delete mode 100644 src/tests/testForestFire.cpp delete mode 100644 src/tests/testFunction.cpp delete mode 100644 src/tests/testFunction/Makefile delete mode 100644 src/tests/testFunction/testFunction.cpp delete mode 100644 src/tests/testGetPixels.cpp delete mode 100644 src/tests/testGetPixels/Makefile delete mode 100644 src/tests/testGetPixels/testGetPixels.cpp delete mode 100644 src/tests/testGradientWheel.cpp delete mode 100644 src/tests/testGradientWheel/Makefile delete mode 100644 src/tests/testGradientWheel/testGradientWheel.cpp delete mode 100644 src/tests/testGraydient.cpp delete mode 100644 src/tests/testGraydient/Makefile delete mode 100644 src/tests/testGraydient/testGraydient.cpp delete mode 100644 src/tests/testGreyscale.cpp delete mode 100644 src/tests/testGreyscale/Makefile delete mode 100644 src/tests/testGreyscale/testGreyscale.cpp delete mode 100644 src/tests/testHighData.cpp delete mode 100644 src/tests/testHighData/Makefile delete mode 100644 src/tests/testHighData/testHighData.cpp delete mode 100644 src/tests/testImage.cpp delete mode 100644 src/tests/testImage/Makefile delete mode 100644 src/tests/testImage/testImage.cpp delete mode 100644 src/tests/testImageCart.cpp delete mode 100644 src/tests/testImageCart/Makefile delete mode 100644 src/tests/testImageCart/testImageCart.cpp delete mode 100644 src/tests/testInverter.cpp delete mode 100644 src/tests/testInverter/ImageInverter.cpp delete mode 100644 src/tests/testInverter/ImageInverter.h delete mode 100644 src/tests/testInverter/Makefile delete mode 100644 src/tests/testInverter/testInverter.cpp delete mode 100644 src/tests/testLangton.cpp delete mode 100644 src/tests/testLineChain.cpp delete mode 100644 src/tests/testLineChain/Makefile delete mode 100644 src/tests/testLineChain/testLineChain.cpp delete mode 100644 src/tests/testLineFan.cpp delete mode 100644 src/tests/testLineFan/Makefile delete mode 100644 src/tests/testLineFan/testLineFan.cpp delete mode 100644 src/tests/testLines.cpp delete mode 100644 src/tests/testLines/Makefile delete mode 100644 src/tests/testLines/testLines.cpp delete mode 100644 src/tests/testMandelbrot.cpp delete mode 100644 src/tests/testMergeSort.cpp delete mode 100644 src/tests/testMouse.cpp delete mode 100644 src/tests/testMouse/Makefile delete mode 100644 src/tests/testMouse/testMouse.cpp delete mode 100644 src/tests/testNewtonPendulum.cpp delete mode 100644 src/tests/testPhilosophers.cpp delete mode 100644 src/tests/testPixels/Makefile delete mode 100644 src/tests/testPixels/testPixels.cpp delete mode 100644 src/tests/testPong.cpp delete mode 100644 src/tests/testPrism.cpp delete mode 100644 src/tests/testPrism/Makefile delete mode 100644 src/tests/testPrism/testPrism.cpp delete mode 100644 src/tests/testProcedural/Makefile delete mode 100644 src/tests/testProcedural/testProcedural.cpp delete mode 100644 src/tests/testProducerConsumer.cpp delete mode 100644 src/tests/testProgressBar.cpp delete mode 100644 src/tests/testProgressBar/Makefile delete mode 100644 src/tests/testProgressBar/testProgressBar.cpp delete mode 100644 src/tests/testProjectiles.cpp delete mode 100644 src/tests/testProjectiles/Makefile delete mode 100644 src/tests/testProjectiles/testProjectiles.cpp delete mode 100644 src/tests/testPyramid.cpp delete mode 100644 src/tests/testPyramid/Makefile delete mode 100644 src/tests/testPyramid/testPyramid.cpp delete mode 100644 src/tests/testReaderWriter.cpp delete mode 100644 src/tests/testRectangle.cpp delete mode 100644 src/tests/testRectangle/Makefile delete mode 100644 src/tests/testRectangle/testRectangle.cpp delete mode 100644 src/tests/testRegularPolygon.cpp delete mode 100644 src/tests/testRegularPolygon/Makefile delete mode 100644 src/tests/testRegularPolygon/testRegularPolygon.cpp delete mode 100644 src/tests/testScreenshot.cpp delete mode 100644 src/tests/testScreenshot/Makefile delete mode 100644 src/tests/testScreenshot/testScreenshot.cpp delete mode 100644 src/tests/testSeaUrchin.cpp delete mode 100644 src/tests/testShakerSort.cpp delete mode 100644 src/tests/testSolarSystem.cpp delete mode 100644 src/tests/testSpectrogram.cpp delete mode 100644 src/tests/testSpectrogram/Makefile delete mode 100644 src/tests/testSpectrogram/testSpectrogram.cpp delete mode 100644 src/tests/testSpectrum.cpp delete mode 100644 src/tests/testSpectrum/Makefile delete mode 100644 src/tests/testSpectrum/testSpectrum.cpp delete mode 100644 src/tests/testSphere.cpp delete mode 100644 src/tests/testSphere/Makefile delete mode 100644 src/tests/testSphere/testSphere.cpp delete mode 100644 src/tests/testSquare.cpp delete mode 100644 src/tests/testSquare/Makefile delete mode 100644 src/tests/testSquare/testSquare.cpp delete mode 100644 src/tests/testStar.cpp delete mode 100644 src/tests/testStar/Makefile delete mode 100644 src/tests/testStar/testStar.cpp delete mode 100644 src/tests/testText.cpp delete mode 100644 src/tests/testText/Makefile delete mode 100644 src/tests/testText/testText.cpp delete mode 100644 src/tests/testTextCart.cpp delete mode 100644 src/tests/testTextCart/Makefile delete mode 100644 src/tests/testTextCart/testTextCart.cpp delete mode 100644 src/tests/testTextTwo.cpp delete mode 100644 src/tests/testTextTwo/Makefile delete mode 100644 src/tests/testTextTwo/testTextTwo.cpp delete mode 100644 src/tests/testTransparency.cpp delete mode 100644 src/tests/testTransparency/Makefile delete mode 100644 src/tests/testTransparency/testTransparency.cpp delete mode 100644 src/tests/testTriangle.cpp delete mode 100644 src/tests/testTriangle/Makefile delete mode 100644 src/tests/testTriangle/testTriangle.cpp delete mode 100644 src/tests/testTriangleStrip.cpp delete mode 100644 src/tests/testTriangleStrip/Makefile delete mode 100644 src/tests/testTriangleStrip/testTriangleStrip.cpp delete mode 100644 src/tests/testUnits.cpp delete mode 100644 src/tests/testUnits/Makefile delete mode 100644 src/tests/testUnits/testUnits.cpp delete mode 100644 src/tests/testVoronoi.cpp delete mode 100644 src/tests/test_specs.cpp delete mode 100644 src/tests/test_specs/Makefile delete mode 100644 src/tests/test_specs/test_specs.cpp diff --git a/src/tests/DiningPhilosophers3D/Fork3D.h b/src/tests/DiningPhilosophers3D/Fork3D.h deleted file mode 100644 index 6425a0a50..000000000 --- a/src/tests/DiningPhilosophers3D/Fork3D.h +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * \struct Fork3D - * \brief Struct for the forks in the 3D visualization of the Dining Philosophers' problem - */ - -#ifndef FORK3D_H_ -#define FORK3D_H_ - -#include -using namespace tsgl; - -struct Fork3D { - int user, id; - ConcavePolygon * myShape; - Fork3D() { - user = -1; id = 0; - - const int POINTS = 20; // number of vertices in polygon - const float HEIGHT = 42; // 42 is preferred, but can be changed - const float WIDTH = 12; // 12 is preferred, but can be changed - float xs[POINTS], ys[POINTS]; - - // scales (out of 100) for the dimensions of the 3D fork - float xscale[POINTS] = {-.50, -.31, -.31, -.23, -.23, -.04, -.04, .04, .04, .23, .23, .31, .31, .5, .5, .15, .15, -.15, -.15, -.50}; - float yscale[POINTS] = {-.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.30, -.30, -.50, -.50, -.20, -.20, .50, .50, -.20, -.20}; - - // create the 3D fork points from the scale arrays - for(int i = 0; i < POINTS; ++i) { - // scale the 3D fork - xs[i] = WIDTH * xscale[i]; - ys[i] = HEIGHT * yscale[i]; - // xs[i] = xs[i]/100; - // ys[i] = ys[i]/100; - } - - //Add vertices - myShape = new ConcavePolygon(0,0,0,POINTS, xs, ys, 0,0,0,WHITE); - } - void setCanvas( Canvas* can) { - can->add(myShape); - } - void draw(float x, float y, double angle, ColorFloat c) { - angle -= PI/2; - myShape->setColor(c); - myShape->setCenter(x, y, 0); - myShape->setYaw(angle*180/PI); - } - ~Fork3D() { - delete myShape; - } -}; - -#endif /* FORK3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp b/src/tests/DiningPhilosophers3D/Philosopher3D.cpp deleted file mode 100644 index b7e9c0b92..000000000 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "Philosopher3D.h" - -/*! - * \brief Explicitly constructs a new Philosopher3D. - * \details Explicit constructor for a new Philosopher3D object. - */ -Philosopher3D::Philosopher3D() { - setId(0,1); - myState = thinking; - myAction = doNothing; - myCylinder = NULL; - myCone = NULL; - numMeals = 0; -} - -Philosopher3D::~Philosopher3D() { - delete myCylinder; - delete myCone; - for (Pyramid * meal : meals) - { - delete meal; - } - meals.clear(); -} - -/** - * Adds Philosopher3D to Canvas or refreshes its color. - */ -void Philosopher3D::draw(Canvas& can, float x, float y) { - const float SIZE = 45; - if( !myCylinder) { - myCylinder = new Cylinder(x,y,-1,SIZE*4,SIZE,0,0,90,RED); - can.add(myCylinder); - } - if( !myCone && myCylinder) { - myCone = new Cone(x,y+SIZE*3,-1,SIZE*2.25,SIZE*1.25,0,0,90,ColorFloat(0.7,0,0,1)); - myCone->setRotationPoint(myCylinder->getCenterX(), myCylinder->getCenterY(), myCylinder->getCenterZ()); - can.add(myCone); - } -} - -/** - * Updates the Philosopher3D's color based on its state - */ -void Philosopher3D::refreshColor() { - ColorFloat c; - switch(myState) { - case hasNone: c=RED; break; - case hasRight: c=ORANGE; break; - case hasLeft: c=PURPLE; break; - case hasBoth: c=GREEN; break; - case isFull: c=BLUE; break; - case thinking: c=BLUE; break; - } - myCylinder->setColor(c); - myCone->setColor(ColorFloat(c.R*.7,c.G*.7,c.B*.7,c.A)); -} - -/** - * Adds a meal representation to meals and the Canvas - */ -void Philosopher3D::addMeal(float x, float y, float z) { - numMeals++; - meals.push_back(new Pyramid(x,y,z,3,8,4,0,0,90,ColorFloat(0.5,0.3,0,1))); -} - -Pyramid * Philosopher3D::getLastMeal() { - return meals.back(); -} - -/** - * Picks up a fork specified by its reference - */ -bool Philosopher3D::acquire(Fork3D& f) { - if (f.user >= 0) - return false; - if (f.id == myLeft) { - if (myState == hasNone) - myState = hasLeft; - else if (myState == hasRight) - myState = hasBoth; - else - return false; - f.user = id; - return true; - } - if (f.id == myRight) { - if (myState == hasNone) - myState = hasRight; - else if (myState == hasLeft) - myState = hasBoth; - else - return false; - f.user = id; - return true; - } - return false; -} - -/** - * Releases a fork specified by its reference - */ -bool Philosopher3D::release(Fork3D& f) { - if (f.user != id) - return false; - if (myState != isFull) - myState = (myState == ((f.id == myLeft) ? hasLeft : hasRight)) ? hasNone : isFull; - f.user = -1; - return true; -} - -/** - * Thinks and switches to hungry state if a random number is a multiple of 3. - */ -void Philosopher3D::think() { - if(saferand(1,9999)%3 == 0) { // 1/3 probability to go to hungry state - setState(hasNone); - setAction(doNothing); - } -} diff --git a/src/tests/DiningPhilosophers3D/Philosopher3D.h b/src/tests/DiningPhilosophers3D/Philosopher3D.h deleted file mode 100644 index 0781393c4..000000000 --- a/src/tests/DiningPhilosophers3D/Philosopher3D.h +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * \class Philosopher3D - * \brief Object representing a 3D philosopher in the Dining Philosophers' problem - * \details The Philosopher3D class contains variables and methods necessary for - * representing a philosopher at a table. Each Philosopher3D may acquire or release - * the fork to his left or to his right (or both), with his state changing - * accordingly. - */ - -#ifndef PHILOSOPHER3D_H_ -#define PHILOSOPHER3D_H_ - -#include -#include -#include "Fork3D.h" -#include "philEnums.h" - -class Philosopher3D { -private: - PhilState myState; - PhilAction myAction; - int id, myLeft, myRight; - unsigned int numMeals; - Cylinder *myCylinder; - Cone * myCone; - std::vector meals; -public: - Philosopher3D(); - ~Philosopher3D(); - void draw(Canvas& can, float x, float y); - void refreshColor(); - void addMeal(float x, float y, float z); - Pyramid * getLastMeal(); - bool acquire(Fork3D& f); - bool release(Fork3D& f); - void think(); - - // Mutators - /*! - * \brief Resets the Philosopher3D to thinking after he eats. - */ - void eat() { myState = thinking; myAction = doNothing;} - /*! - * \brief Mutator for myState - * \param s PhilState to set myState to. - */ - void setState(PhilState s) { myState = s; } - /*! - * \brief Mutator for myAction - * \param s PhilAction to set myAction to. - */ - void setAction(PhilAction a) { myAction = a; } - /*! - * \brief Mutator for id - * \param i Which philosopher id to mutate - * \param nphil Total number of philosophers. - */ - void setId(int i, int nphil) {id = myLeft = i; myRight = (id+nphil-1)%nphil; } - - //Accessors - /** - * Accessor for number of meals Philosopher3D has consumed. - */ - int getMeals() { return numMeals; } - /** - * Accessor for Philosopher3D's state. - */ - PhilState state() { return myState; } - /** - * Accessor for Philosopher3D's action. - */ - PhilAction action() { return myAction; } - /** - * Accessor for Philosopher3D's id. - */ - int getId() { return id; } - /** - * Accessor for Philosopher3D's cylinder. - */ - bool hasCylinder() { return myCylinder; } -}; - -#endif /* PHILOSOPHER3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Table3D.cpp b/src/tests/DiningPhilosophers3D/Table3D.cpp deleted file mode 100644 index 60fe9e951..000000000 --- a/src/tests/DiningPhilosophers3D/Table3D.cpp +++ /dev/null @@ -1,489 +0,0 @@ -#include "Table3D.h" - -/*! - * \brief Creates a new 3D Table of dining Philosopher3Ds. - * \details Explicit constructor for a new Table3D object. - * \param can The Canvas on which the Table3D is to be drawn. - * \param p Integer denoting the number of Philosopher3Ds at the Table3D - * \param m PhilMethod denoting how the Philosopher3Ds should interact. - */ -Table3D::Table3D(Canvas& can, int p, PhilMethod m) { - numPhils = p; - myCan = &can; - myTable = new Cylinder(0,0,-55,100,150,0,0,90,ColorFloat(0.5,0.5,0.5,1)); - can.add(myTable); - phils = new Philosopher3D[numPhils]; - forks = new Fork3D[numPhils]; - for (int i = 0; i < numPhils; ++i) { - phils[i].setId(i,numPhils); - forks[i].id = i; - forks[i].setCanvas(myCan); - } - // float delta = 2.0f / numPhils * PI; - // for(int i = 0; i < numPhils; i++) { - // myCan->drawImage("../assets/pics/spaghet.png", tabX-50+(200)*cos(i*delta), tabY-25+(215)*sin(i*delta), 100, 50, 1.0f); - // } - myMethod = m; - switch(myMethod) { - case forfeitWhenBlocked: - methodString = "forfeit when blocked"; - break; - case waitWhenBlocked: - methodString = "wait when blocked"; - break; - case nFrameRelease: - methodString = "release on nth frame"; - break; - case resourceHierarchy: - methodString = "hierarchical resources"; - break; - case oddEven: - methodString = "odd-even check"; - break; - default: - break; - } - - // myCan2 = new Canvas(0,0,300,300,"Legend"); - // myCan2->start(); - // myCan2->drawText("Method:",16,32,32,BLACK); - // myCan2->drawText("\"" + methodString + "\"",32,64,24,BLACK); - // myCan2->drawText("Legend:",16,96,24,BLACK); - // myCan2->drawText("Red: Hungry",32,128,24,RED); - // myCan2->drawText("Orange: Has Right Fork",32,160,24,ORANGE); - // myCan2->drawText("Yellow: Has Left Fork",32,192,24,YELLOW); - // myCan2->drawText("Green: Eating",32,224,24,GREEN); - // myCan2->drawText("Blue: Thinking",32,256,24,BLUE); - // myCan2->drawText("Meals eaten: ",32,288,24,BROWN); - // myCan2->drawCircle(165,281,3,BROWN); -} - -/*! - * \brief Destructor for Table3D. - */ -Table3D::~Table3D() { - // if (myCan2->isOpen()) - // myCan2->stop(); - // delete myCan2; - delete myTable; - delete [] phils; - delete [] forks; -} - - /*! - * \brief Method for determining which fork a Philosopher3D should get. - * \details - * - Store the id numbers for the left and the right Philsopher's state. - * - Switch for the state of a Philosopher3D: - * - Philosopher3D has no fork: - * - If the right fork is free, try to get that fork. - * - Else, if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has right fork: - * - If the left fork is free, try to get that fork. - * . - * - Philosopher3D has the left fork: - * - If the right fork is free, try to get that fork. - * - Else, release the left fork. - * . - * - Philosopher3D has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher3D. - * \note This is an example of Deadlock amongst threads. - */ -void Table3D::forfeitWhenBlockedMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(releaseRight); - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(releaseLeft); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].setState(hasNone); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher3D should get. - * \details - * - Store the states of the left and right Philosopher3Ds. - * - Switch for the state of the current Philosopher3D: - * - Philosopher3D has no forks: - * - If the right fork is free, try to get that fork. - * - Else if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has right fork: - * - If the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has the left fork: - * - If the right fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher3D. - * \note This is an example of Livelock amongst threads. - */ -void Table3D::waitWhenBlockedMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher3D should get. - * \details - * - Store the states of the left and right Philosopher3Ds. - * - Switch statement for the current Philosopher3D: - * - Philosopher3D has no forks: - * - If the right fork is free, try to get that fork. - * - Else, if the left fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has right fork: - * - If the left fork is free, try to get that fork. - * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas - * modulo the number of Philosopher3Ds+1, then release the right fork. - * - Else, do nothing. - * . - * - Philosopher3D has the left fork: - * - If the right fork is free, try and get that fork. - * - Else, if the id of the current Philosopher3D is equal to the frame number of the Canvas - * modulo the number of Philosopher3Ds+1, then release the left fork. - * - Else, do nothing. - * . - * - Philosopher3D has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher3D. - */ -void Table3D::nFrameReleaseMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else { - if (id == (myCan->getFrameNumber() % numPhils+1)) - phils[id].setAction(releaseRight); - else - phils[id].setAction(doNothing); - } - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else { - if (id == (myCan->getFrameNumber() % numPhils+1)) - phils[id].setAction(releaseLeft); - else - phils[id].setAction(doNothing); - } - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher3D should get. - * \details - * - Store the states for the left and right Philosopher3Ds. - * - Switch statement for the state of the current Philosopher3D. - * - Philosopher3D has no forks: - * - If the right Philosopher3D's id is less than the left Philsopher's id: - * - If the right fork is free, try to get that fork. - * - Else, do nothing. - * . - * - Else, if the left fork is free then try and get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has the right fork: - * - If the left fork is free, try and get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has the left fork: - * - If the right fork is free, try and get that fork. - * - Else, do nothing. - * . - * - Philosopher3D has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher3D. - */ -void Table3D::hierarchyMethod(int id) { - int left = id, right = (id+numPhils-1)%numPhils; - switch(phils[id].state()) { - case hasNone: - if (right < left) { - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - } else { - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else - phils[id].setAction(doNothing); - } - break; - case hasRight: - if (forks[left].user == -1) - phils[id].setAction(tryLeft); - else { - phils[id].setAction(doNothing); - } - break; - case hasLeft: - if (forks[right].user == -1) - phils[id].setAction(tryRight); - else - phils[id].setAction(doNothing); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - - /*! - * \brief Method for determining which fork a Philosopher3D should get. - * \details - * - Switch statement for the current Philosopher3D: - * - Philosopher3D has no forks: - * - If the Philosopher3D's id is even - * - Philosopher3D has right fork (odd id): - * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number - * modulo 2, then try and get the left fork. - * - Else, release the right fork. - * . - * - Philosopher3D has left fork (even id): - * - If the Philsopher's id modulo 2 is equal to the Canvas' current frame number - * modulo 2, then try and get the right fork. - * - Else, release the left fork. - * . - * - Philosopher3D has both forks: - * - Release both of them. - * . - * . - * . - * \param id The id number of the current Philosopher3D. - * \note This method is the one that works best. - */ -void Table3D::oddEvenMethod(int id) { - switch(phils[id].state()) { - case hasNone: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryBoth); - else - phils[id].setAction(doNothing); - break; - case hasRight: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryLeft); - else { - phils[id].setAction(releaseRight); - } - break; - case hasLeft: - if ((id % 2) == (myCan->getFrameNumber() % 2)) - phils[id].setAction(tryRight); - else - phils[id].setAction(releaseLeft); - break; - case hasBoth: - phils[id].setAction(releaseBoth); - break; - case thinking: - phils[id].think(); - break; - default: - break; - } -} - -/*! - * \brief Method for determining which method of resolution the philosopher is using. - */ -void Table3D::checkStep() { - int i = omp_get_thread_num(); - if (phils[i].state() == isFull) { - phils[i].eat(); - return; - } - switch(myMethod) { - case forfeitWhenBlocked: - forfeitWhenBlockedMethod(i); - break; - case waitWhenBlocked: - waitWhenBlockedMethod(i); - break; - case nFrameRelease: - nFrameReleaseMethod(i); - break; - case resourceHierarchy: - hierarchyMethod(i); - break; - case oddEven: - oddEvenMethod(i); - break; - default: - break; - } -} - -/*! - * \brief Method for philosopher to act based on myAction. - */ -void Table3D::actStep() { - // myCan2->sleep(); - int i = omp_get_thread_num(); - int left = i, right = (i+numPhils-1)%numPhils; - switch(phils[i].action()) { - case tryLeft: - phils[i].acquire(forks[left]); - break; - case tryRight: - phils[i].acquire(forks[right]); - break; - case tryBoth: - phils[i].acquire(forks[left]); - phils[i].acquire(forks[right]); - break; - case releaseLeft: - phils[i].release(forks[left]); - break; - case releaseRight: - phils[i].release(forks[right]); - break; - case releaseBoth: - phils[i].release(forks[left]); - phils[i].release(forks[right]); - break; - default: - break; - } -} - -/*! - * \brief Method calculating angles calling draw methods of a philosopher and its fork or forks. - */ -void Table3D::drawStep() { - const float RAD = 195; - float FORK_RAD = 130; - const float ARC =2*PI/numPhils; - const float CLOSE = 0.15f; - const float BASEDIST = RAD+58; - - int i = omp_get_thread_num(); - float pangle = (i*2*PI)/numPhils; - ColorFloat fcolor = WHITE; - float fangle = (i+0.5f)*ARC; - - if( !phils[i].hasCylinder() ) { - phils[i].draw(*myCan,RAD*cos(pangle),RAD*sin(pangle)); - } - - phils[i].refreshColor(); - if( phils[i].state() == isFull ) { - int meals = phils[i].getMeals(); - float angle = pangle+(meals/10)*2*PI/(100*RAD), dist = BASEDIST+8*(meals%10); - // myCan->drawRegularPolygon(dist*cos(angle), dist*sin(angle), 3, 10 ,BROWN, BLACK); - phils[i].addMeal(dist*cos(angle), dist*sin(angle),0); - myCan->add(phils[i].getLastMeal()); - } - if (forks[i].user == i) { - fangle = i*ARC + CLOSE; - fcolor = (phils[i].state() == hasBoth) ? GREEN : PURPLE; - } - else if((forks[i].user == (i+1)%numPhils)) { - fangle = ((i+1)*ARC) - CLOSE; - fcolor = (phils[(i+1)%numPhils].state() == hasBoth) ? GREEN : ORANGE; - } else { - FORK_RAD = 120; - fangle = pangle + PI / numPhils; - } - forks[i].draw(FORK_RAD*cos(fangle),FORK_RAD*sin(fangle),fangle,fcolor); -} \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/Table3D.h b/src/tests/DiningPhilosophers3D/Table3D.h deleted file mode 100644 index daf857b5c..000000000 --- a/src/tests/DiningPhilosophers3D/Table3D.h +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * \class Table3D - * \brief Object managing the forks and philosophers in the Dining Philosophers' problem. - * \details The Table3D class keeps track of the forks and philosophers in the Dining - * Philosophers' problem; it additionally manages the actions of the philosophers. - * \details Each step of the problem is broken up into two phases. In the checking phase, - * the philosophers look at the 3D table around them and, without communicating with the - * other philosophers, determine an action to take based on their state and the states - * of their adjacent forks. - * \details In the action phase, each philosopher attempts to execute the action previously - * determined in the checking phase. If unsuccessful, the philosopher does nothing; - * otherwise, the philosopher's state changes depending on the action taken. - */ - -#ifndef TABLE3D_H_ -#define TABLE3D_H_ - -#include -#include "Philosopher3D.h" - -using namespace tsgl; - -class Table3D { -private: - int numPhils; - PhilMethod myMethod; - std::string methodString; - Canvas *myCan/* , *myCan2 */; - Philosopher3D *phils; - Fork3D *forks; - Cylinder * myTable; - // TextureHandler loader; -public: - Table3D(Canvas& can, int p, PhilMethod m); - - ~Table3D(); - - void forfeitWhenBlockedMethod(int id); - - void waitWhenBlockedMethod(int id); - - void nFrameReleaseMethod(int id); - - void hierarchyMethod(int id); - - void oddEvenMethod(int id); - - void checkStep(); - - void actStep(); - - void drawStep(); -}; - -#endif /* TABLE3D_H_ */ \ No newline at end of file diff --git a/src/tests/DiningPhilosophers3D/philEnums.h b/src/tests/DiningPhilosophers3D/philEnums.h deleted file mode 100644 index 17390208e..000000000 --- a/src/tests/DiningPhilosophers3D/philEnums.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PHIL_ENUM_H_ -#define PHIL_ENUM_H_ - -/*! \brief Enum for valid states for the Dining Philosophers - */ -enum PhilState { - hasNone, hasRight, hasLeft, hasBoth, isFull, thinking -}; - -/*! \brief Enum for valid actions for the Dining Philosophers - */ -enum PhilAction { - doNothing, tryLeft, tryRight, tryBoth, releaseLeft, releaseRight, releaseBoth -}; - -/*! \brief Enum for resource collision resolution methods for the Dining Philosophers' problem - */ -enum PhilMethod { - forfeitWhenBlocked, waitWhenBlocked, nFrameRelease, resourceHierarchy, oddEven -}; - -#endif /* PHIL_ENUM_H_ */ \ No newline at end of file diff --git a/src/tests/Fireworks/Arc.cpp b/src/tests/Fireworks/Arc.cpp deleted file mode 100644 index 0c154288a..000000000 --- a/src/tests/Fireworks/Arc.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Arc.cpp - */ - -#include "Arc.h" - -const float HFLOAT = 6.0f/255.0f; - -/*! - * \brief Explicit constructor for an Arc. - * \details Explicitly constructs an Arc. - * \param can The Canvas to which the Arc is to be drawn. - */ -Arc::Arc(Canvas& can) { - f = NULL; - myLife = 0; - myCan = &can; - myX = rand() % myCan->getWindowWidth(); - myY = rand() % myCan->getWindowHeight(); - myAngle = ((rand() % 32000) / 32000.0f) * 2.0f*PI; - myRad = 20 + rand() % 180; - computeStepSize(); - myColor = ColorHSV(0.0f,1.0f,1.0f,1.0f); -} - -/*! - * \brief Explicit constructor for an Arc. - * \details Explicitly constructs an Arc. - * \param can The Canvas to which the dot is to be drawn. - * \param x The x coordinate of the dot emission point. - * \param y The y coordinate of the dot emission point. - * \param rad The radians of the Arc. - * \param angle The starting angle of the Arc. - */ -Arc::Arc(Canvas* can, int x, int y, int rad, float angle) { - myCan = can; - myX = x; myY = y; - myAngle = angle; myRad = rad; - computeStepSize(); -} - -/*! - * \brief Accessor for if the Arc is out of the Canvas window. - * \details Returns if myX and myY are between 0 and the Canvas' width and height respectively. - */ -bool Arc::outOfBounds() { - return (myX < 0 || myY < 0 || myX > myCan->getWindowWidth() || myY > myCan->getWindowHeight()); -} - -/*! - * \brief Accesssor if the Canvas is black at the Arc's pixel. - */ -bool Arc::onBlackPixel() { - const int LET = 14; - ColorInt col = myCan->getPoint(myX,myY); - return !(col.RgetWindowWidth(); - myY = rand() % myCan->getWindowHeight(); - } - computeStepSize(); -} - -/*! - * \brief Makes the Arc take a step. - */ -void Arc::step() { - if (f != NULL) - f->step(); - if (rand() % 100 < 2) { - ++myRad; - myStepSize = 1.0f/(myRad); - } - myAngle += myStepSize; - myX += cos(myAngle); - myY += sin(myAngle); - if (outOfBounds() || onBlackPixel()) { - if (f != NULL) - delete f; - f = new Firework(*myCan,myX,myY); - relocate(); - } - myCan->drawPoint(myX,myY,myColor); -} - -Arc::~Arc() { - delete f; -} \ No newline at end of file diff --git a/src/tests/Fireworks/Arc.h b/src/tests/Fireworks/Arc.h deleted file mode 100644 index a7cd14718..000000000 --- a/src/tests/Fireworks/Arc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Firework.h - */ - -#ifndef ARC_H_ -#define ARC_H_ - -#include -#include "Firework.h" - -using namespace tsgl; - -class Arc { -private: - Canvas* myCan; - int myLife; - float myX, myY, myRad; - float myAngle, myStepSize; - ColorHSV myColor; - Firework* f; -public: - Arc(Canvas& can); - - Arc(Canvas* can, int x, int y, int rad, float angle); - - ~Arc(); - - bool outOfBounds(); - - bool onBlackPixel(); - - void computeStepSize(); - - void relocate(); - - void step(); -}; - -#endif /* ARC_H_ */ - -/* #ifdef _WIN32 - #define Arc tsgl::Arc -#endif */ \ No newline at end of file diff --git a/src/tests/Fireworks/Dot.cpp b/src/tests/Fireworks/Dot.cpp deleted file mode 100644 index ccd6c5b37..000000000 --- a/src/tests/Fireworks/Dot.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Dot.cpp - */ - -#include "Dot.h" - -/*! - * \brief Explicit constructor for a Dot. - * \details Draws a Dot to a Canvas parameter - * \param can Canvas to which the Dot will be drawn. - * \param x The x-coordinate of the Dot. - * \param y The y-coordinate of the Dot. - * \param s The Dot's movement speed. - * \param f The Dot's friction. - * - */ -Dot::Dot(Canvas& can, float x, float y, float s, float d, float f) { - myCan = &can; - dead = false; - myX = x; myY = y; mySpeed = s; - myDir = d; myFric = f; -} - -/*! - * \brief Makes the Dot take a step.\ - * \details Updates the Dot's x and y based on its speed and friction - */ -void Dot::step() { - myX += mySpeed*cos(myDir); - myY += mySpeed*sin(myDir); - mySpeed *= myFric; - if (!dead) - myCan->drawPoint(myX,myY,WHITE); - if (mySpeed < 0.5f) - dead = true; -} - -/*! - * \brief Accessor for the Dot's death status - * \details Returns the Dot's dead variable. - * \return dead The Dot's variable that says whether it's dead. - */ -bool Dot::isDead() { - return dead; -} \ No newline at end of file diff --git a/src/tests/Fireworks/Dot.h b/src/tests/Fireworks/Dot.h deleted file mode 100644 index 12052a7bf..000000000 --- a/src/tests/Fireworks/Dot.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Dot.h - */ - -#ifndef DOT_H_ -#define DOT_H_ - -#include - -using namespace tsgl; - -class Dot { -private: - bool dead; - Canvas* myCan; - float myX, myY, mySpeed, myDir, myFric; -public: - Dot(Canvas& can, float x, float y, float s, float d, float f); - - void step(); - - bool isDead(); -}; - -#endif /* DOT_H_ */ \ No newline at end of file diff --git a/src/tests/Fireworks/Firework.cpp b/src/tests/Fireworks/Firework.cpp deleted file mode 100644 index d222832a2..000000000 --- a/src/tests/Fireworks/Firework.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Firework.cpp - */ - -#include "Firework.h" - -/*! - * \brief Explicit constructor for a Firework. - * \details Shoots white dots out in random directions from a point. - * \param can The Canvas to which the dot is to be drawn. - * \param x The x coordinate of the dot emission point. - * \param y The y coordinate of the dot emission point. - */ -Firework::Firework(Canvas& can, int x, int y) { - dead = false; - myCan = &can; - myX = x; - myY = y; - for (int i = 0; i < 10; ++i) { - myDots[i] = new Dot(can, myX,myY,(rand() % 10000)/10000.0f,(rand() % 10000)/10000.0f * 2 * PI, 0.99f); - } -} - -/*! - * \brief Destructor for Firework. - * \details Deallocates the myDots array. - */ -Firework::~Firework() { - for (int i = 0; i < 10; i++) { - delete myDots[i]; - } -} - -/*! - * \brief Makes the firework take a step. - * \details Makes each dot in myDots take a step. - */ -void Firework::step() { - if (!dead) { - bool allDead = true; - for (int i = 0; i < 10; ++i) { - myDots[i]->step(); - if (!myDots[i]->isDead()) - allDead = false; - } - dead = allDead; - } -} - -/*! - * \brief Accessor for if the Firework is dead. - * \details Returns the dead variable. - * \return dead A bool stating whether the Firework is dead. - */ -bool Firework::isDead() { - return dead; -} \ No newline at end of file diff --git a/src/tests/Fireworks/Firework.h b/src/tests/Fireworks/Firework.h deleted file mode 100644 index 5eb86af65..000000000 --- a/src/tests/Fireworks/Firework.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Firework.h - */ - -#ifndef FIREWORK_H_ -#define FIREWORK_H_ - -#include -#include "Dot.h" - -using namespace tsgl; - -class Firework { -private: - bool dead; - int myX, myY; - Canvas* myCan; - Dot* myDots[10]; -public: - Firework(Canvas& can, int x, int y); - - ~Firework(); - - void step(); - - bool isDead(); -}; - -#endif /* FIREWORK_H_ */ \ No newline at end of file diff --git a/src/tests/ImageInverter/ImageInverter.cpp b/src/tests/ImageInverter/ImageInverter.cpp deleted file mode 100644 index f559065b1..000000000 --- a/src/tests/ImageInverter/ImageInverter.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ImageInverter.cpp - */ - -#include "ImageInverter.h" - -ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsigned height) - : myCanvas1(0, 0, width, height, fileName), - myCanvas2(-1, -1, width, height, fileName), - myWidth(width), myHeight(height), myFileName(fileName) -{ - myCanvas1.start(); - myCanvas1.drawImage(fileName, 0, 0, width, height); - // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); - sleep(1); - myCanvas2.start(); -} - -void ImageInverter::run(unsigned numThreads) { - invertImage(numThreads); - stop(); -} - -void ImageInverter::invertImage(unsigned numThreads) { - ColorInt pixelColor; - // #pragma omp parallel for num_threads(numThreads) - const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); - #pragma omp parallel num_threads(numThreads) - { - int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - for (unsigned int x = row; x < row + blocksize; x++) { - for (unsigned int y = 0; y < WW; y++) { - pixelColor = myCanvas1.getPixel(x, y); - int invertedR = 255 - pixelColor.R; - int invertedG = 255 - pixelColor.G; - int invertedB = 255 - pixelColor.B; - myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); - } - myCanvas1.sleep(); - myCanvas2.sleep(); - } - } -} - -void ImageInverter::stop() { - myCanvas2.wait(); - myCanvas1.wait(); -} - -ImageInverter::~ImageInverter() { -// delete myCanvas1; -// delete myCanvas2; -// std::cout << "ImageInverter terminated normally.\n" << std::endl; -} diff --git a/src/tests/ImageInverter/ImageInverter.h b/src/tests/ImageInverter/ImageInverter.h deleted file mode 100644 index 6906b31b6..000000000 --- a/src/tests/ImageInverter/ImageInverter.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ImageInverter.h declares the ImageInverter class. - */ - -#ifndef IMAGEINVERTER_H_ -#define IMAGEINVERTER_H_ - -#include // Canvas, ColorInt, etc. -#include - -#ifdef _WIN32 - #include -#else - #include // sleep() -#endif - -using namespace tsgl; - -class ImageInverter { -private: - Canvas myCanvas1; - Canvas myCanvas2; - int myWidth; - int myHeight; - std::string myFileName; - #ifdef _WIN32 - void sleep(unsigned seconds) { Sleep(seconds * 1000); } - #endif -protected: - - /* invertImage inverts the image using a given number of threads - * @param: numThreads, the number of threads to use - * when inverting the image (default 1). - * Postcondition: myCanvas2 contains an image that is the - * inverse of the image in myCanvas1. - */ - virtual void invertImage(unsigned numThreads = 1); - - /* helper method to keep Canvases up until the user - * clicks their window-frame's close button. - * - * Postcondition: myCanvas1 and myCanvas2 have been closed. - */ - virtual void stop(); - -public: - - /* explicit constructor - * @param fileName, a string. - * @param width, an unsigned. - * @param height, an unsigned. - * Precondition: fileName contains the name of a valid image file - * && width contains the number of columns in that image - * && height contains the number of rows in the image. - * Postcondition: myCanvas1 contains the image from fileName - * && myCanvas2 is ready for drawing its inverse - * && myWidth = width - * && myHeight = height. - */ - ImageInverter(const std::string& fileName, unsigned width, unsigned height); - - /* destructor - * Postcondition: myCanvas1 and myCanvas2 have been closed - * && myCanvas1 and myCanvas2 have been deallocated - * && glfwTerminate() has shut down GLFW - * && a termination message was written to the console. - */ - virtual ~ImageInverter(); - - /* method to coordinate the image inversion - * @param: numThreads, the number of threads to use - * when inverting the image (default 1). - * PostCondition: myCanvas2 contains the inverse - * of the image in myCanvas1. - */ - virtual void run(unsigned numThreads = 1); -}; - -#endif /* IMAGEINVERTER_H_ */ diff --git a/src/tests/Langton/AntFarm.cpp b/src/tests/Langton/AntFarm.cpp deleted file mode 100644 index 4d687c184..000000000 --- a/src/tests/Langton/AntFarm.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * AntFarm.cpp - */ - -#include "AntFarm.h" - -AntFarm::AntFarm(int w, int h, int s, Canvas* c) { - width = w; - height = h; - cap = s; - size = 0; - ants = new LangtonAnt*[cap]; - filled = new bool[w * h](); // Create an empty bitmap for the window - can = c; - shading = false; - inParallel = true; -} - -AntFarm::~AntFarm() { - for (int i = 0; i < size; i++) { - delete ants[i]; - } - delete[] ants; - delete[] filled; -} - -void AntFarm::addAnt(int x, int y, int r, int g, int b, int d) { - if (size < cap) { - ants[size] = new LangtonAnt(x, y, r, g, b, d, this); - size++; - } -} - -inline void AntFarm::moveAnt(int j) { - if (filled[ants[j]->myX + width * ants[j]->myY]) { - ants[j]->myDir = (ants[j]->myDir + 1) % 4; - if (shading) - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); - else - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); - } else { - ants[j]->myDir = (ants[j]->myDir + 3) % 4; - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); - } -} - -void AntFarm::moveAnts() { - if (inParallel) { - #pragma omp parallel num_threads(omp_get_num_procs()) - { - int nthreads = omp_get_num_threads(); - int tid = omp_get_thread_num(); - for (int j = tid; j < size; j+= nthreads) - moveAnt(j); - } - } else { - for (int j = 0; j < size; j++) - moveAnt(j); - } - for (int j = 0; j < size; j++) { - filled[ants[j]->myX + width * ants[j]->myY] ^= true; - ants[j]->move(); - } -} - -void AntFarm::setShading(bool b) { - shading = b; -} - -void AntFarm::setParallel(bool b) { - inParallel = b; -} diff --git a/src/tests/Langton/AntFarm.h b/src/tests/Langton/AntFarm.h deleted file mode 100644 index 2f85d75ab..000000000 --- a/src/tests/Langton/AntFarm.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * AntFarm.h - */ - -#ifndef ANTFARM_H_ -#define ANTFARM_H_ - -#include - -#include -#include "LangtonAnt.h" - -using namespace tsgl; - -class LangtonAnt; //Forward Declaration - -/*! - * \class AntFarm - * \brief Display one or more of Langton's Ant! - * \details Contains the data and method needed in order to hold and move around one or more LangtonAnt objects. - * \details You can have one LangtonAnt, or multiple. - * \details You can move them in parallel, or in sequence. - * \details You can also shade the colors of each LangtonAnt. - */ -class AntFarm { -private: - bool* filled; - bool shading; - bool inParallel; - void moveAnt(int j); -public: - LangtonAnt** ants; - int width, height, size, cap; - Canvas* can; - - /*! - * \brief Explicitly constructs an AntFarm object. - * \details Explicit constructor for the AntFarm class. - * \param w The width of the AntFarm object. - * \param h The height of the AntFarm object. - * \param s The size of the AntFarm object (how many ants are going to be in the AntFarm object). - * \param can Pointer to the Canvas to draw to. - */ - AntFarm(int w, int h, int s, Canvas* can); - - /*! - * \brief Destroy an AntFarm object. - * \details Destructor for the AntFarm class. - * \return Frees up any allocated memory to an AntFarm object. - */ - ~AntFarm(); - - /*! - * \brief Add an ant. - * \details Adds a LangtonAnt to the AntFarm with the specified arguments. - * \param x The x coordinate of the LangtonAnt. - * \param y The y coordinate of the LangtonAnt. - * \param r Red component of the color of the LangtonAnt. - * \param g Green component of the color of the LangtonAnt. - * \param b Blue component of the color of the LangtonAnt. - * \param d The direction of the LangtonAnt. - */ - void addAnt(int x, int y, int r, int g, int b, int d); - - /*! - * \brief Move the ants. - * \details Move the LangtonAnts that are currently in the AntFarm object. - */ - void moveAnts(); - - /*! - * \brief Shade the ants. - * \details Determines if we should shade the LangtonAnt(s) so that they have a darker color or not. - * \param b A boolean determining if we should shade the LangtonAnt(s) or not. - */ - void setShading(bool b); - - /*! - * \brief Moves the ants in parallel. - * \details Determines if we should move the LangtonAnt(s) in parallel or not. - * \param b A boolean determining if we should move the LangtonAnt(s) in parallel or not. - */ - void setParallel(bool b); -}; - -#endif /* ANTFARM_H_ */ diff --git a/src/tests/Langton/LangtonAnt.cpp b/src/tests/Langton/LangtonAnt.cpp deleted file mode 100644 index 0d1621cf9..000000000 --- a/src/tests/Langton/LangtonAnt.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * LangtonAnt.cpp - */ - -#include "LangtonAnt.h" - -LangtonAnt::LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p) { - myX = x; - myY = y; - myRed = r; - myGreen = g; - myBlue = b; - myDir = d; - myFarm = p; - myAlpha = 16; -} - -void LangtonAnt::move() { - switch (myDir) { - case UP: - myY = (myY > 0) ? myY - 1 : myFarm->height - 1; - break; - case RIGHT: - myX = (myX < myFarm->width - 1) ? myX + 1 : 0; - break; - case DOWN: - myY = (myY < myFarm->height - 1) ? myY + 1 : 0; - break; - case LEFT: - myX = (myX > 0) ? myX - 1 : myFarm->width - 1; - break; - default: - break; - } -} - -void LangtonAnt::changeColor(int r, int g, int b) { - myRed = r; myGreen = g; myBlue = b; -} - -void LangtonAnt::changeColor(ColorFloat c) { - changeColor(c.R*255,c.G*255,c.B*255); -} - -void LangtonAnt::setAlpha(int a) { - myAlpha = a; -} diff --git a/src/tests/Langton/LangtonAnt.h b/src/tests/Langton/LangtonAnt.h deleted file mode 100644 index 3baac9c6c..000000000 --- a/src/tests/Langton/LangtonAnt.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * LangtonAnt.h - */ - -#ifndef LANGTONANT_H_ -#define LANGTONANT_H_ - -#include "AntFarm.h" - -using namespace tsgl; - -class AntFarm; //Forward Declaration - -// Shared values between langton functions -enum direction { - UP = 0, - RIGHT = 1, - DOWN = 2, - LEFT = 3 -}; - -/*! - * \class LangtonAnt - * \brief Create one of Langton's Ant! - * \details Contains all of the data and method needed in order to simulate a LangtonAnt. - * \details You can change the color either by manually setting the red, green, and blue components - * or by passing a ColorFloat struct that contains those values. - * \details The movement of each LangtonAnt is determined by its direction; UP, DOWN, LEFT, or RIGHT. - * \details You can also set each LangtonAnt object to have an alpha value in order to make them transparent. - */ -class LangtonAnt { -public: - int myX, myY, myRed, myGreen, myBlue, myAlpha, myDir; - AntFarm* myFarm; -public: - - /*! - * \brief Explicitly constructs a LangtonAnt object. - * \details Explicit constructor for the LangtonAnt class. - * \param x The x coordinate of the LangtonAnt object. - * \param y The y coordinate of the LangtonAnt object. - * \param r Red component for the color of the LangtonAnt object. - * \param g Green component for the color of the LangtonAnt object. - * \param b Blue component for the color of the LangtonAnt object. - * \param d The direction of the LangtonAnt object. - * \param p Pointer to the AntFarm object that the LangtonAnt object belongs to. - * \return The constructed LangtonAnt object. - */ - LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p); - - /*! - * \brief Move the LangtonAnt object. - * \details Set to movement of the LangtonAnt object based off of its current direction (UP, DOWN, LEFT, or RIGHT). - */ - void move(); - - /*! - * \brief Change the color of a LangtonAnt object. - * \details Specifying a new red, green, and blue component allows you to change the - * color of the LangtonAnt object. - * \param r Red component of the new color for the LangtonAnt object. - * \param g Green component of the new color for the LangtonAnt object. - * \param b Blue component of the new color for the LantonAnt object. - */ - void changeColor(int r, int g, int b); - - /*! - * \brief Change the color of a LangtonAnt object. - * \details Same as changeColor(r, g, b) but instead of passing the red, green, and - * blue components seperately you are passing a ColorFloat struct that contains all three. - * \param c A ColorFloat struct containing the new red, green, and blue components for the new - * color of the LangtonAnt object. - */ - void changeColor(ColorFloat c); - - /*! - * \brief Set the alpha component of the color. - * \details Set the alpha component of the color for a LangtonAnt object. - * \param a Alpha component to give to the LangtonAnt object. - */ - void setAlpha(int a); -}; - -#endif /* LANGTONANT_H_ */ diff --git a/src/tests/Makefile b/src/tests/Makefile deleted file mode 100644 index 183246145..000000000 --- a/src/tests/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Master Makefile for Tests - -# ***************************************************** - -# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the tests -SUBDIRS_TO_BUILD := test_specs \ - test2Dvs3D \ - test3DRotation \ - testAlphaRectangle \ - testArrows \ - testBackground \ - testCircle \ - testConcavePolygon \ - testCone \ - testConvexPolygon \ - testCube \ - testCuboid \ - testCylinder \ - testDice \ - testDiorama \ - testEllipse \ - testEllipsoid \ - testImage \ - testLines \ - testPrism \ - testProcedural \ - testPyramid \ - testRectangle \ - testRegularPolygon \ - testSphere \ - testSquare \ - testStar \ - testText \ - testTransparency \ - testTriangle \ - testTriangleStrip \ -# testAura \ -# testBlurImage \ -# testCalcPi \ -# testColorWheel \ -# testConstructors \ -# testCosineIntegral \ -# testFunction \ -# testGetPixels \ -# testGradientWheel \ -# testGraydient \ -# testGreyscale \ -# testHighData \ -# testImageCart \ -# testInverter \ -# testLineChain \ -# testLineFan \ -# testMouse \ -# testPixels \ -# testProgressBar \ -# testProjectiles \ -# testScreenshot \ -# testSpectrogram \ -# testSpectrum \ -# testTextCart \ -# testTextTwo \ -# testUnits \ - -SUBDIRS_TO_CLEAN := $(subst test,..., $(SUBDIRS_TO_BUILD)) # Used to clean the tests - - -all: $(SUBDIRS_TO_BUILD) - -$(SUBDIRS_TO_BUILD): - @echo "" - @tput setaf 3; - @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" - @tput sgr0; - @echo "" - $(MAKE) -C $@ - -.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) - -clean: $(SUBDIRS_TO_CLEAN) - -$(SUBDIRS_TO_CLEAN): - cd $(subst ...,test,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/tests/Mandelbrot/Buddhabrot.cpp b/src/tests/Mandelbrot/Buddhabrot.cpp deleted file mode 100644 index f3d2ab888..000000000 --- a/src/tests/Mandelbrot/Buddhabrot.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Buddhabrot.cpp - */ - -#include "Buddhabrot.h" - -#ifdef _WIN32 //Windows doesn't like numbers higher than RAND_MAX (32767) - #define rand() (rand() | rand() << 16) -#endif - -Buddhabrot::Buddhabrot(unsigned threads, unsigned depth = 1000) : Mandelbrot(threads, depth) { - counter = nullptr; - cww = cwh = 0; -} - -Buddhabrot::~Buddhabrot() { - for (int i = 0; i < cwh; ++i) - delete [] counter[i]; - delete[] counter; - counter = nullptr; -} - -void Buddhabrot::draw(Cart& can) { - cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - const unsigned long MAXITS = cww*cwh*10; - ColorFloat tcolor(1.0f,1.0f,1.0f,0.1f); - const int RPREC = 100000; - counter = new int*[cwh]; - for (int i = 0; i < cwh; ++i) - counter[i] = new int[cww]; - while (myRedraw) { - myRedraw = false; - can.clearProcedural(); - for (int i = 0; i < cwh; ++i) - for (int j = 0; j < cww; ++j) - counter[i][j] = 0; - const Decimal cph = can.getPixelHeight(), cpw = can.getPixelWidth(), - cMinx = can.getMinX(), cMiny = can.getMinY(), - cMaxx = cMinx+cpw*(cww-1), cMaxy = cMiny+cph*(cwh-1); - unsigned long cycles = 0; - #pragma omp parallel num_threads(myThreads) - { - unsigned tid = omp_get_thread_num(), threads = omp_get_num_threads(); - Decimal offset = cMiny+(cph*cwh*tid)/(Decimal)threads; - const Decimal wscale = (cpw*cww)/(Decimal)RPREC; - const Decimal hscale = (cph*cwh/threads)/(Decimal)RPREC; - ColorFloat tc = Colors::highContrastColor(tid); - ColorFloat tcolor(tc.R,tc.G,tc.B,0.1f); - complex* znums = new complex[myDepth]; - Decimal col, row; - for (unsigned long i = tid; i < MAXITS; i+= threads) { - if (myRedraw) break; - col = cMinx+wscale*(rand() % RPREC); //Between cMinx and cMaxx - row = offset+hscale*(rand() % RPREC); //Between cMiny and cMaxy - complex c(col,row); - complex z = c; - unsigned its = 0; - while (std::abs(z) < 2.0l && its != myDepth) { - z = z * z + c; - znums[its] = z; - ++its; - } - if (its < myDepth) { //If we're not in the Mandelbrot set - z = c; - while (its > 0) { - --its; - if (znums[its].imag() < cMiny || znums[its].imag() > cMaxy || - znums[its].real() < cMinx || znums[its].real() > cMaxx) - continue; - int boxY = (znums[its].imag()-cMiny)/cph; - int boxX = (znums[its].real()-cMinx)/cpw; - #pragma omp atomic - ++(counter[boxY][boxX]); - can.Canvas::drawPixel(boxY, boxX, tcolor); - } - } - #pragma omp atomic - ++cycles; - if (cycles % (MAXITS/100) == 0) { - std::cout << (100*cycles)/MAXITS << "%" << std::endl; - can.handleIO(); - } - if (myRedraw || !can.isOpen()) - break; - } - delete [] znums; - znums = NULL; - } - if (!can.isOpen()) - return; - int maxIts = 0; - for (int i = 0; i < cwh; ++i) - for (int j = 0; j < cww; ++j) - if (counter[i][j] > maxIts) - maxIts = counter[i][j]; - std::cout << maxIts << " max iterations" << std::endl; - #pragma omp parallel num_threads(myThreads) - { - for (int i = omp_get_thread_num(); i < cwh; i += omp_get_num_threads()) - for (int j = 0; j < cww; ++j) { - float normalize = sqrt((float)counter[i][j]/maxIts); - can.Canvas::drawPixel(i, j, (ColorFloat)can.getPixel(i,j) * normalize); - } - } - while (can.isOpen() && !myRedraw) - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - } -} - diff --git a/src/tests/Mandelbrot/Buddhabrot.h b/src/tests/Mandelbrot/Buddhabrot.h deleted file mode 100644 index ea4de8320..000000000 --- a/src/tests/Mandelbrot/Buddhabrot.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Buddhabrot.h - */ - -#ifndef BUDDHABROT_H_ -#define BUDDHABROT_H_ - -#include - -#include "Mandelbrot.h" - -using namespace tsgl; - -/*! - * \class Buddhabrot - * \brief Draw a Buddhabrot. - * \details Contains all of the information necessary in order to draw a Buddhabrot. - * \details Child class of the Mandelbrot class. - * \see https://en.wikipedia.org/wiki/Buddhabrot for details on what a Buddhabrot is. - * \see Mandelbrot class - */ -class Buddhabrot : public Mandelbrot { -private: - int **counter; - int cww, cwh; -public: - - /*! - * \brief Explicitly construct a Buddhabrot object. - * \details Explicit constructor for the Buddhabrot class. - * \param threads The number of threads to use when drawing the Buddhabrot object to the CartesianCanvas. - * \param depth The number of iterations to go to in order to draw the Buddhabrot object. - * \return The constructed Buddhabrot object. - */ - Buddhabrot(unsigned threads, unsigned depth); - - /*! - * \brief Destroys a Buddhabrot object. - * \details Destructor for the Buddhabrot class. - * \return Frees up memory allocated to a Buddhabrot object. - */ - ~Buddhabrot(); - - /*! - * \brief Draw the Buddhabrot. - * \details Actually draws the Buddhabrot object to the CartesianCanvas. - * \param can Reference to the CartesianCanvas to draw on. - * \note This method overrides the draw() method from Mandelbrot. - * \note Cart is a typedef for CartesianCanvas. - */ - void draw(Cart& can); -}; - -#endif /* BUDDHABROT_H_ */ - diff --git a/src/tests/Mandelbrot/GradientMandelbrot.cpp b/src/tests/Mandelbrot/GradientMandelbrot.cpp deleted file mode 100644 index c2cba1c51..000000000 --- a/src/tests/Mandelbrot/GradientMandelbrot.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * GradientMandelbrot.cpp - */ - -#include "GradientMandelbrot.h" - -GradientMandelbrot::GradientMandelbrot(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} - -void GradientMandelbrot::draw(Cart& can) { - while (myRedraw) { - myRedraw = false; - #pragma omp parallel num_threads(myThreads) - { - unsigned int nthreads = omp_get_num_threads(); - double blockstart = can.getCartHeight() / nthreads; - unsigned int iterations; - double smooth; - for (unsigned int k = 0; k <= (can.getWindowHeight() / nthreads) && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... - long double row = blockstart * omp_get_thread_num() + can.getMinY() + can.getPixelHeight() * k; - for (long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { - complex c(col, row); - complex z(col, row); - smooth = exp(-std::abs(z)); - iterations = 0; - while (std::abs(z) < 2.0l && iterations != myDepth) { - iterations++; - z = z * z + c; - smooth += exp(-std::abs(z)); - } - smooth /= (myDepth + 1); - float value = (float)iterations/myDepth; - can.drawPoint(col, row, ColorHSV((float)smooth * 6.0f, 1.0f, value, 1.0f)); - if (myRedraw) break; - } - can.handleIO(); - if (myRedraw) break; - } - } - while (can.isOpen() && !myRedraw) - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - } -} - diff --git a/src/tests/Mandelbrot/GradientMandelbrot.h b/src/tests/Mandelbrot/GradientMandelbrot.h deleted file mode 100644 index 4f219ebf5..000000000 --- a/src/tests/Mandelbrot/GradientMandelbrot.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * GradientMandelbrot.h - */ - -#ifndef GRADIENTMANDELBROT_H_ -#define GRADIENTMANDELBROT_H_ - -#include "Mandelbrot.h" - -using namespace tsgl; - -/*! - * \class GradientMandelbrot - * \brief Draws a GradientMandelbrot set on a CartesianCanvas. - * \details Similar to a normal Mandelbrot set but with a smoother shading. - * \details Extends the Mandelbrot class and overrides its draw() function and setRedraw() function. - * \details Can zoom in and out of the Mandelbrot set by scrolling up and down on the mouse wheel (respectively). - * \see Mandelbrot class - */ -class GradientMandelbrot : public Mandelbrot { -public: - - /*! - * \brief Explicitly constructs a GradientMandelbrot set. - * \details Explicit constructor for the GradienMandelbrot class. - * \param threads The number of threads to use in the drawing of the GradientMandelbrot object. - * \param depth The number of iterations to go to in order to draw the GradientMandelbrot object. - * \return The GradientMandelbrot object ready to be drawn onto the CartesianCanvas. - */ - GradientMandelbrot(unsigned threads, unsigned depth); - - /*! - * \brief Draw the GradientMandelbrot set. - * \details Actually draws the GradientMandelbrot set onto the CartesianCanvas. - * \param can Reference to the CartesianCanvas to draw to. - * \note This method overrides the Mandelbrot class' draw() method. - * \note Cart is a typedef for a CartesianCanvas object. - */ - void draw(Cart& can); -}; - -#endif /* GRADIENTMANDELBROT_H_ */ - diff --git a/src/tests/Mandelbrot/Julia.cpp b/src/tests/Mandelbrot/Julia.cpp deleted file mode 100644 index 1e84b90f2..000000000 --- a/src/tests/Mandelbrot/Julia.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Julia.cpp - */ - -#include "Julia.h" - -Julia::Julia(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} - -void Julia::draw(Cart& can) { - const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas - VisualTaskQueue vq(CH); - while(myRedraw) { - myRedraw = false; - can.reset(); - unsigned next = 0; - vq.reset(); - #pragma omp parallel num_threads(myThreads) - { - vq.showLegend(); - int myNext; - while(true) { // As long as we aren't trying to render off of the screen... - #pragma omp critical - { - myNext = next++; - } - if (myNext >= can.getWindowHeight()) - break; - vq.update(myNext,RUNNING); - long double row = can.getMinY() + can.getPixelHeight() * myNext; - for(long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { - complex z(-0.8f, 0.156f); - complex c(col, row); - unsigned iterations = 0; - while (std::abs(c) < 2.0 && iterations != myDepth) { // Compute it until it escapes or we give up - iterations++; - c = c * c + z; - } - if(iterations == myDepth) { // If the point never escaped, draw it black - can.drawPoint(col, row, BLACK); - } else { // Otherwise, draw it with color based on how long it took - float mult = iterations/(float)myDepth; - can.drawPoint(col, row, Colors::blend(BLACK,WHITE,0.25f+0.5f*mult)*mult); - } - if (!can.isOpen() || myRedraw) break; - } - vq.update(myNext,FINISHED); - can.handleIO(); - if (myRedraw) break; - } - } -// manhattanShading(can); - std::cout << can.getTime() << std::endl; - while (can.isOpen() && !myRedraw) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - vq.sleep(); - } - } - vq.close(); -} diff --git a/src/tests/Mandelbrot/Julia.h b/src/tests/Mandelbrot/Julia.h deleted file mode 100644 index 081b5b0e2..000000000 --- a/src/tests/Mandelbrot/Julia.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Julia.h - */ - -#ifndef JULIA_H_ -#define JULIA_H_ - -#include "Mandelbrot.h" - -using namespace tsgl; - -/*! - * \class Julia - * \brief Draw a Julia set. - * \details Contains all of the information necessary in order to draw a Julia set onto a CartesianCanvas. - * \details Can zoom in and out of the Julia set by scrolling the mouse wheel up and down (respectively). - * \details Same is true when clicking the left mouse button (zooming in) and the right mouse button (zooming out). - * \details Can also clear the screen by pressing the spacebar. - */ -class Julia : public Mandelbrot { -public: - - /*! - * \brief Explicitly constructs a Julia object. - * \details Explicit constructor for the Julia class. - * \param threads The number of threads to use in drawing the Julia object onto the CartesianCanvas. - * \param depth The number of iterations to go to in order to draw the Julia object. - *\return The constructed Julia object. - */ - Julia(unsigned threads, unsigned depth); - - /*! - * \brief Draw the Julia object. - * \details Actually draws the Julia object to a CartesianCanvas. - * \param can Reference to the CartesianCanvas to draw on. - * \note Cart is a typedef for a CartesianCanvas object. - */ - void draw(Cart& can); -}; - -#endif /* JULIA_H_ */ diff --git a/src/tests/Mandelbrot/Mandelbrot.cpp b/src/tests/Mandelbrot/Mandelbrot.cpp deleted file mode 100644 index 5e3986600..000000000 --- a/src/tests/Mandelbrot/Mandelbrot.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Mandelbrot.cpp - */ - -#include "Mandelbrot.h" - -Mandelbrot::Mandelbrot(unsigned threads, unsigned depth) { - myThreads = threads; - myDepth = depth; - myFirstX = myFirstY = mySecondX = mySecondY = 0.0; - myRedraw = true; -} - -void Mandelbrot::manhattanShading(CartesianCanvas& can) { - int** canPoints = new int*[can.getWindowHeight()]; - for (int i = 0; i < can.getWindowHeight(); ++i) { - canPoints[i] = new int[can.getWindowWidth()]; - for (int j = 0; j < can.getWindowWidth(); ++j) { - ColorInt c = can.getPoint(j,i); - canPoints[i][j] = ((c.R == c.G) && (c.G == c.B) && (c.B == 0)) ? 0 : -1; - } - } - bool done = false; - int loop, cwh = can.getWindowHeight(), cww = can.getWindowWidth(); - for (loop = 0; !done; ++loop) { - done = true; - #pragma omp parallel for - for (int i = 0; i < cwh; ++i) { - for (int j = 0; j < cww; ++j) { - if (canPoints[i][j] != loop) - continue; - if (i > 0 && canPoints[i-1][j] == -1) - canPoints[i-1][j] = loop+1, done = false; - if (j > 0 && canPoints[i][j-1] == -1) - canPoints[i][j-1] = loop+1, done = false; - if (i < cwh-1 && canPoints[i+1][j] == -1) - canPoints[i+1][j] = loop+1, done = false; - if (j < cww-1 && canPoints[i][j+1] == -1) - canPoints[i][j+1] = loop+1, done = false; - } - } - } - - int sum = 0; - for (int i = 0; i < cwh; ++i) - for (int j = 0; j < cww; ++j) - sum += canPoints[i][j]; - float avg = (((float)sum)/cww)/cwh; - - #pragma omp parallel for - for (int i = 0; i < cwh; ++i) { - for (int j = 0; j < cww; ++j) { - float mult = sqrt(avg*((float)canPoints[i][j])/loop); - ColorFloat c = can.getPoint(j,i); - can.Canvas::drawPoint(j,i,c*mult); - } - } - - for (int i = 0; i < can.getWindowHeight(); ++i) - delete [] canPoints[i]; - delete [] canPoints; - canPoints = NULL; -} - -void Mandelbrot::bindings(Cart& can) { - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can, this]() { - can.clearProcedural(); - this->myRedraw = true; - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&can, this]() { - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->myFirstX, this->myFirstY); - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&can, this]() { - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->mySecondX, this->mySecondY); - if (!(this->myFirstX == this->mySecondX || this->myFirstY == this->mySecondY)) { - can.zoom(this->myFirstX, this->myFirstY, this->mySecondX, this->mySecondY); - this->myRedraw = true; - } - }); - can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&can, this]() { - Decimal x, y; - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); - can.zoom(x, y, 1.5); - this->myRedraw = true; - }); - can.bindToScroll([&can, this](double dx, double dy) { - Decimal x, y; - can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); - Decimal scale; - if (dy == 1) scale = .5; - else scale = 1.5; - can.zoom(x, y, scale); - this->myRedraw = true; - }); - } - -void Mandelbrot::draw(Cart& can) { - const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas - const int XBRD = 10; //Border for out progress bar - const int YBRD = 40; //Border for out progress bar - const int PBWIDTH = 800; - Canvas pCan(0, 0, PBWIDTH, 100, "Thread Workloads"); //Canvas for our progress bar - pCan.start(); - ProgressBar pb( - XBRD,YBRD,pCan.getWindowWidth()-XBRD*2,pCan.getWindowHeight()-YBRD*2, - 0,CH - (CH % myThreads),myThreads //Make the max PB value a multiple of myThreads - ); - for (int i = 0; i < myThreads; ++i) { - pCan.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); - } - while(myRedraw) { - myRedraw = false; - can.reset(); - #pragma omp parallel num_threads(myThreads) - { - unsigned tid = omp_get_thread_num(); - unsigned nthreads = omp_get_num_threads(); - ColorFloat tcolor = Colors::highContrastColor(tid); - double blocksize = can.getCartHeight() / nthreads; - double blockheight = CH / nthreads; - pb.update(blockheight*tid); - pCan.drawProgress(&pb); - long double startrow = blocksize * tid + can.getMinY(); - for(unsigned int k = 0; k <= blockheight && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... - pb.update(k+(CH*tid)/nthreads); - //Messy, but effective -// pCan.drawRectangle(XBRD,YBRD,pCan.getWindowWidth()-XBRD,pCan.getWindowHeight()-YBRD,pCan.getBackgroundColor(),true); - //Elegant, but flickery - pCan.drawProgress(&pb); - long double row = startrow + can.getPixelHeight() * k; - for(long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { - complex originalComplex(col, row); - complex c(col, row); - unsigned iterations = 0; - while (std::abs(c) < 2.0 && iterations != myDepth) { // Compute it until it escapes or we give up - iterations++; - c = c * c + originalComplex; - } - if(iterations == myDepth) { // If the point never escaped, draw it black - can.drawPoint(col, row, BLACK); - } else { // Otherwise, draw it with color based on how long it took - float mult = iterations/(float)myDepth; - can.drawPoint(col, row, Colors::blend(tcolor,WHITE,0.25f+0.5f*mult)*mult); - } - if (myRedraw) break; - } - can.handleIO(); - if (myRedraw) break; - } - } -// shadeCanvas(can); Optional shading - std::cout << can.getTime() << std::endl; - while (can.isOpen() && !myRedraw) { - pCan.sleep(); - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - } - } - if (pCan.isOpen()) - pCan.close(); - pCan.wait(); //Close our progress bar if we're done -} diff --git a/src/tests/Mandelbrot/Mandelbrot.h b/src/tests/Mandelbrot/Mandelbrot.h deleted file mode 100644 index 4c61cdf11..000000000 --- a/src/tests/Mandelbrot/Mandelbrot.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Mandelbrot.h - */ - -#ifndef MANDELBROT_H_ -#define MANDELBROT_H_ - -//Imports, constants.... -#include -#include -#include -#include -#include -#include - -using namespace tsgl; - -/*! - * \var complex - * \brief Typedef for std::complex. - */ -typedef std::complex complex; - -/*! - * \class Mandelbrot - * \brief Draw a Mandelbrot set. - * \details Contains the information necessary in order to draw a Mandelbrot set onto a CartesianCanvas. - * \details Can zoom in and out of the screen by scrolling up and down on the mouse wheel (respectively). - * \details Same is true if you click on the left mouse button (zoom in) and right mouse button (zoom out). - */ -class Mandelbrot { -private: - Decimal myFirstX, myFirstY, mySecondX, mySecondY; - -protected: - int myThreads; - unsigned int myDepth; - bool myRedraw; - - /*! - * \brief Shades the fractal using Manhattan distances - * \details This function may be called after the Mandelbrot has finished rendering to do some - * post-procecssing using the distances from non-escaped pixels to their nearest escaped pixels, - * using the average of their Manhattan distances. - */ - void manhattanShading(CartesianCanvas& can); - -public: - - /*! - * \brief Explicitly construct a Mandelbrot object. - * \details Explicit constructor for the Mandelbrot class. - * \param threads The number of threads to use in drawing the Mandelbrot object onto the CartesianCanvas. - * \param depth The number of iterations to go to in order to draw the Mandelbrot object. - * \return The constructed Mandelbrot object. - */ - Mandelbrot(unsigned threads, unsigned depth); - - /*! - * \brief Destroys a Mandelbrot object and any children of the Mandelbrot class. - * \details Destructor for the Mandelbrot class and its children. - * \note Does absolutely nothing. - */ - virtual ~Mandelbrot() {}; - - /*! - * \brief Binds buttons and/or mouse clicks. - * \details Binds buttons and/or mouse clicks needed for I/O capabilities. - * \details In this case: the mouse wheel, left and right mouse buttons. - * \param can Reference to the CartesianCanvas to have the buttons bound to. - * \note Cart is a typedef for CartesianCanvas. - */ - void bindings(Cart& can); - - /*! - * \brief Draw the Mandelbrot object. - * \details Actually draws the Mandelbrot object onto the CartesianCanvas. - * \param can Reference to the CartesianCanvas to draw on. - * \note Can be inherited by children classes who extend the Mandelbrot class. - * \note Cart is a typedef for CartesianCanvas. - */ - virtual void draw(Cart& can); -}; - -#endif /* MANDELBROT_H_ */ diff --git a/src/tests/Mandelbrot/Nova.cpp b/src/tests/Mandelbrot/Nova.cpp deleted file mode 100644 index 983438694..000000000 --- a/src/tests/Mandelbrot/Nova.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Nova.cpp - */ - -#include "Nova.h" - -Nova::Nova(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} - -void Nova::draw(Cart& can) { - const long double R = 1.0l; - while (myRedraw) { - myRedraw= false; - #pragma omp parallel num_threads(myThreads) - { - unsigned int nthreads = omp_get_num_threads(); - double blockstart = can.getCartHeight() / nthreads; - unsigned int iterations; - double smooth; - for (unsigned int k = 0; k <= (can.getWindowHeight() / nthreads) && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... - long double row = blockstart * omp_get_thread_num() + can.getMinY() + can.getPixelHeight() * k; - for (long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { - complex c(col, row); - complex z(1, 0); - smooth = exp(-std::abs(z)); - complex n, d, c1; - complex r(1, 0); - iterations = 0; - while (std::abs(z) < 2.0l && iterations != myDepth) { - iterations++; - n = z * z * z - 1.0l; - d = z * z * 3.0l; - z = z + c - (R * n / d); - smooth += exp(-std::abs(z)); - } - smooth /= myDepth; - if (smooth != smooth || smooth < 0) // Check to see if smooth is NAN - smooth = 0; - smooth = smooth - (int)smooth; - //float mult = iterations/(float)myDepth; - if (iterations == myDepth) - can.drawPoint(col, row, BLACK); - else - can.drawPoint(col, row, ColorHSV((float) smooth * 6.0f, 1.0f, (float) smooth, 1.0f)); - } - can.handleIO(); - if (myRedraw) break; - } - } - manhattanShading(can); - while (can.isOpen() && !myRedraw) - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - } -} diff --git a/src/tests/Mandelbrot/Nova.h b/src/tests/Mandelbrot/Nova.h deleted file mode 100644 index a750258e2..000000000 --- a/src/tests/Mandelbrot/Nova.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Nova.h - */ - -#ifndef NOVA_H_ -#define NOVA_H_ - -#include "Mandelbrot.h" - -using namespace tsgl; - -/*! - * \class Nova - * \brief Draws a Nova (Newton Fractal) set on a CartesianCanvas. - * \details Extends the Mandelbrot class and overrides its draw() function and setRedraw() function. - * \details Can zoom in and out of the Nova set by scrolling up and down on the mouse wheel (respectively). - * \see Mandelbrot class - */ -class Nova : public Mandelbrot { -public: - - /*! - * \brief Explicitly constructs a Nova set. - * \details Explicit constructor for the Nova class. - * \param threads The number of threads to use in the drawing of the Nova object. - * \param depth The number of iterations to go to in order to draw the Nova object. - * \return The Nova object ready to be drawn onto the CartesianCanvas. - */ - Nova(unsigned threads, unsigned depth); - - /*! - * \brief Draw the Nova set. - * \details Actually draws the Nova set onto the CartesianCanvas. - * \param can Reference to the CartesianCanvas to draw to. - * \note This method overrides the Mandelbrot class' draw() method. - * \note Cart is a typedef for a CartesianCanvas object. - */ - void draw(Cart& can); -}; - -#endif /* NOVA_H_ */ - diff --git a/src/tests/Pong/Ball.cpp b/src/tests/Pong/Ball.cpp deleted file mode 100644 index 676f6f47c..000000000 --- a/src/tests/Pong/Ball.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Ball.cpp - */ - -#include "Ball.h" - - - /*! - * \brief Explicitly construct the Ball object. - * \details Explicit constructor for the Ball object. - * \param can Reference to the Canvas that will have the Ball object. - * \param speed Reference to the speed of the Ball object. - * \return The constructed Ball object. - */ -Ball::Ball(Canvas& can, int & speed) { - mySpeed = speed; - myX = -8; - myY = -8; - do { - myDir = randfloat(1000) * 2 * PI; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while(myXX > -4 && myXX < 4); - myCircle = new Circle(myX, myY, 0, 8, 0,0,0, WHITE); - can.add(myCircle); -} - - /*! - * \brief Accessor for the Ball object's current x-coordinate. - * \return myX The x-coordinate of the Ball object. - */ -float Ball::getX() const { - return myX; -} - - /*! - * \brief Accessor for the Ball object's current y-coordinate. - * \return myY The y-coordinate of the Ball object. - */ -float Ball::getY() const { - return myY; -} - - /*! - * \brief Invert the Ball's direction. - * \details The Ball's direction must be inverted whenever it collides with a Paddle object or - * when it touches one of the boundary walls in the game of Pong. - * \param choice Determines which coordinate value to invert (y-coordinate = 0, x-coordinate = 1). - * \see Paddle class, Pong class. - */ -void Ball::invert(int choice) { - if(choice == 0) { - myYY = -myYY; - } else if(choice == 1) { - myXX = -myXX; - myYY += randfloat(1000) * 2 - 1; - } -} - - /*! - * \brief Move the Ball object. - * \details Actually moves the Ball object around. - */ -void Ball::move() { - myX += myXX; - myY += myYY; - myCircle->setCenter(myX, myY, 0); -} - - /*! - * \brief Reset the Ball object's position. - * \details After a point is earned in the game of Pong, the Ball object's position must be reset back - * to the middle of the Canvas and its direction must be randomized again. - * \param can Reference to the Canvas object that has the Ball object. - */ -void Ball::reset(Canvas& can) { - myX = -8; - myY = -8; - do { - myDir = randfloat(1000) * 2 * PI; - myXX = mySpeed * cos(myDir); - myYY = mySpeed * sin(myDir); - } while (myXX > -4 && myXX < 4); -} diff --git a/src/tests/Pong/Ball.h b/src/tests/Pong/Ball.h deleted file mode 100644 index 322f5c471..000000000 --- a/src/tests/Pong/Ball.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Ball.h - */ - -#ifndef BALL_H_ -#define BALL_H_ - -#include - -using namespace tsgl; - -/*! - * class Ball - * \brief We can't play Pong without a Ball! - * \details Creates the ball needed in order to play Pong. - * \details The constructor determines the speed and direction of the ball. - * \details The draw() method draws the ball onto the Canvas object. - * \details The ball's position is always reset after a point has been earned in the game. - * \details Collisions with the paddle or the boundaries are not handled here; they are handled in the Pong class' draw() method. - * \see Paddle class, Pong class. - */ -class Ball { - public: - Ball(Canvas& can, int & speed); - - float getX() const; - - float getY() const; - - void invert(int choice); - - void move(); - - void reset(Canvas& can); - - /*! - * \brief Destroys the Ball object. - */ - virtual ~Ball() { delete myCircle; } - -private: - float myX, myY, myXX, myYY, mySpeed, myDir; - Circle* myCircle; -}; - -#endif /* BALL_H_ */ diff --git a/src/tests/Pong/Paddle.cpp b/src/tests/Pong/Paddle.cpp deleted file mode 100644 index 091c7d9c2..000000000 --- a/src/tests/Pong/Paddle.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Paddle.cpp - */ - -#include "Paddle.h" - - /*! - * \brief Explicitly constructs a Paddle object. - * \details Explicit constructor for a Paddle object. - * \param can Reference to the Canvas to have the Paddle object on. - * \param speed Reference to the speed of the Paddle object. - * \return The constructed Paddle object. - */ -Paddle::Paddle(Canvas& can, int & speed, int side) { - mySpeed = speed; - myDir = myPoints = 0; - myY = - 32; - myRect = new Rectangle(0,myY,0,24,64,0,0,0, BLACK); - if(side == -1) { //Left side - myRect->setColor(BLUE); - myRect->setCenterX(-can.getWindowWidth() / 2 + 20); - } else if(side == 1) { //Right side - myRect->setColor(RED); - myRect->setCenterX(can.getWindowWidth() / 2 - 20); - } - can.add(myRect); -} - - /*! - * \brief Binds the buttons. - * \details Binds the buttons with the Canvas. In this case, the keys that move the paddle up and down. - * \param can Reference to the Canvas to bind the keys to. - * \param side The side that the Paddle object is on (left = -1 and the W and S keys are bound, right = 1 and the Up and Down arrow keys are bound). - */ -void Paddle::bindings(Canvas& can, int side) { - if(side == 1) { //Right - can.bindToButton(TSGL_UP, TSGL_PRESS, [this]() {this->myDir = 1;}); - can.bindToButton(TSGL_DOWN, TSGL_PRESS, [this]() {this->myDir = -1;}); - can.bindToButton(TSGL_UP, TSGL_RELEASE, [this]() {if (this->myDir == 1) this->myDir = 0;}); - can.bindToButton(TSGL_DOWN, TSGL_RELEASE, [this]() {if (this->myDir == -1) this->myDir = 0;}); - } else if(side == -1) { //Left - can.bindToButton(TSGL_W, TSGL_PRESS, [this] () {this->myDir = 1;}); - can.bindToButton(TSGL_S, TSGL_PRESS, [this] () {this->myDir = -1;}); - can.bindToButton(TSGL_W, TSGL_RELEASE, [this] () {if (this->myDir == 1) this->myDir = 0;}); - can.bindToButton(TSGL_S, TSGL_RELEASE, [this] () {if (this->myDir == -1) this->myDir = 0;}); - } -} - - /*! - * \brief Increments the Paddle object's score in the game of Pong. - */ -void Paddle::increment() { - ++myPoints; -} - - /*! - * \brief Actually Moves the Paddle object up or down. - */ -void Paddle::move() { - myY += mySpeed * myDir; - myRect->changeYBy(mySpeed * myDir); -} - - /*! - * \brief Accessor for the score of the Paddle object. - * \return myPoints The current score of the Paddle object in the game of Pong. - */ -int Paddle::getPoints() const { - return myPoints; -} - - /*! - * \brief Accessor for the current y-coordinate of the Paddle object. - * \return myY The y-coordinate of the Paddle object. - */ -float Paddle::getY() const { - return myY; -} - - /*! - * \brief Mutator for the direction of the Paddle object. - * \details Changes the current direction of the Paddle object (up or down). - */ -void Paddle::setDir(int direction) { - myDir = direction; -} diff --git a/src/tests/Pong/Paddle.h b/src/tests/Pong/Paddle.h deleted file mode 100644 index f5b56960b..000000000 --- a/src/tests/Pong/Paddle.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Paddle.h - */ - -#ifndef PADDLE_H_ -#define PADDLE_H_ - -#include -#include "Ball.h" - -using namespace tsgl; - -/*! - * class Paddle - * \brief How can you hit a ball without a paddle? - * \details Creates a Paddle in order to play the game, Pong. - * \details The W and S keys move the left paddle, the Up and Down arrow keys move the right paddle in the game. - * \details Collisions with the ball are not handled here; they are handled in the Pong class' draw() method. - * \details The left and right paddles in the game are created from this class; they are essentially the same object. - * However, there are side parameters in some of the methods that determine which side to place the Paddle object on and how to treat - * the Paddle object (either as the left or the right paddle in the game). The Pong class handles how to distribute points to the Paddle objects - * in the game (the Paddle class only has an increment() method that increments its score counter; the Pong class determines which object should - * call that method when a point is earned). - * \see Ball class, Pong class. - */ -class Paddle { -public: - Paddle(Canvas& can, int & speed, int side); - - void bindings(Canvas& can, int side); - - void draw(Canvas& can, int side); - - void increment(); - - void move(); - - int getPoints() const; - - float getY() const; - - void setDir(int direction); - - /** - * \brief Destroys the Paddle object. - */ - ~Paddle() { delete myRect; } - -private: - int myDir; //-1 = up, 1 = down, 0 = stationary - int myPoints; //Score - int mySpeed; //Speed - float myY; //y-coordinate for Paddle - Rectangle * myRect; -}; - -#endif /* PADDLE_H_ */ diff --git a/src/tests/Pong/Pong.cpp b/src/tests/Pong/Pong.cpp deleted file mode 100644 index 8ac917cc6..000000000 --- a/src/tests/Pong/Pong.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Pong.cpp - */ - -#include "Pong.h" - -using namespace tsgl; - - /*! - * \brief Explicitly construct the game, Pong. - * \details Explicit constructor for the game, Pong. It sets up the Paddle objects and the Ball object - * in order to play. - * \param can Reference to the Canvas to use when playing Pong. - * \param ballSpeed Reference to the ball speed to use in the game. - * \param paddleSpeed Reference to the paddle speed to use in the game. - */ -Pong::Pong(Canvas& can, int & ballSpeed, int & paddleSpeed) { - leftPaddle = new Paddle(can, paddleSpeed, -1); // Create the Paddle objects and the Ball object - rightPaddle = new Paddle(can, paddleSpeed, 1); - //Bind the buttons - leftPaddle->bindings(can, -1); // W & S keys - rightPaddle->bindings(can, 1); // Up and Down arrow keys - pongBall = new Ball(can, ballSpeed); - // leftScore = new Text(L"0", can.getWindowWidth() / 2-64, 40, 32, ColorFloat(0.0f, 0.0f, 1.0f, 1.0f)); - // rightScore = new Text(L"0", can.getWindowWidth()/2+64, 40, 32, ColorFloat(1.0f, 0.0f, 0.0f, 1.0f)); - // can.add(leftScore); can.add(rightScore); -} - - /*! - * \brief Draw the game of Pong. - * \details Actually draws all of the necessary components in order to play Pong. - * This also includes any necessary button bindings in order to move the Paddle objects. - * \param can Reference to the Canvas to draw on. - * \see Paddle class, Ball class. - */ -void Pong::draw(Canvas& can) { - // While the window has not been closed.... - while (can.isOpen()) { - can.sleep(); - // Move the ball - pongBall->move(); - // Handle ball boundary collisions - if (pongBall->getX() > can.getWindowWidth() / 2 + 8) { - leftPaddle->increment(); // Increment the points - // leftScore->setText( std::to_wstring(leftPaddle->getPoints())); - pongBall->reset(can); // Reset the ball's position - } else if (pongBall->getX() < -can.getWindowWidth() / 2 -8) { - rightPaddle->increment(); - // rightScore->setText( std::to_wstring(rightPaddle->getPoints())); - pongBall->reset(can); - } else if (pongBall->getY() > can.getWindowHeight() / 2 - 8 || pongBall->getY() < -can.getWindowHeight() / 2 + 8) pongBall->invert(0); //Invert the ball's y-coordinate changer - // Handle ball paddle collisions - // handle left - if (pongBall->getX() - 8 < -can.getWindowWidth() / 2 + 32 && - pongBall->getX() - 8 > -can.getWindowWidth() / 2 + 16 && - pongBall->getY() > leftPaddle->getY() - 32 && - pongBall->getY() < leftPaddle->getY() + 32) - { - pongBall->invert(1); - } - // handle right - else if (pongBall->getX() + 8 > can.getWindowWidth() / 2 - 32 && - pongBall->getX() + 8 < can.getWindowWidth() / 2 - 16 && - pongBall->getY() > rightPaddle->getY() - 32 && - pongBall->getY() < rightPaddle->getY() + 32) - { - pongBall->invert(1); - } - // Move the paddles if necessary - leftPaddle->move(); - rightPaddle->move(); - } -} - -/** - * \brief Destroys the Pong game object. - */ -Pong::~Pong() { - delete pongBall; - delete leftPaddle; - delete rightPaddle; - // delete leftScore; - // delete rightScore; -} \ No newline at end of file diff --git a/src/tests/Pong/Pong.h b/src/tests/Pong/Pong.h deleted file mode 100644 index c8af2d11a..000000000 --- a/src/tests/Pong/Pong.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Pong.h - */ - -#ifndef PONG_H_ -#define PONG_H_ - -#include -#include -#include -#include -#include -#include "Ball.h" -#include "Paddle.h" -#include "Util.h" - -using namespace tsgl; - -/*! - * \class Pong - * \brief An old-school classic! - * \details Draw the interactive game of Pong. The two paddles are objects and the ball is also an object. - * \details The constructor constructs the two paddle objects and the ball object. - * \details Use the W and S keys in order to move the left paddle, the Up and Down arrow keys in order to move the right paddle. - * \details Everything else is handled in the draw() method (button bindings, score keeping, drawing the objects and the game itself, - * ball collisions with the paddles and the boundaries). - * \see Paddle class, Ball class. - */ -class Pong { -public: - - Pong(Canvas& can, int & ballSpeed, int & paddleSpeed); - - void draw(Canvas& can); - - ~Pong(); - -private: - Paddle *leftPaddle, *rightPaddle; - Ball *pongBall; - // Text *leftScore, *rightScore; -}; - -#endif /* PONG_H_ */ diff --git a/src/tests/ProducerConsumer/Consumer.cpp b/src/tests/ProducerConsumer/Consumer.cpp deleted file mode 100644 index 548bce74c..000000000 --- a/src/tests/ProducerConsumer/Consumer.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "Consumer.h" - -/** - * Default-constructor for the Consumer class. - * return: The constructed Consumer object. - */ -Consumer::Consumer() : PCThread() { } - -/** - * Explicit-constructor for the Consumer class. - * param: sharedBuffer, a reference to the Queue object that is shared between the Consumer and Producer. - * param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming object from the Queue. - * return: The constructed Consumer object. - */ -Consumer::Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { - myX = can.getWindowWidth() - 50; - myShape = new Rectangle(myX, myY, 40, 40, ColorInt(0, 0, 0), BLACK); - myShape->setCenter(myX, myY); - myShape->setLayer(1); - myCountLabel->setCenter(myX, myY); - myCountLabel->setLayer(2); - myCan->add(myShape); -} - -/** - * locks the Queue for consumption - */ -void Consumer::lock() { - //Show waiting status - myShape->setColor( BLACK, WHITE ); - myCountLabel->setColor(WHITE); - if( myItem ) { - myCan->remove( myItem ); - delete myItem; - myItem = NULL; - } - - buffer->consumerLock(); //Request lock - myShape->setColor( WHITE, BLACK ); - myCountLabel->setColor(BLACK); - while( paused ) {} -} - -/** - * act goes through the process of consuming an item from Queue - */ -void Consumer::act() { - myItem = buffer->remove(); //Take out data from the Queue and consume it - int endX = myShape->getCenterX()-50, endY = myShape->getCenterY(); - animateItem(endX, endY); - while( paused ) {} - ColorFloat* fillColor = myItem->getFillColor(); - myShape->setColor( fillColor, BLACK ); //Change Consumer color to Item color - myCountLabel->setColor(fillColor->getContrast()); - delete[] fillColor; - count++; myCountLabel->setText( std::to_wstring(count) ); - if(count == 10) myCountLabel->setCenter(myX, myY); - if(count == 100) { - myCountLabel->setFontSize(22); - myCountLabel->setCenter(myX, myY); - } -} - -/** - * unlocks the Queue after consuming an item - */ -void Consumer::unlock() { - // myCan->remove(myItem); - // delete myItem; - // myItem = NULL; - buffer->consumerUnlock(); - while( paused ) {} -} - -Consumer::~Consumer() { - if(myItem) { - delete myItem; - myItem = NULL; - } -} diff --git a/src/tests/ProducerConsumer/Consumer.h b/src/tests/ProducerConsumer/Consumer.h deleted file mode 100644 index 427bbee76..000000000 --- a/src/tests/ProducerConsumer/Consumer.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Consumer.h contains the class necessary in order to create a Consumer object for the Producer-Consumer visualization. - */ -#ifndef CONSUMER_H_ -#define CONSUMER_H_ - -#include -#include -#include "Queue.h" -#include "PCThread.h" -using namespace tsgl; - -/** - * Consumer class inherits from the Thread class in order to create a Consumer object. - * Inheritance: Thread class. - * Implements the run() method, which calls the consume() method. - */ -class Consumer : public PCThread { -public: - Consumer(); //Default constructor - ~Consumer(); - Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can); //Explicit constructor - void lock(); - void act(); - void unlock(); -}; - -#endif /* CONSUMER_H_ */ diff --git a/src/tests/ProducerConsumer/PCThread.cpp b/src/tests/ProducerConsumer/PCThread.cpp deleted file mode 100644 index da60b3ef0..000000000 --- a/src/tests/ProducerConsumer/PCThread.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "PCThread.h" - -std::atomic PCThread::paused(false); - -/** - * \brief Default-constructor for the PCThread class. - * \return: The constructed PCThread object. - */ -PCThread::PCThread() : Thread() { - buffer = NULL; - myCan = NULL; - myShape = NULL; - myItem = NULL; - myArrow = NULL; - myCountLabel = NULL; - count = 0; - myX = myY = 0; -} - -/** - * Explicit-constructor for the PCThread class. - * param: sharedBuffer, a reference to the Queue object that is shared between the Producer and Consumer. - * param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming objects from the Queue. - * return: The constructed PCThread object. - */ -PCThread::PCThread(Queue & sharedBuffer, unsigned long id, Canvas & can) : Thread(id) { - count = 0; - buffer = &sharedBuffer; //Get the handle to the Queue - myCan = &can; //Get the handle to the Canvas - myY = 50 * (id + 1); - myX = 0; //Set in subclass constructor - myItem = NULL; - myArrow = NULL; - myCountLabel = new Text( std::to_wstring(count), myX, myY+5, 24, WHITE); - myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); - // myCountLabel->setLayer(3); - myCan->add( myCountLabel ); -} - -//TODO: comment and improve -void PCThread::wait() { - myCan->sleepFor( (rand()%10+3.0)/5.0 ); - while( paused ) {} -} - -void PCThread::run() { - while( myCan->isOpen() ) { - wait(); - lock(); - act(); - unlock(); - } -} - -void PCThread::animateItem(int endX, int endY) { - const int steps = 20; - const float timeInterval = 0.7; - int startX = myItem->getCenterX(), startY = myItem->getCenterY(); - - myArrow = new Arrow (startX, startY, endX, endY, BLACK, false); - myCan->add(myArrow); - - float deltaX = (endX - startX) / float(steps); //Change in x each step - float deltaY = (endY - startY) / float(steps); //Change in y each step - - for(int i = 0; i <= steps; i++) { - myItem->setCenter( round( startX+ i*deltaX ), round(startY+i*deltaY)); - myCan->sleepFor( timeInterval / steps ); - while( paused ) {} - } - myCan->remove(myArrow); - delete myArrow; - myArrow = NULL; -} - -PCThread::~PCThread() { - delete myCountLabel; - delete myShape; - if(myItem) { - delete myItem; - myItem = NULL; - } - if(myArrow) { - delete myArrow; - myArrow = NULL; - } -} diff --git a/src/tests/ProducerConsumer/PCThread.h b/src/tests/ProducerConsumer/PCThread.h deleted file mode 100644 index 454cd6471..000000000 --- a/src/tests/ProducerConsumer/PCThread.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * PCThread.h contains the subclass of Thread and superclass of Producer and Consumer for the Producer-Consumer visualization. - * Includes details for drawing Threads to the Canvas - */ -#ifndef PCTHREAD_H_ -#define PCTHREAD_H_ - -#include -#include "Thread.h" -#include "Queue.h" -#include -#include -using namespace tsgl; - -/** - * PChread class inherits from the Thread class in order to create a PCThread object. - * Inheritance: Thread class. - */ -class PCThread : public Thread { -public: - PCThread(); //Default constructor - virtual ~PCThread(); - PCThread(Queue & sharedBuffer, unsigned long id, Canvas & can); //Explicit constructor - virtual void run(); - virtual void wait(); - virtual void lock() = 0; //Must be implemented by subclass - virtual void act() = 0; //Must be implemented by subclass - virtual void unlock() = 0; //Must be implemented by subclass - static std::atomic paused; -protected: - void animateItem(int endX, int endY); - int myX, myY; //Center coordinates for the PCThread - int count; //Number of colors processed (produced or consumed) - Queue * buffer; //Handle to the current buffer - Canvas * myCan; //Handle to the Canvas - ConvexPolygon * myShape; - Arrow * myArrow; - Star * myItem; //Handle to item Produced/Consumed - Text * myCountLabel; //Text label for number Produced/Consumed -}; - -#endif /* PCTHREAD_H_ */ diff --git a/src/tests/ProducerConsumer/Producer.cpp b/src/tests/ProducerConsumer/Producer.cpp deleted file mode 100644 index 2813e3213..000000000 --- a/src/tests/ProducerConsumer/Producer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "Producer.h" - -/** - * Default-constructor for the Producer class. - * @return: The constructed Producer object. - */ -Producer::Producer() : PCThread() { } - -/** - * Explicit-constructor for the Producer class. - * @param: sharedBuffer, a reference to the Queue object that is shared between the Consumer and Producer. - * @param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * @param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue producing object into the Queue. - * @return: The constructed Producer object. - */ -Producer::Producer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { - myX = 50; //Set the x-coordinate to 50 - myShape = new Circle(myX, myY, 20, ColorInt(0, 0, 0), BLACK); - myShape->setLayer(1); - myCountLabel->setBottomLeftCorner(myX - 5, myY + 10); - myCountLabel->setLayer(2); - myCan->add(myShape); -} - -/** - * randColor generates a new random ColorInt - */ -ColorInt Producer::randColor() { - int red = rand() % 255; - int green = rand() % 255; - int blue = rand() % 255; - return ColorInt(red, green, blue); -} - -/** - * nextItem generates a new Star with a random color - */ -Star* Producer::nextItem() { - return new Star(myX+50, myY, 20, 5, randColor() ); -} - -/** - * wait takes some time to find the next color - */ -void Producer::wait() { - myItem = nextItem(); - ColorFloat * fillColor = myItem->getFillColor(); - myShape->setColor( fillColor, BLACK ); - myCountLabel->setColor(fillColor->getContrast()); - delete[] fillColor; - PCThread::wait(); -} - -/** - * locks the Queue for production - */ -void Producer::lock() { - myCan->add( myItem ); - myShape->setColor( BLACK, WHITE ); - myCountLabel->setColor(WHITE); - buffer->producerLock(); - myShape->setColor( WHITE, BLACK ); - myCountLabel->setColor(BLACK); - while( paused ) {} -} - -/** - * act goes through the process of adding a produced item to Queue - */ -void Producer::act() { - while( paused ) {} - myCan->sleep(); - int i = buffer->getLastIndex(); - buffer->append(myItem, getId()); //Append something and pass your id along too - //Show Item added to Queue - float itAngle = (i*2*PI + PI)/8; // angle of item - int endX = 100*cos(itAngle)+300, endY = 100*sin(itAngle)+175; - animateItem(endX, endY); - - count++; myCountLabel->setText( std::to_wstring(count) ); - if(count == 10) myCountLabel->setCenter(myX, myY); - if(count == 100) { - myCountLabel->setFontSize(22); - myCountLabel->setCenter(myX, myY); - } - myItem = NULL; -} - -/** - * unlocks the Queue after production - */ -void Producer::unlock() { - buffer->producerUnlock(); //TODO: change name of method - while( paused ) {} -} - -Producer::~Producer() { - if(myItem) { - delete myItem; - myItem = NULL; - } -} diff --git a/src/tests/ProducerConsumer/Producer.h b/src/tests/ProducerConsumer/Producer.h deleted file mode 100644 index f0e5f909a..000000000 --- a/src/tests/ProducerConsumer/Producer.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Producer.h contains the class necessary in order to create a Producer object for the Producer-Consumer visualization. - */ -#ifndef PRODUCER_H_ -#define PRODUCER_H_ - -#include -#include -#include "Queue.h" -#include "PCThread.h" -using namespace tsgl; - -/** - * Producer class creates a Producer object and inherits from the Thread class. - * Inheritance: Thread class. - * Implements the abstract run() method from the Thread class so that the pthread runs the produce() method. - */ -class Producer : public PCThread { -public: - Producer(); //Default constructor - ~Producer(); - Producer(Queue & sharedBuffer, unsigned long id, Canvas & can); //Size of data to generate and id of pthread - void wait(); - void lock(); - void act(); - void unlock(); - -private: - Star* nextItem(); - ColorInt randColor(); -}; - -#endif /* PRODUCER_H_ */ diff --git a/src/tests/ProducerConsumer/Queue.h b/src/tests/ProducerConsumer/Queue.h deleted file mode 100644 index d027c2cc7..000000000 --- a/src/tests/ProducerConsumer/Queue.h +++ /dev/null @@ -1,289 +0,0 @@ -/** - * Queue.h contains the class template code in order to create a custom Queue object. - * Used in the Producer-Consumer visualization in order to visualize a shared buffer amongst pthreads. - * A mutex and condition variables are used to synchronize accesses to the Queue and to avoid race conditions. - * (Condition variable logic was adapted from the TS_Queue code given to me by Professor Joel Adams). - * (Self-synchronization logic was also adapted from TS_Queue). - */ - -#ifndef QUEUE_H_ -#define QUEUE_H_ - -#include -#include -#include -#include -using namespace tsgl; - -template - -/** - * Queue class contains the data necessary in order to create a custom Queue object. - * Used as a shared buffer in the Producer-Consumer visualization. - */ -class Queue { -public: - Queue(); //Default constructor - Queue(int size, Canvas & can); //Explicit Constructor - void append(Item it, int proId); //Push an Item onto the Queue - Item remove(); //Get an Item off of the Queue - //Accessors - Item* getArray(); - int getCount(); - Item getFirst(); - Item getLast(); - int getCapacity(); - int* getPthreadIds(); //Stored Pthread ids - int getLastIndex() { return myLast; } - int getFirstIndex() { return myFirst; } - //Utility methods - bool isEmpty() const; - bool isFull() const; - void producerLock(); - void producerUnlock(); - void consumerLock(); - void consumerUnlock(); - ~Queue(); //Destructor - -private: - Item * myArray; //Array of data - int mySize, myCount, myFirst, myLast; //Size, number of elements, and first and last indice - pthread_mutex_t myMutex; - //Broadcast a signal indicating that the Queue is not full (append, Producers) and that the Queue is not empty (remove, Consumers) - pthread_cond_t notEmpty; //Condition variable for remove - pthread_cond_t notFull; //Condition variable for append - pthread_cond_t notOpen; //Condition variable for determining if the Canvas is open - //Reference to the Canvas - Canvas * myCan; - int * myPthreadIds; //Producer pthread ids (to color the rectangles around the Queue in the visualization) -}; - -/** - * Default constructor for the Queue class. - */ -template -Queue::Queue() { - myArray = NULL; - myPthreadIds = NULL; - mySize = myCount = myFirst = myLast = 0; - pthread_cond_init( ¬Empty, NULL ); //Initialize the condition variables and the mutex - pthread_cond_init( ¬Full, NULL ); - pthread_cond_init( ¬Open, NULL ); - pthread_mutex_init( &myMutex, NULL ); - myCan = NULL; -} - -/** - * Explicit-constructor for the Queue class. - * @param: size, the size of the Queue. - */ -template -Queue::Queue(int size, Canvas & can) { - myArray = new Item[size]; - myPthreadIds = new int[size]; - mySize = size; //Max number of elements to be in the Queue - myCount = 0; //Number of elements currently in the Queue - myFirst = myLast = 0; - pthread_cond_init( ¬Empty, NULL ); //Initialize the condition variables and the mutex - pthread_cond_init( ¬Full, NULL ); - pthread_cond_init( ¬Open, NULL ); - pthread_mutex_init( &myMutex, NULL ); - myCan = &can; -} - -/** - * append() puts an item into the Queue. - * @param: it, an Item to put into the Queue. - * @param: proId, an int representing the pthread id. - * (Pthread condition variable logic adapted from TS_Queue code given to me by Professor Joel Adams). - */ -template -void Queue::append(Item it, int proId) { - myArray[myLast] = it; - myLast = (myLast + 1) % mySize; //Increment the indexer to my last item - myCount++; - myPthreadIds[myLast] = proId; //Store the most recent pthread id - pthread_cond_signal(¬Empty); //Signal that the Queue is not empty. - myPthreadIds[myLast] = proId; //Store the most recent pthread id -} - -/** - * producerLock() locks the Queue for the thread to append an item - */ -template -void Queue::producerLock() { - pthread_mutex_lock( &myMutex ); //Lock the mutex so only one thread can append - while(myCount == mySize) { - pthread_cond_wait(¬Full, &myMutex); //The Queue is full, please wait until it is not full. - } - if(!myCan->isOpen()) { //If the Canvas is not open, wake up all of the sleeping threads - pthread_cond_broadcast( ¬Open ); - pthread_mutex_unlock( &myMutex ); - } //Else... -} - -/** - * producerUnlock() unlocks the Queue after the thread appends an item - */ -template -void Queue::producerUnlock() { - pthread_cond_signal(¬Empty); //Signal that the Queue is not empty. - pthread_mutex_unlock( &myMutex ); //Unlock for other threads -} - -/** - * remove() takes an Item out of the Queue. - * @return: temp, an Item that was taken out of the Queue. - * (Pthread condition variable logic adapted from TS_Queue code given to me by Professor Joel Adams). - */ -template -Item Queue::remove() { - //ColorInt white(255, 255, 255); - Item temp = myArray[myFirst]; // Item to be removed from Queue - //myArray[myFirst] = white; - myFirst = (myFirst + 1) % mySize; - myCount--; - return temp; -} - -/** - * consumerLock() locks the Queue for the thread to remove an item - */ -template -void Queue::consumerLock() { - pthread_mutex_lock( &myMutex ); //Lock the mutex - if(!myCan->isOpen()) { //If the Canvas is not open, wake up all of the sleeping threads - pthread_cond_broadcast( ¬Open ); - pthread_mutex_unlock( &myMutex ); - } else { //Else... - while(myCount == 0) { - pthread_cond_wait(¬Empty, &myMutex); //The Queue is empty, please wait until it is not empty - } - } -} - -/** - * consumerUnlock() locks the Queue after the thread to removes an item - */ -template -void Queue::consumerUnlock() { - pthread_cond_signal(¬Full); //Signal that the Queue is not full - pthread_mutex_unlock( &myMutex ); //Unlock before returning -} - -//Accessors - -/** - * getArray() is the accessor method for the array of the Queue. - * @return: array, the array of items in the Queue. - */ -template -Item* Queue::getArray() { - Item * array; - pthread_mutex_lock( &myMutex ); - array = myArray; - pthread_mutex_unlock( &myMutex ); - return array; -} - -/** - * getCount() is the accessor method for the number of elements currently in the Queue. - * @return: count, an int representing the current number of elements in the Queue. - */ -template -int Queue::getCount() { - int count; - pthread_mutex_lock( &myMutex ); - count = myCount; - pthread_mutex_unlock( &myMutex ); - return count; -} - -/** - * getFirst() is the accessor method for the first element in the Queue. - * @return: first, an Item representing the first element in the Queue. - */ -template -Item Queue::getFirst() { - Item first; - pthread_mutex_lock( &myMutex ); - first = myArray[myFirst]; - pthread_mutex_unlock( &myMutex ); - return first; -} - -/** - * getLast() is the accessor method for the last element in the Queue. - * @return: last, an Iteme representing the last element in the Queue. - */ -template -Item Queue::getLast() { - Item last; - pthread_mutex_lock( &myMutex ); - last = myArray[(myLast-1+mySize) % mySize]; - pthread_mutex_unlock( &myMutex ); - return last; -} - -/** - * getCapacity() is the accessor method for the size of the Queue. - * @return: size, an int representing the size of the Queue. - */ -template -int Queue::getCapacity() { - int size; - pthread_mutex_lock( &myMutex ); - size = mySize; - pthread_mutex_unlock( &myMutex ); - return size; -} - -/** - * getPthreadIds() is the accessor method for the stored pthread ids of the Producers. - * (They are used to determine the color of the Rectangle drawn around the circles in the visualization). - * @return: ids, the array of stored pthread ids. - */ -template -int* Queue::getPthreadIds() { - int * ids; - pthread_mutex_lock( &myMutex ); - ids = myPthreadIds; - pthread_mutex_unlock( &myMutex ); - return ids; -} - -//Utility methods - -/** - * isEmpty() determines if the Queue is empty or not. - * @return: myCount == 0, a boolean expression which evalutes to true or false. - */ -template -bool Queue::isEmpty() const { - return myCount == 0; -} - -/** - * isFull() determines if the Queue is full or not. - * @return: myCount == mySize, a boolean expression which evalutes to true or false. - */ -template -bool Queue::isFull() const { - return myCount == mySize; -} - -/** - * Destructor for the Queue. - */ -template -Queue::~Queue() { - pthread_cond_destroy(¬Empty); //Destroy the condition variables and mutex - pthread_cond_destroy(¬Full); - pthread_cond_destroy(¬Open); - pthread_mutex_destroy(&myMutex); - delete [] myArray; //Deallocate the array - delete [] myPthreadIds; - myArray = NULL; -} - -#endif /*QUEUE_H_*/ diff --git a/src/tests/ProducerConsumer/Thread.cpp b/src/tests/ProducerConsumer/Thread.cpp deleted file mode 100644 index 2236127f7..000000000 --- a/src/tests/ProducerConsumer/Thread.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "Thread.h" - -/** - * Default-constructor for a Thread object. - * @return: The constructed Thread object with id == 0. - */ -Thread::Thread() { - myId = 0; -} - -/** - * Explicit-constructor for a Thread object. - * @param: myId, an unsigned long representing the id for the Thread object. - * @return: The constructed Thread object with id == myId. - */ -Thread::Thread(unsigned long id) { - myId = id; -} - -/** - * threadFunction() is the function that the pthread should run as soon as it is created. - * @param: obj, a void* that will be statically casted into a Thread object. - * It will run the run() function, which will be defined by the inheriting subclass. - ^ @return: NULL. - */ -void* Thread::threadFunction(void* obj) { - Thread * thread = static_cast(obj); - thread->run(); //This NEEDS to be defined by the subclass - pthread_exit(0); //Exit upon completion -} - -/** - * start() function creates the pthread inside of the Thread class. - */ -void Thread::start() { - pthread_create(&myThread, NULL, threadFunction, this); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); -} - -/** - * join() function cancels the pthread inside of the Thread class. - */ -void Thread::join() { - pthread_cancel(myThread); -} - -/** - * getId() is the accessor function for the id of the Thread object. - * @return: myId, an unsigned long representing the id of the Thread object. - */ -unsigned long Thread::getId() const { - return myId; -} diff --git a/src/tests/ProducerConsumer/Thread.h b/src/tests/ProducerConsumer/Thread.h deleted file mode 100644 index 7e2f80d83..000000000 --- a/src/tests/ProducerConsumer/Thread.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Thread.h contains the abstract class necessary in order to have pthreads for Producers and Consumers. - * Adapted from: http://jrdodds.blogs.com/blog/2006/06/encapsulating_a.html - * https://slworkthings.wordpress.com/2009/11/10/a-pthread-wrapper-class-part-1/ - * https://cppcodetips.wordpress.com/2013/12/05/pthread-c-wrapper/ - * http://peter.bourgon.org/blog/2010/10/27/who-needs-boost-a-simple-pthreads-wrapper.html - * Practical Guide To Pthread Programming in C++ By Swaminathan Bhaskar (pdf) - */ -#ifndef THREAD_H_ -#define THREAD_H_ - -#include - -/** - * The Thread class encapsulates the details of creating a pthread. - * It is abstract; cannot be instantiated. - */ -class Thread { -public: - Thread(); //Default-constructor - Thread(unsigned long id); //Constructor - unsigned long getId() const; //Accessor for the id - void start(); //Create the pthread and run the corresponding method - virtual void run() = 0; //Needs to be defined by the inheriting subclass - void join(); //Join at the end - -protected: - static void* threadFunction(void* obj); //The function that the pthread will run - -private: - unsigned long myId; //Id for the Thread object - pthread_t myThread; //pthread -}; - -#endif /* THREAD_H_ */ diff --git a/src/tests/ReaderWriter/FLock.cpp b/src/tests/ReaderWriter/FLock.cpp deleted file mode 100644 index 07fb60f90..000000000 --- a/src/tests/ReaderWriter/FLock.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "FLock.h" -/** - * FLock.cpp provides the monitor for the Reader-Writer visualization that gives a fair preference. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - */ - -FLock::FLock() : Lock() { - counterLock = PTHREAD_MUTEX_INITIALIZER; - writerLock = PTHREAD_MUTEX_INITIALIZER; -} - -FLock::FLock(RWDatabase* data) : Lock(data) { - counterLock = PTHREAD_MUTEX_INITIALIZER; - writerLock = PTHREAD_MUTEX_INITIALIZER; -} - -/** - * \brief readLock() implements the abstract method in Lock - * \details Grants the calling thread access for reading - */ -void FLock::readLock() { - pthread_mutex_lock( &this->lock ); - pthread_mutex_lock( &this->counterLock ); - if( (++activeReaders) == 1) pthread_mutex_lock( &this->writerLock ); - pthread_mutex_unlock( &this->lock ); - pthread_mutex_unlock( &this->counterLock ); -} - -/** - * \brief readUnlock() implements the abstract method in Lock - * \details Releases the calling thread's read lock - */ -void FLock::readUnlock() { - pthread_mutex_lock( &this->counterLock ); - if ( (--activeReaders) == 0 ) pthread_mutex_unlock( &this->writerLock ); - pthread_mutex_unlock( &this->counterLock ); -} - -/** - * \brief writeLock() implements the abstract method in Lock - * \details Grants the calling thread acces for writing - */ -void FLock::writeLock() { - pthread_mutex_lock( &this->lock ); - pthread_mutex_lock( &this->writerLock ); -} - -/** - * \brief writeUnlock() implements the abstract method in Lock - * \details Releases the calling thread's write lock - */ -void FLock::writeUnlock() { - pthread_mutex_unlock( &this->writerLock ); - pthread_mutex_unlock( &this->lock ); -} diff --git a/src/tests/ReaderWriter/FLock.h b/src/tests/ReaderWriter/FLock.h deleted file mode 100644 index 604ebe4b3..000000000 --- a/src/tests/ReaderWriter/FLock.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * FLock.h provides the fair monitor for the Reader-Writer visualization that gives equal preference to the Readers and Writers. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - * implements the "commonly known solution" presented in: https://arxiv.org/pdf/1309.4507.pdf - */ - -#ifndef RWLOCK_H_ -#define RWLOCK_H_ - -#include -#include -#include "Lock.h" -#include "RWDatabase.h" - -/** - * \class FLock - * \brief A lock giving equal priority to Readers and Writers. - * \details Inheritance: Lock class. - * \details Implements the locking and unlocking methods of a monitor. - */ -class FLock : public Lock { -public: - FLock(); //Default constructor - FLock(RWDatabase* data); //Explicit constructor - void readLock(); //Inherited from Lock class - void readUnlock(); //Inherited from Lock class - void writeLock();//Inherited from Lock class - void writeUnlock(); //Inherited from Lock class -private: - - // TODO: name these better - pthread_mutex_t counterLock; - pthread_mutex_t writerLock; - -}; - -#endif /*RWLOCK_H_*/ diff --git a/src/tests/ReaderWriter/Lock.cpp b/src/tests/ReaderWriter/Lock.cpp deleted file mode 100644 index 2d9e8d61d..000000000 --- a/src/tests/ReaderWriter/Lock.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Lock.h" -/** - * Lock.cpp provides a Lock class for the Reader-Writer visualization. - * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. - */ - -/** - * \brief Default constructor for the Lock class - * \return: The constructed Lock object. - */ -Lock::Lock() { - activeWriters = activeReaders = waitingWriters = waitingReaders = 0; - lock = PTHREAD_MUTEX_INITIALIZER; - okToRead = PTHREAD_COND_INITIALIZER; - okToWrite = PTHREAD_COND_INITIALIZER; -} - -/** - * \brief Explicit constructor for the Lock class - * \param data, the database being protected - * \return: The constructed Lock object. - */ -Lock::Lock(RWDatabase* database) { - activeWriters = activeReaders = waitingWriters = waitingReaders = 0; - lock = PTHREAD_MUTEX_INITIALIZER; - okToRead = PTHREAD_COND_INITIALIZER; - okToWrite = PTHREAD_COND_INITIALIZER; - data = database; -} diff --git a/src/tests/ReaderWriter/Lock.h b/src/tests/ReaderWriter/Lock.h deleted file mode 100644 index 5f9ccb4f8..000000000 --- a/src/tests/ReaderWriter/Lock.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Lock.h provides a Lock class for the Reader-Writer visualization. - * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. - */ - -#ifndef LOCK_H_ -#define LOCK_H_ - -#include -#include -#include -#include -#include -#include "RWDatabase.h" -using namespace std; - -/** - * \class Lock - * \brief An abstract database protecting a vector of data - * \details Database has its locks - * \details Locking methods must be implemented in subclass, giving priority to different types of threads. - */ -class Lock { -public: - Lock(); //Default constructor - Lock(RWDatabase* data); //Explicit constructor - virtual void readLock() = 0; //Must be defined by subclass - virtual void readUnlock() = 0; //Must be defined by subclass - virtual void writeLock() = 0; //Must be defined by subclass - virtual void writeUnlock() = 0; //Must be defined by subclass - -protected: - int activeWriters, activeReaders, waitingWriters, waitingReaders; - pthread_mutex_t lock; - pthread_cond_t okToRead, okToWrite; - RWDatabase* data; -}; - -#endif /*LOCK_H_*/ diff --git a/src/tests/ReaderWriter/RLock.cpp b/src/tests/ReaderWriter/RLock.cpp deleted file mode 100644 index 064b87d6c..000000000 --- a/src/tests/ReaderWriter/RLock.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "RLock.h" -/** - * RLock.cpp provides the monitor for the Reader-Writer visualization that gives preference to the Readers. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - */ - -/** - * \brief readLock() implements the abstract method in Lock - * \details Grants the calling thread access for reading, giving priority to readers - */ -void RLock::readLock() { - pthread_mutex_lock( &this->lock ); - ++this->waitingReaders; - while( data->getItemCount() == 0 ) { //Wait for okToRead while vector is empty - pthread_cond_wait( &this->okToRead, &this->lock ); - } - while( this->activeWriters > 0 ) { //Yield only to active Writers - pthread_cond_wait( &this->okToRead, &this->lock ); - } - --this->waitingReaders; - ++this->activeReaders; - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief readUnlock() implements the abstract method in Lock - * \details Releases the calling thread's read lock - */ -void RLock::readUnlock() { - pthread_mutex_lock( &this->lock ); - --this->activeReaders; - if( this->activeReaders == 0 && this->waitingWriters > 0 ) { //Last out alerts Writers - pthread_cond_signal( &this->okToWrite ); - } - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief writeLock() implements the abstract method in Lock - * \details Grants the calling thread acces for writing, giving priority to Readers - */ -void RLock::writeLock() { - pthread_mutex_lock( &this->lock ); - while( this->activeWriters > 0 || this->activeReaders > 0 || this->waitingReaders > 0) { - //Yield to active Writers and all Readers - ++this->waitingWriters; - pthread_cond_wait( &this->okToWrite, &this->lock ); - --this->waitingWriters; - } - ++this->activeWriters; - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief writeUnlock() implements the abstract method in Lock - * \details Releases the calling thread's write lock - */ -void RLock::writeUnlock() { - pthread_mutex_lock( &this->lock ); - --this->activeWriters; - if( this->waitingReaders > 0 ) { //Alert all Readers data is available - pthread_cond_broadcast( &this->okToRead ); - } else if( this->waitingWriters > 0 ) { //Alert other Writers only if no Readers - pthread_cond_signal( &this->okToWrite ); - } - pthread_mutex_unlock( &this->lock ); -} diff --git a/src/tests/ReaderWriter/RLock.h b/src/tests/ReaderWriter/RLock.h deleted file mode 100644 index 973e26416..000000000 --- a/src/tests/ReaderWriter/RLock.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * RLock.h provides the monitor for the Reader-Writer visualization that gives preference to the Readers. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - */ - -#ifndef RLOCK_H_ -#define RLOCK_H_ - -#include -#include -#include "Lock.h" -#include "RWDatabase.h" - -/** - * \class RLock - * \brief A lock giving priority to Readers. - * \details Inheritance: Lock class. - * \details Implements the locking and unlocking methods of a monitor. - */ -class RLock : public Lock { -public: - RLock() : Lock() {}; //Default constructor - RLock(RWDatabase* data) : Lock(data) {}; //Explicit constructor - void readLock(); //Inherited from Lock class - void readUnlock(); //Inherited from Lock class - void writeLock();//Inherited from Lock class - void writeUnlock(); //Inherited from Lock class -}; - -#endif /*RLOCK_H_*/ diff --git a/src/tests/ReaderWriter/RWDatabase.h b/src/tests/ReaderWriter/RWDatabase.h deleted file mode 100644 index ffdd1cf1d..000000000 --- a/src/tests/ReaderWriter/RWDatabase.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * RWDatabase.h provides a RWDatabase class for the Reader-Writer visualization. - * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. - */ - -#ifndef RWDATA_H_ -#define RWDATA_H_ - -#include -#include -#include -using namespace std; - -template - -/** - * \class RWDatabase - * \brief An abstract database protecting a vector of data - * \details Database has its locks and a vector - * \details Locking methods must be implemented in subclass, giving priority to different types of threads. - */ -class RWDatabase { -public: - RWDatabase(); //Default constructor - RWDatabase(int max); //Explicit constructor - int getItemCount() { return vec.size(); } //Get number of items in vector - int getMaxCapacity() { return maxCapacity; }//Get maximum items in vector - Item read(unsigned index); //Access item at index - void write(Item it, unsigned index); //Set item at index - -protected: - std::vector vec; - unsigned maxCapacity; -}; - -/** - * \brief Default constructor for the RWDatabase class - * \return: The constructed RWDatabase object. - */ -template -RWDatabase::RWDatabase() { - vec = vector(); -} - -/** - * \brief Explicit constructor for the RWDatabase class - * \param max, an int describing the maximum size of the contained vector - * \return: The constructed RWDatabase object. - */ -template -RWDatabase::RWDatabase(int max) { - vec = vector(); - maxCapacity = max; -} - -/** - * \brief read() returns the Item from the vector at an index - * \param index, an index in the vector to access a piece of data - */ -template -Item RWDatabase::read(unsigned index) { - if( index >= vec.size() ) - throw range_error("Access attempted beyond present items"); - else - return vec[index]; -} - -/** - * \brief write() sets an item at an index - * \param it, an Item to add to the vector - * \param index, the index to add the Item it - */ -template -void RWDatabase::write(Item it, unsigned index) { - if( index >= vec.size() ) { - if( index > maxCapacity ) - throw range_error("Item added beyond max capacity"); - else - vec.push_back(it); - } else { - vec[index] = it; - } -} - -#endif /*RWDATA_H_*/ diff --git a/src/tests/ReaderWriter/RWThread.cpp b/src/tests/ReaderWriter/RWThread.cpp deleted file mode 100644 index e210790ef..000000000 --- a/src/tests/ReaderWriter/RWThread.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "RWThread.h" - -int RWThread::WAIT_RANGE = 40, RWThread::WAIT_MIN = 15; - // used 32 and 160 for 8 threads and it took forever but worked - // 40 and 15 worked very well with the new version of ReaderWriter - // Still need to have these change based on number of threads. - const int RWThread::width = 20; //Width of each object - const int RWThread::dataX = 200, RWThread::dataY = 670; //Bottom left coordinates of the data area - const int RWThread::dataHeight = 600, RWThread::dataWidth = 200; //Dimensions of the data area - int RWThread::threadCount = 0; - float RWThread::access_wait = 1.0; - atomic RWThread::paused(false); - -/** - * \brief Default-constructor for the RWThread class. - * \return: The constructed RWThread object. - */ -RWThread::RWThread() : Thread() { - myX = myY = count = 0; - data = NULL; - monitor = NULL; - myCan = NULL; - myCircle = NULL; - myCountLabel = NULL; -} - -/** - * \brief Explicit-constructor for the RWThread class. - * \param: sharedDatabase, a reference to the RWDatabase object that is shared between the Reader and Writer. - * \param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * \param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming object from the Queue. - * \return: The constructed RWThread object. - */ -RWThread::RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : Thread(id) { - //Update static variables - threadCount++; - access_wait = 1.0/threadCount; - - count = 0; - data = &sharedDatabase; //Get the handle to the Database - monitor = &lock; //Get the handle to the monitor - myCan = &can; //Get the handle to the Canvas - myY = RWThread::dataY - 50 * (id + 1); - myX = 0; //Set in subclass constructor - myCircle = new Circle(myX, myY, 20, GRAY); //Move based on new x in subclass - myCircle->setLayer(3); - myCan->add(myCircle); - myCountLabel = new Text( to_wstring(count), myX, myY+5, 24, BLACK); - myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); - myCountLabel->setLayer(4); - myCan->add( myCountLabel ); -} - -void RWThread::run() { - while( myCan->isOpen() ) { - lock(); - act(); - unlock(); - wait(); - } -} - -void RWThread::wait() { - myCan->sleepFor( (rand()%RWThread::WAIT_RANGE+RWThread::WAIT_MIN)/10.0 ); //Wait for a random time -} diff --git a/src/tests/ReaderWriter/RWThread.h b/src/tests/ReaderWriter/RWThread.h deleted file mode 100644 index aba8058ff..000000000 --- a/src/tests/ReaderWriter/RWThread.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * RWThread.h contains the subclass of Thread and superclass of Reader and Writer for the Reader-Writer visualization. - * Includes details for drawing Threads to the Canvas - */ -#ifndef RWTHREAD_H_ -#define RWTHREAD_H_ - -#include -#include -#include //atomic paused -#include "RWDatabase.h" -#include "Thread.h" -#include "Lock.h" -using namespace tsgl; - -/** - * RWThread class inherits from the Thread class in order to create a RWThread object. - * Inheritance: Thread class. - */ -class RWThread : public Thread { -public: - RWThread(); //Default constructor - RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor - void run(); - void wait(); - virtual void lock() = 0; //Must be implemented by subclass - virtual void act() = 0; //Must be implemented by subclass - virtual void unlock() = 0; //Must be implemented by subclass - static const int width, dataX, dataY, dataHeight, dataWidth; //constants for display - static int WAIT_MIN, WAIT_RANGE; - static float access_wait; - static atomic paused; -protected: - int myX, myY; //Center coordinates for the RWThread - int count; //Number of colors processed (read or written) - RWDatabase * data; //Handle to the current database - Lock* monitor; //Handle to the current monitor - Canvas * myCan; //Handle to the Canvas - Circle * myCircle; //Circle representing the Thread - Text * myCountLabel; //Text label for number processed - - //Static values - static int threadCount; -}; - -#endif /* RWTHREAD_H_ */ diff --git a/src/tests/ReaderWriter/Reader.cpp b/src/tests/ReaderWriter/Reader.cpp deleted file mode 100644 index 8757d9584..000000000 --- a/src/tests/ReaderWriter/Reader.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "Reader.h" - -/** - * \brief Default-constructor for the Reader class. - * \return: The constructed Reader object. - */ -Reader::Reader() : RWThread() { } - -/** - * \brief Explicit-constructor for the Reader class. - * \param: sharedData, a reference to the RWDatabase object that is shared between the Reader and Writer. - * \param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * \param: can, a handle to the Canvas that will be drawn on. - * \return: The constructed Reader object. - */ -Reader::Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { - myX = can.getWindowWidth()-50; - myCircle->setCenter(myX, myY); - myCountLabel->setCenter(myX, myY); -} - -/** - * \brief Draws and removes Arrow from Canvas - * \details Helps the read() method - * \details Includes a half second pause - */ -void Reader::drawArrow(int x, int y) { - Arrow arrow(myCircle->getCenterX()-20, myY, x, y, BLACK, false); - arrow.setLayer(5); - myCan->add(&arrow); - myCan->sleepFor(0.5); - while( paused ) {} - myCan->remove(&arrow); -} - -//TODO: comment -void Reader::lock() { - myCircle->setCenter(myX-75, myY); //Move towards data - myCountLabel->setCenter(myX-75, myY); - monitor->readLock(); //Lock data for reading - myCan->sleepFor(RWThread::access_wait); - while( paused ) {} - myCircle->setCenter(myX-127, myY); //Move inside data - myCountLabel->setCenter(myX-127, myY); -} - -//TODO: comment -void Reader::act() { - //Read - Rectangle * rec = data->read(rand()%data->getItemCount()); //Get the color - ColorFloat* fillColor = rec->getFillColor(); - myCircle->setColor( fillColor[0] ); - myCountLabel->setColor( fillColor[0].getContrast() ); - delete[] fillColor; - - //Draw and erase the arrow - drawArrow(rec->getCenterX(), rec->getCenterY()); -} - -//TODO: comment -void Reader::unlock() { - //Release lock - count++; myCountLabel->setText( to_wstring(count) ); //Finished another read - if( count == 100 ) { - myCountLabel->setFontSize(22); - } - while( paused ) {} - myCircle->setCenter(myX, myY); //Return to home location - myCountLabel->setCenter(myX, myY); - monitor->readUnlock(); //Unlock the data -} diff --git a/src/tests/ReaderWriter/Reader.h b/src/tests/ReaderWriter/Reader.h deleted file mode 100644 index 396722879..000000000 --- a/src/tests/ReaderWriter/Reader.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Reader.h contains the class necessary in order to create a Reader object for the Reader-Writer visualization. - */ -#ifndef READER_H_ -#define READER_H_ - -#include -#include -#include "RWDatabase.h" -#include "RLock.h" -#include "RWThread.h" -#include "Thread.h" -using namespace tsgl; - -/** - * \class Reader - * \brief Reader class inherits from the RWThread class in order to create a Reader object. - * \details Inheritance: RWThread class. - * \details Implements the run() method, which calls the read() method. - */ -class Reader : public RWThread { -public: - Reader(); //Default constructor - Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor - void lock(); - void act(); - void unlock(); -private: - void drawArrow(int x, int y); -}; - -#endif /* READER_H_ */ diff --git a/src/tests/ReaderWriter/Thread.cpp b/src/tests/ReaderWriter/Thread.cpp deleted file mode 100644 index b6de9570a..000000000 --- a/src/tests/ReaderWriter/Thread.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "Thread.h" - -/** - * \brief Default-constructor for a Thread object. - * \return: The constructed Thread object with id == 0. - */ -Thread::Thread() { - myId = 0; -} - -/** - * \brief Explicit-constructor for a Thread object. - * \param myId, an unsigned long representing the id for the Thread object. - * \return: The constructed Thread object with id == myId. - */ -Thread::Thread(unsigned long id) { - myId = id; -} - -/** - * \brief threadFunction() is the function that the pthread should run as soon as it is created. - * \param obj, a void* that will be statically casted into a Thread object. - * It will run the run() function, which will be defined by the inheriting subclass. - * \return: NULL. - */ -void* Thread::threadFunction(void* obj) { - Thread * thread = static_cast(obj); - thread->run(); //This NEEDS to be defined by the subclass - pthread_exit(0); //Exit upon completion -} - -/** - * \brief start() function creates the pthread inside of the Thread class. - */ -void Thread::start() { - pthread_create(&myThread, NULL, threadFunction, this); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); -} - -/** - * \brief join() function cancels the pthread inside of the Thread class. - */ -void Thread::join() { - pthread_cancel(myThread); // solution to hanging process bug -} - -/** - * \brief getId() is the accessor function for the id of the Thread object. - * \return: myId, an unsigned long representing the id of the Thread object. - */ -unsigned long Thread::getId() const { - return myId; -} diff --git a/src/tests/ReaderWriter/Thread.h b/src/tests/ReaderWriter/Thread.h deleted file mode 100644 index fba976088..000000000 --- a/src/tests/ReaderWriter/Thread.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Thread.h contains the abstract class necessary in order to have pthreads for Readers and Writers. - * Adapted from: http://jrdodds.blogs.com/blog/2006/06/encapsulating_a.html - * https://slworkthings.wordpress.com/2009/11/10/a-pthread-wrapper-class-part-1/ - * https://cppcodetips.wordpress.com/2013/12/05/pthread-c-wrapper/ - * http://peter.bourgon.org/blog/2010/10/27/who-needs-boost-a-simple-pthreads-wrapper.html - * Practical Guide To Pthread Programming in C++ By Swaminathan Bhaskar (pdf) - */ -#ifndef THREAD_H_ -#define THREAD_H_ - -#include -#include - -/** - * \class Thread - * \brief The Thread class encapsulates the details of creating a pthread. - * \details It is abstract; cannot be instantiated. - */ -class Thread { -public: - Thread(); //Default-constructor - Thread(unsigned long id); //Constructor - unsigned long getId() const; //Accessor for the id - void start(); //Create the pthread and run the corresponding method - virtual void run() = 0; //Needs to be defined by the inheriting subclass - void join(); //Join at the end - -protected: - static void* threadFunction(void* obj); //The function that the pthread will run - -private: - unsigned long myId; //Id for the Thread object - pthread_t myThread; //pthread -}; - -#endif /* THREAD_H_ */ diff --git a/src/tests/ReaderWriter/WLock.cpp b/src/tests/ReaderWriter/WLock.cpp deleted file mode 100644 index df03ec7b1..000000000 --- a/src/tests/ReaderWriter/WLock.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "WLock.h" -/** - * WLock.cpp provides the monitor for the Reader-Writer visualization that gives preference to the Writers. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - */ - -/** - * \brief readLock() implements the abstract method in Lock - * \details Grants the calling thread access for reading, giving priority to writers - */ -void WLock::readLock() { - pthread_mutex_lock( &this->lock ); - ++this->waitingReaders; - while( data->getItemCount() == 0 ) { //Wait for okToRead while vector is empty - pthread_cond_wait( &this->okToRead, &this->lock ); - } - while( this->activeWriters > 0 || this->waitingWriters > 0) { //Yield to all Writers - pthread_cond_wait( &this->okToRead, &this->lock ); - } - --this->waitingReaders; - ++this->activeReaders; - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief readUnlock() implements the abstract method in Lock - * \details Releases the calling thread's read lock - */ -void WLock::readUnlock() { - pthread_mutex_lock( &this->lock ); - --this->activeReaders; - if( this->activeReaders == 0 && this->waitingWriters > 0 ) { - pthread_cond_signal( &this->okToWrite ); //Alert Writer data is available - } - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief writeLock() implements the abstract method in Lock - * \details Grants the calling thread acces for writing, giving priority to writers - */ -void WLock::writeLock() { - pthread_mutex_lock( &this->lock ); - while( this->activeWriters > 0 || this->activeReaders > 0) { //Wait for anyone already in data - ++this->waitingWriters; - pthread_cond_wait( &this->okToWrite, &this->lock ); - --this->waitingWriters; - } - ++this->activeWriters; - pthread_mutex_unlock( &this->lock ); -} - -/** - * \brief writeUnlock() implements the abstract method in Lock - * \details Releases the calling thread's write lock - */ -void WLock::writeUnlock() { - pthread_mutex_lock( &this->lock ); - --this->activeWriters; - if( this->waitingWriters > 0 ) { //Alert waiting Writer - pthread_cond_signal( &this->okToWrite ); - } else if( this->waitingReaders > 0 ) { //Alert waiting Readers only if no waiting Writers - pthread_cond_broadcast( &this->okToRead ); - } - pthread_mutex_unlock( &this->lock ); -} diff --git a/src/tests/ReaderWriter/WLock.h b/src/tests/ReaderWriter/WLock.h deleted file mode 100644 index 22d119a5d..000000000 --- a/src/tests/ReaderWriter/WLock.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * WLock.h provides the monitor for the Reader-Writer visualization that gives preference to the Writers. - * This class is a subclass of Lock and implements its locking and unlocking virtual methods. - */ - -#ifndef WLOCK_H_ -#define WLOCK_H_ - -#include -#include "Lock.h" - -/** - * \class WLock - * \brief A lock giving priority to Writers in the visualization. - * \details Inheritance: Lock class. - * \details Implements the locking and unlocking methods of a monitor. - */ -class WLock : public Lock { -public: - WLock() : Lock() {}; //Default constructor - WLock(RWDatabase* data) : Lock(data) {}; //Explicit constructor - void readLock(); //Inherited from Lock class - void readUnlock(); //Inherited from Lock class - void writeLock(); //Inherited from Lock class - void writeUnlock(); //Inherited from Lock class -}; - -#endif /*WLOCK_H_*/ diff --git a/src/tests/ReaderWriter/Writer.cpp b/src/tests/ReaderWriter/Writer.cpp deleted file mode 100644 index 9c7447725..000000000 --- a/src/tests/ReaderWriter/Writer.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "Writer.h" -Text * Writer::dataLabel = NULL; - -/** - * \brief Default-constructor for the Writer class. - * \return: The constructed Writer object. - */ -Writer::Writer() : RWThread() { dataLabel = NULL; } - -/** - * \brief Explicit-constructor for the Writer class. - * \param sharedDatabase, a reference to the RWDatabase object that is shared between the Reader and Writer. - * \param id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. - * \param can, a handle to the Canvas that will be drawn on. - * \return: The constructed Writer object. - */ -Writer::Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { - myX = 50; //Set the x-coordinate to 50 - myCircle->setCenter(myX, myY); - myCountLabel->setCenter(myX, myY); - if( !dataLabel ) { - dataLabel = new Text(L"0/300", RWThread::dataX-40, RWThread::dataY-RWThread::dataHeight-20, 16, BLACK); - dataLabel->setCenter(RWThread::dataX - 20, RWThread::dataY-RWThread::dataHeight-15); - myCan->add( dataLabel ); - dataLabel->setLayer(3); - } -} - -/** - * \brief Draws and removes Arrow from Canvas - * \details Helps the write() method - * \details Includes a half second pause - */ -void Writer::drawArrow(int x, int y) { - Arrow arrow(myCircle->getCenterX()+20, myY, x, y, BLACK); - arrow.setLayer(5); - myCan->add(&arrow); - myCan->sleepFor(0.5); - while( paused ) {} - myCan->remove(&arrow); -} - -/** - * \brief newColor() generates a new random color for writing. - */ -ColorInt Writer::randColor() { - int red = rand() % 255; - int green = rand() % 255; - int blue = rand() % 255; - return ColorInt(red, green, blue); -} - -/** - * \brief randIndex() generates an index number to add a new item - */ -int Writer::randIndex() { - int i = rand()%(data->getMaxCapacity()); //Random index between 0 and the max number of items in data - if( i > data->getItemCount() ) //Max index is next empty index - i = data->getItemCount(); - return i; -} - -/** - * \brief makeRec() creates a new Rectangle representing a random color - */ -Rectangle * Writer::makeRec(int index) { - int x = dataX + index%(200/RWThread::width) * RWThread::width; // start of data + column - int y = dataY - (index/(200/RWThread::width) + 1) * RWThread::width; // start of data + row - - return new Rectangle(x, y, RWThread::width, RWThread::width, randColor()); -} - -//TODO: comment -void Writer::lock() { - myCircle->setCenter(myX+75, myY); //Move in toward data - myCountLabel->setCenter(myX+75, myY); - monitor->writeLock(); //Lock data for writing - myCan->sleepFor(RWThread::access_wait); -} - -//TODO: comment -void Writer::act() { - while( paused ) {} - int id = randIndex(); - myCircle->setCenter(myX+127, myY); //Move inside data - myCountLabel->setCenter(myX+127, myY); - Rectangle * rec; - if( id < data->getItemCount() ) { //Change the color of an item - rec = data->read(id); - rec->setColor(randColor()); - } else { //Create a new item - rec = makeRec(id); //Make random color at random index - data->write(rec, id); // Write the item to the data - rec->setLayer(3); - myCan->add(rec); - dataLabel->setText( to_wstring( data->getItemCount() ) + L"/" + to_wstring( data->getMaxCapacity() ) ); - } - ColorFloat* fillColor = rec->getFillColor(); - myCircle->setColor( fillColor[0] ); - myCountLabel->setColor(fillColor[0].getContrast()); - delete[] fillColor; - - //Draw an arrow down to the item - drawArrow(rec->getCenterX(), rec->getCenterY()); -} - -//TODO: comment -void Writer::unlock() { - //Release lock - count++; myCountLabel->setText( to_wstring(count) ); //Finished another write - if( count == 100 ) { - myCountLabel->setFontSize(22); - } - while( paused ) {} - myCircle->setCenter(myX, myY); //Return to home location - myCountLabel->setCenter(myX, myY); - monitor->writeUnlock(); //Unlock the data for writing -} diff --git a/src/tests/ReaderWriter/Writer.h b/src/tests/ReaderWriter/Writer.h deleted file mode 100644 index 33c5871a4..000000000 --- a/src/tests/ReaderWriter/Writer.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Writer.h contains the class necessary in order to create a Writer object for the Reader-Writer visualization. - */ -#ifndef WRITER_H_ -#define WRITER_H_ - -//#include -#include -#include "RWDatabase.h" -#include "Lock.h" -#include "RWThread.h" -#include "Thread.h" -using namespace tsgl; - -/** - * \class Writer - * \brief A Thread that writes items in the visualization. - * \details Writer class creates a Writer object and inherits from the RWThread class. - * \details Inheritance: RWThread class. - * \details Implements the abstract run() method from the Thread class so that the pthread runs the write() method. - */ -class Writer : public RWThread { -public: - Writer(); //Default constructor - Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor - void lock(); - void act(); - void unlock(); -private: - ColorInt randColor(); - int randIndex(); - TextureHandler loader; - void drawArrow(int x, int y); - Rectangle * makeRec(int index); - static Text * dataLabel; -}; - -#endif /* WRITER_H_ */ diff --git a/src/tests/SeaUrchin/SeaUrchin.cpp b/src/tests/SeaUrchin/SeaUrchin.cpp deleted file mode 100644 index 042b62f65..000000000 --- a/src/tests/SeaUrchin/SeaUrchin.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SeaUrchin.cpp - */ - -#include "SeaUrchin.h" - -SeaUrchin::SeaUrchin(Canvas& can, int threadId) { - myX = -can.getWindowWidth() / 2 + 60; - myY = -can.getWindowHeight() / 2 + 60; - myX += (threadId % 8) * 110; - myY += (threadId / 8) * 110; - float delta = 180 / MY_SPOKES; - myColor = Colors::highContrastColor(threadId); - for(int i = 0; i < MY_SPOKES; i++) { - Line * l = new Line(myX, myY, 0, 100, i * delta, 0, 0, myColor); - lines.push_back(l); - can.add(l); - } -} - -void SeaUrchin::move(Canvas& can) { - float delta = 180 / MY_SPOKES; - for(int j = 0; j < MY_SPOKES; ++j) { - lines[j]->setYaw(j * delta + can.getReps() * 180 / PI); - } -} - -SeaUrchin::~SeaUrchin() { - for (unsigned int i = 0; i < lines.size(); i++) { - delete lines[i]; - } -} - diff --git a/src/tests/SeaUrchin/SeaUrchin.h b/src/tests/SeaUrchin/SeaUrchin.h deleted file mode 100644 index e163e22d3..000000000 --- a/src/tests/SeaUrchin/SeaUrchin.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SeaUrchin.h - */ - -#ifndef SEAURCHIN_H_ -#define SEAURCHIN_H_ - -#include - -using namespace tsgl; - -/*! - * \class SeaUrchin - * \brief Who doesn't love sea urchins? - * \details Draws a sea urchin onto the Canvas. - * \details Used as an example of what it means to put a process on a thread. - * \details The SeaUrchin objects are created in a parallel block, and each thread gets one SeaUrchin. - * \details Then, the thread draws the SeaUrchin onto the Canvas. - * \details Each SeaUrchin object has its own color and plot data based off of the thread's id number. - * \details SeaUrchin objects are drawn similar to the line fan in testLineFan. - * \see testLineFan. - */ -class SeaUrchin { -public: - - /*! - * \brief Explicitly construct a SeaUrchin object. - * \details Explicit constructor for a SeaUrchin object. - * \param can Reference to the Canvas to draw to. - * \param threadId The id of the thread that is currently creating a SeaUrchin object. - * \return The constructed SeaUrchin object. - */ - SeaUrchin(Canvas& can, int threadId); //Default constructor - - /*! - * \brief Draw the SeaUrchin. - * \details Actually draws the SeaUrchin object onto the Canvas. - * \param can Reference to the Canvas object to draw to. - */ - void move(Canvas& can); - - /*! - * \brief Destroy a SeaUrchin. - * \details Destructor for a SeaUrchin object. - * \note This function does absolutely nothing. - */ - virtual ~SeaUrchin(); - -private: - static const int MY_SPOKES = 8; - int myX, myY; - ColorFloat myColor; - std::vector lines; -}; - -#endif /* SEAURCHIN_H_ */ diff --git a/src/tests/Voronoi/ShadedVoronoi.cpp b/src/tests/Voronoi/ShadedVoronoi.cpp deleted file mode 100644 index 167f36de6..000000000 --- a/src/tests/Voronoi/ShadedVoronoi.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ShadedVoronoi.cpp - */ - -#include "ShadedVoronoi.h" - -using namespace tsgl; - -ShadedVoronoi::ShadedVoronoi(Canvas& can) : Voronoi(can) { - const int WW = can.getWindowWidth(), // Set the screen sizes - WH = can.getWindowHeight(); // Create a mapping of control point values - myKValue2 = new int[WW * WH](); // Create a mapping of more control point values -} - -void ShadedVoronoi::draw(Canvas& can) { - const int WW = can.getWindowWidth(), // Set the screen sizes - WH = can.getWindowHeight(); - #pragma omp parallel for - for (int i = 0; i < WW; i++) { // For each individual point... - for (int j = 0; j < WH; j++) { - int myBestK = -1, myNextBestK = -1; - float myBDist = 9999, myNBDist = 9999; // Reset the best distance - for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point - float myXD = i - myX[k], myYD = j - myY[k]; - float myDist = sqrt(myXD * myXD + myYD * myYD); // Calculate the distance from each control point - if (myDist < myBDist) { // If it's the closest one - myNBDist = myBDist; // Update the next best distance and control point - myNextBestK = myBestK; - myBDist = myDist; // Update the best distance and control point - myBestK = k; - } else if (myDist < myNBDist) { // If it's the second closest one - myNBDist = myDist; // Just update the next best distance / CP - myNextBestK = k; - } - } - myKValue[i * WH + j] = myBestK; - myKValue2[i * WH + j] = myNextBestK; - can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color - } - } - #pragma omp parallel for - for (int i = 0; i < WW; i++) { // For each individual point... - for (int j = 0; j < WH; j++) { - int k = myKValue[i * WH + j]; // Find its closest control point - int nk = myKValue2[i * WH + j]; // Then find its second closest - float xd1 = i - myX[k]; - float yd1 = j - myY[k]; - float d1 = xd1 * xd1 + yd1 * yd1; // Find the distance to it closest - float xkd = myX[k] - myX[nk]; - float ykd = myY[k] - myY[nk]; - float kd = xkd * xkd + ykd * ykd; // Find the distance between the CPs themselves - float shading = sqrt(d1 / kd); - clamp(shading,0,1); - can.drawPoint(i, j, ColorFloat(0, 0, 0, shading)); // Draw the point with the closest control's color - } - } -} - -ShadedVoronoi::~ShadedVoronoi() { - delete [] myKValue2; - myKValue2 = NULL; -} - diff --git a/src/tests/Voronoi/ShadedVoronoi.h b/src/tests/Voronoi/ShadedVoronoi.h deleted file mode 100644 index 2faf6bf1c..000000000 --- a/src/tests/Voronoi/ShadedVoronoi.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ShadedVoronoi.h - */ - -#ifndef SHADEDVORONOI_H_ -#define SHADEDVORONOI_H_ - -#include "Voronoi.h" - -/*! - * \class ShadedVoronoi - * \brief Voronoi diagram, only shaded! - * \details Creates a Shaded Voronoi diagram. - * \details Similar to a Voronoi diagram, but with some parts shaded in. - * \details Subclass of the Voronoi class. - * \see Voronoi class. - */ -class ShadedVoronoi : public Voronoi { -private: - int * myKValue2; -public: - - /*! - * \brief Explicitly construct a ShadedVoronoi object. - * \details Explicit constructor for a ShadedVoronoi object. - * \param can Reference to the Canvas to draw to. - * \return The constructed ShadedVoronoi object. - */ - ShadedVoronoi(Canvas& can); - - /*! - * \brief Draw the ShadedVoronoi object. - * \details Actually draws the ShadedVoronoi object onto the Canvas. - * \param can Reference to the Canvas to draw to. - */ - void draw(Canvas& can); - - /*! - * \brief Destroy a ShadedVoronoi object. - * \details Destructor for a ShadedVoronoi object. - * \return The memory allocated to a ShadedVoronoi object. - */ - virtual ~ShadedVoronoi(); -}; - -#endif /* SHADEDVORONOI_H_ */ diff --git a/src/tests/Voronoi/Voronoi.cpp b/src/tests/Voronoi/Voronoi.cpp deleted file mode 100644 index c1f6c6bc5..000000000 --- a/src/tests/Voronoi/Voronoi.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Voronoi.cpp - */ - -#include "Voronoi.h" - -using namespace tsgl; - -Voronoi::Voronoi(Canvas& can) { - const int WW = can.getWindowWidth(), // Set the screen sizes - WH = can.getWindowHeight(); - srand(time(NULL)); - myX = new int[MY_POINTS](); - myY = new int[MY_POINTS](); - myKValue = new int[WW * WH](); - for (int i = 0; i < MY_POINTS; i++) { // Randomize the control points - myX[i] = rand() % WW; - myY[i] = rand() % WH; - } - srand(time(NULL)); - myTC = Colors::randomColor(1.0f); // Randomize the axis colors - myRC = Colors::randomColor(1.0f); - myLC = Colors::randomColor(1.0f); - myBC = Colors::randomColor(1.0f); - for (int j = 0; j < MY_POINTS; j++) { // For each control point... - float xx = (float) myX[j] / WW; // Calculate an value from 0:1 based on x coord - float yy = (float) myY[j] / WH; // Do the same for y - myXC = Colors::blend(myLC, myRC, xx); // Interpolate between the left and right colors - myYC = Colors::blend(myTC, myBC, yy); // Do the same for top and bottom - myColor[j] = Colors::blend(myXC, myYC, 0.5f); // Complete the 4-way interpolation - } - -} - -void Voronoi::draw(Canvas& can) { - int myBestK = 0; // Keep track of the current best k-value - float myBDist, myDist, myXD, myYD; // Keep track of the closes matches and current distances - #pragma omp parallel for private(myBDist, myXD, myYD, myDist, myBestK) - for (int i = 0; i < can.getWindowWidth(); i++) { // For each individual point... - myBestK = 0; - for (int j = 0; j < can.getWindowHeight(); j++) { - myBDist = 9999; // Reset the best distance - for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point - myXD = i - myX[k]; // Calculate the distance from each control point - myYD = j - myY[k]; - myDist = sqrt(myXD * myXD + myYD * myYD); - if (myDist < myBDist) { // If it's the closest one - myBDist = myDist; // Update the best distance and control point - myBestK = k; - } - } - myKValue[i * can.getWindowHeight() + j] = myBestK; - can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color - if (!can.isOpen()) break; - } - } -} - -Voronoi::~Voronoi() { - delete [] myX; - delete [] myY; - delete [] myKValue; - myX = myY = myKValue = NULL; -} - diff --git a/src/tests/Voronoi/Voronoi.h b/src/tests/Voronoi/Voronoi.h deleted file mode 100644 index 632aa9f11..000000000 --- a/src/tests/Voronoi/Voronoi.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Voronoi.h - */ - -#ifndef VORONOI_H_ -#define VORONOI_H_ - -#include -#include -#include -#include -#include -#include "Util.h" - -using namespace tsgl; - -/*! - * \class Voronoi - * \brief A Voronoi diagram. - * \details Creates a Voronoi diagram to be drawn onto a Canvas. - * \see http://en.wikipedia.org/wiki/Voronoi_diagram. - */ -class Voronoi { -protected: - static const int MY_POINTS = 100 * 4; - int * myX; - int * myY; - int * myKValue; - ColorFloat myColor[MY_POINTS]; // And for an array of colors - ColorFloat myTC, myRC, myLC, myBC, myXC, myYC; // Color for the top, right, left, bottom, x-average, and y-average -public: - - /*! - * \brief Explicitly construct a Voronoi object. - * \details Explicit constructor for a Voronoi object. - * \param can Reference to the Canvas to draw to. - * \return The constructed Voronoi object. - */ - Voronoi(Canvas& can); - - /*! - * \brief Draw the Voronoi object. - * \details Actually draws the Voronoi object onto the Canvas. - * \param can Reference to the Canvas to draw to. - */ - void draw(Canvas& can); - - /*! - * \brief Destroy a Voronoi object. - * \details Destructor for a Voronoi object. - * \return The memory allocated to a Voronoi object. - */ - virtual ~Voronoi(); -}; - -#endif /* VORONOI_H_ */ diff --git a/src/tests/test2Dvs3D.cpp b/src/tests/test2Dvs3D.cpp deleted file mode 100644 index 807dcda4c..000000000 --- a/src/tests/test2Dvs3D.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * test2Dvs3D.cpp - * - * Usage: ./test2Dvs3D - */ - -#include -#include - -using namespace tsgl; - -void contrastFunction(Canvas& can) { - ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; - ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; - ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; - Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); - // can.add(testPyramid); - Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); - // can.add(triangle1); - Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); - // can.add(triangle2); - Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); - // can.add(triangle3); - Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); - // can.add(triangle4); - Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); - // can.add(triangle5); - Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); - // can.add(triangle6); - // testPyramid->setPitch(45); - int stepsTaken = 0; - while (can.isOpen()) { - can.sleep(); - if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { - can.add(triangle1); - stepsTaken++; - } - if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { - can.add(triangle2); - stepsTaken++; - } - if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { - can.add(triangle3); - stepsTaken++; - } - if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { - can.add(testPyramid); - stepsTaken++; - } - if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { - can.remove(triangle1); - can.remove(triangle2); - can.remove(triangle3); - stepsTaken++; - } - if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { - can.add(triangle4); - stepsTaken++; - } - if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { - can.add(triangle5); - stepsTaken++; - } - if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { - can.add(triangle6); - stepsTaken++; - } - if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { - if (testPyramid->getPitch() < 45) { - testPyramid->changePitchBy(0.5); - } else { - testPyramid->setPitch(45); - stepsTaken++; - } - } - } - - delete testPyramid; - delete triangle1; - delete triangle2; - delete triangle3; - delete triangle4; - delete triangle5; - delete triangle6; - -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing"); - c.setBackgroundColor(BLACK); - c.run(contrastFunction); -} \ No newline at end of file diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile deleted file mode 100644 index 2e37f36e4..000000000 --- a/src/tests/test2Dvs3D/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for test2Dvs3D - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = test2Dvs3D - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp deleted file mode 100644 index 2c47d5f79..000000000 --- a/src/tests/test2Dvs3D/test2Dvs3D.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * test2Dvs3D.cpp - * - * Usage: ./test2Dvs3D - */ - -#include -#include - -using namespace tsgl; - -void contrastFunction(Canvas& can) { - ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; - ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; - ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; - Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); - // can.add(testPyramid); - Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); - // can.add(triangle1); - Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); - // can.add(triangle2); - Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); - // can.add(triangle3); - Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); - // can.add(triangle4); - Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); - // can.add(triangle5); - Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); - // can.add(triangle6); - // testPyramid->setPitch(45); - int stepsTaken = 0; - while (can.isOpen()) { - can.sleep(); - if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { - can.add(triangle1); - stepsTaken++; - } - if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { - can.add(triangle2); - stepsTaken++; - } - if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { - can.add(triangle3); - stepsTaken++; - } - if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { - can.add(testPyramid); - stepsTaken++; - } - if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { - can.remove(triangle1); - can.remove(triangle2); - can.remove(triangle3); - stepsTaken++; - } - if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { - can.add(triangle4); - stepsTaken++; - } - if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { - can.add(triangle5); - stepsTaken++; - } - if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { - can.add(triangle6); - stepsTaken++; - } - if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { - if (testPyramid->getPitch() < 45) { - testPyramid->changePitchBy(0.5); - } else { - testPyramid->setPitch(45); - stepsTaken++; - } - } - } - - delete testPyramid; - delete triangle1; - delete triangle2; - delete triangle3; - delete triangle4; - delete triangle5; - delete triangle6; - -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing", BLACK); - c.run(contrastFunction); -} \ No newline at end of file diff --git a/src/tests/test3DPhilosophers.cpp b/src/tests/test3DPhilosophers.cpp deleted file mode 100644 index 6da76e638..000000000 --- a/src/tests/test3DPhilosophers.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * test3DPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. - * This file includes a main method, Philospher3D class, Fork3D class, and Table3D class. - * - * The program provides a 3D visualization of the Dining Philosophers Problem - * in which philosophers sit around a table, think for a random amount of time, and then want to eat. - * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. - * This visualization includes six different ways of resolving the conflicts. - * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. - * - * Usage: ./test3DPhilosophers - * for enter: - * 'w' for waitWhenBlocked, which results in Deadlock - * 'f' for forfeitWhenBlocked, which results in Livelock - * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 - * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 - * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) - * - * for enter: - * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). - * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. - * - * If step-through is turned off, the spacebar pauses the visualization. - */ - -#include -#include -#include -#include "DiningPhilosophers3D/Table3D.h" -#include "DiningPhilosophers3D/Philosopher3D.h" - -using namespace tsgl; - -void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { - - PhilMethod method; - //switch statement to create table with resolution method - char resolutionMethod = RM[0]; - switch(resolutionMethod) { - case 'w': - method = waitWhenBlocked; //Deadlock - break; - case 'f': - method = forfeitWhenBlocked; //Livelock (when synchronized) - break; - case 'n': - method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 - break; - case 'r': - method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 - break; - case 'o': - method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 - break; - default: - method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 - break; - } - - Table3D t(can,philosophers,method); - - srand(time(NULL)); // seed the random number generator for thinking steps - - bool stepThrough = step; // Flag that determines whether the animation pauses between steps - bool paused = false; // Flag that determines whether the animation is paused - bool philPauses[philosophers]; - for(int i = 0; i < philosophers; i++) { - philPauses[i] = false; - } - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed - paused = !paused; - for(int i = 0; i < philosophers; i++) { - philPauses[i] = false; - } - }); - - #pragma omp parallel num_threads(philosophers) - { - while(can.isOpen()) { - can.sleep(); - if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { - if(stepThrough) { philPauses[omp_get_thread_num()] = true; } - t.checkStep(); - can.pauseDrawing(); - if(method == forfeitWhenBlocked) { //Synchronize to see Livelock - #pragma omp barrier //Barrier for optional synchronization - } - t.actStep(); - t.drawStep(); - can.resumeDrawing(); - } - } - } -} - -int main(int argc, char* argv[]) { - if( argc == 1) { - std::cout << "\nTo run the program with different values, use the format:\n\t./test3DPhilosophers " - << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in tests/test3DPhilosophers.cpp" << std::endl; - } - int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 - int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 - bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); - std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven - Canvas c(-1, -1, 1300, 1000, "3D Dining Philosophers",1.0f/speed); - c.run(philosopherFunction,nphil,resM,stepThrough); -} diff --git a/src/tests/test3DRotation.cpp b/src/tests/test3DRotation.cpp deleted file mode 100644 index 44e2d82d9..000000000 --- a/src/tests/test3DRotation.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * test3DRotation.cpp - * - * Usage: ./test3DRotation - */ - -#include -#include - -using namespace tsgl; - -void cubeFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); - testCube->setRotationPoint(0,0,0); - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); - Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); - testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - can.add(testCube); - can.add(testPrism); - can.add(testSphere); - float rotation = 0.0f; - while (can.isOpen()) { - can.sleep(); - testCube->setYaw(rotation); - testPrism->setYaw(-rotation); - testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setYaw(-rotation); - rotation += 1; - } - - delete testCube; - delete testPrism; - delete testSphere; -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "3D Rotation"); - c.setBackgroundColor(BLACK); - c.run(cubeFunction); -} \ No newline at end of file diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile deleted file mode 100644 index 03345c4c7..000000000 --- a/src/tests/test3DRotation/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for test3DRotation - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = test3DRotation - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/test3DRotation/test3DRotation.cpp b/src/tests/test3DRotation/test3DRotation.cpp deleted file mode 100644 index 1ed4e77bd..000000000 --- a/src/tests/test3DRotation/test3DRotation.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * test3DRotation.cpp - * - * Usage: ./test3DRotation - */ - -#include -#include - -using namespace tsgl; - -void cubeFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); - testCube->setRotationPoint(0,0,0); - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); - Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); - testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - can.add(testCube); - can.add(testPrism); - can.add(testSphere); - float rotation = 0.0f; - while (can.isOpen()) { - can.sleep(); - testCube->setYaw(rotation); - testPrism->setYaw(-rotation); - testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); - testSphere->setYaw(-rotation); - rotation += 1; - } - - delete testCube; - delete testPrism; - delete testSphere; -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "3D Rotation", BLACK); - c.run(cubeFunction); -} \ No newline at end of file diff --git a/src/tests/testAlphaRectangle.cpp b/src/tests/testAlphaRectangle.cpp deleted file mode 100644 index 4340864e4..000000000 --- a/src/tests/testAlphaRectangle.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * testAlphaRectangle.cpp - * - * Usage: ./testAlphaRectangle - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws semi-transparent rectangles on a Canvas. - * \details - * - Store the Canvas' width and height in variables for easy reuse. - * - Set up the internal timer of the Canvas to expire once every \b FRAME / 10 seconds. - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - Select a random position on the Canvas for a corner of a rectangle. - * - Draw a rectangle stretching from the specified corner to another corner on the Canvas, - * with a random color and a transparency of 16 (~0.06). - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void alphaRectangleFunction(Canvas& can) { - const int WW = can.getWindowWidth(), WH = can.getWindowHeight(); - int a, b, c, d, x, y, w, h; - while (can.isOpen()) { - can.sleep(); - a = rand() % WW; b = rand() % WH; - c = rand() % WW; d = rand() % WH; - x = (a > c ? c : a); - y = (b > d ? d : b); - w = abs(c - a); - h = abs(d - b); - can.drawRectangle(x, y, w, h, ColorInt(rand()%MAX_COLOR, rand()%MAX_COLOR, rand()%MAX_COLOR, 16), true); - } -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Fancy Rectangles"); - c.setBackgroundColor(BLACK); - c.run(alphaRectangleFunction); -} diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile deleted file mode 100644 index 072c3514f..000000000 --- a/src/tests/testAlphaRectangle/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testAlphaRectangle - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testAlphaRectangle - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/testAlphaRectangle.cpp b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp deleted file mode 100644 index 8721ee1ea..000000000 --- a/src/tests/testAlphaRectangle/testAlphaRectangle.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * testAlphaRectangle.cpp - * - * Usage: ./testAlphaRectangle - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws semi-transparent rectangles on a Canvas. - * \details - * - Store the Canvas' width and height in variables for easy reuse. - * - Set up the internal timer of the Canvas to expire once every \b FRAME / 10 seconds. - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - Select a random position on the Canvas for a corner of a rectangle. - * - Draw a rectangle stretching from the specified corner to another corner on the Canvas, - * with a random color and a transparency of 16 (~0.06). - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void alphaRectangleFunction(Canvas& can) { - Background * bg = can.getBackground(); - const int WW = can.getWindowWidth(), WH = can.getWindowHeight(); - int a, b, c, d, x, y, w, h; - while (can.isOpen()) { - can.sleep(); - a = saferand(-WW/2,WW/2); b = saferand(-WH/2, WH/2); - c = saferand(-WW/2,WW/2); d = saferand(-WH/2, WH/2); - x = (a + c) / 2; - y = (b + d) / 2; - w = abs(c - a); - h = abs(d - b); - bg->drawRectangle(x, y, 0, w, h, 0,0,0, ColorFloat(randfloat(), randfloat(), randfloat(), (float) 16/255)); - } -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Fancy Rectangles", BLACK); - c.run(alphaRectangleFunction); -} diff --git a/src/tests/testArrows.cpp b/src/tests/testArrows.cpp deleted file mode 100644 index 61b13731c..000000000 --- a/src/tests/testArrows.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * testArrows.cpp tests displaying the Line class's Arrow and Dotted attributes - */ -#include -using namespace tsgl; - -void arrowFunction(Canvas& c) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.5), ColorFloat(0,1,0,1) }; - Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); - c.add(doubleArrow); - c.add(arrow2); - // doubleArrow->setCenterX(100); - // doubleArrow->setRotationPoint(0,0,0); - // doubleArrow->setYaw(45); - // printf("%f\n", doubleArrow->getAlpha()); - // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", doubleArrow->getAlpha()); - // doubleArrow->setColor(colors); - // printf("%f\n", doubleArrow->getAlpha()); - float floatVal = 0.0f; - GLfloat delta = 5; - bool boolean = true; - while( c.isOpen() ) { - c.sleep(); - // doubleArrow->setCenterX(sin(floatVal/90)); - // doubleArrow->setCenterY(sin(floatVal/90)); - // doubleArrow->setCenterZ(sin(floatVal/90)); - // doubleArrow->setYaw(floatVal); - // doubleArrow->setPitch(floatVal); - // doubleArrow->setRoll(floatVal); - // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); - if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { - delta *= -1; - arrow2->setIsOutlined(boolean); - arrow2->setIsFilled(!boolean); - boolean = !boolean; - } - doubleArrow->changeLengthBy(delta); - floatVal += 1; - } - - delete doubleArrow; -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Arrows"); - c.run(arrowFunction); -} \ No newline at end of file diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile deleted file mode 100644 index 7411d70f1..000000000 --- a/src/tests/testArrows/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testArrows - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testArrows - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp deleted file mode 100644 index 61b13731c..000000000 --- a/src/tests/testArrows/testArrows.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * testArrows.cpp tests displaying the Line class's Arrow and Dotted attributes - */ -#include -using namespace tsgl; - -void arrowFunction(Canvas& c) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.5), ColorFloat(0,1,0,1) }; - Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); - Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); - c.add(doubleArrow); - c.add(arrow2); - // doubleArrow->setCenterX(100); - // doubleArrow->setRotationPoint(0,0,0); - // doubleArrow->setYaw(45); - // printf("%f\n", doubleArrow->getAlpha()); - // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", doubleArrow->getAlpha()); - // doubleArrow->setColor(colors); - // printf("%f\n", doubleArrow->getAlpha()); - float floatVal = 0.0f; - GLfloat delta = 5; - bool boolean = true; - while( c.isOpen() ) { - c.sleep(); - // doubleArrow->setCenterX(sin(floatVal/90)); - // doubleArrow->setCenterY(sin(floatVal/90)); - // doubleArrow->setCenterZ(sin(floatVal/90)); - // doubleArrow->setYaw(floatVal); - // doubleArrow->setPitch(floatVal); - // doubleArrow->setRoll(floatVal); - // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); - if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { - delta *= -1; - arrow2->setIsOutlined(boolean); - arrow2->setIsFilled(!boolean); - boolean = !boolean; - } - doubleArrow->changeLengthBy(delta); - floatVal += 1; - } - - delete doubleArrow; -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Arrows"); - c.run(arrowFunction); -} \ No newline at end of file diff --git a/src/tests/testAura.cpp b/src/tests/testAura.cpp deleted file mode 100644 index 7b97bcbae..000000000 --- a/src/tests/testAura.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * testMouse.cpp - * - * Usage: ./testMouse - */ - -#include - -using namespace tsgl; - -inline float dist(float x1, float y1, float x2, float y2) { - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -inline void scatter(float& f, float max) { - float am = 1.0f - ((rand() % 20000) / 10000.0f); - f += max*am; -} - -/*! - * - */ -void auraFunction(Canvas& can, int segs) { - const float SR2 = sqrt(2); - const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); - const int ccw = CW/2, cch = CH/2; - const float ROT = 0.01f; - const float HUEDELTA = 0.01f; - const float OFF = (2*PI/segs); - const float START = PI/2; - - int mx, my; - ColorHSV *cf = new ColorHSV[segs]; - bool *drawn = new bool[segs]; - float *x1 = new float[segs], *y1 = new float[segs], - *x2 = new float[segs], *y2 = new float[segs]; - - float mangle = 0; - float mdist = 0; - - for (int i = 0; i < segs; ++i) { - cf[i] = Colors::highContrastColor(i); - cf[i].A = 0.01f; - } - - while(can.isOpen()) { - //Update mouse coordinates - scatter(mangle,0.02f); - scatter(mdist,2.0f); - if (mdist > 100) mdist *= 0.99f; - mx = can.getMouseX()+mdist*cos(mangle); - my = can.getMouseY()+mdist*sin(mangle); - - //Update positions of the edges of the triangles - float ang = START + ROT*can.getFrameNumber(); - for (int i = 0; i < segs; ++i) { - cf[i].H += HUEDELTA; - if (cf[i].H > 6.0f) cf[i].H = 0.0f; - float sang = sin(ang), cang = cos(ang); - if (fabs(cang) > fabs(sang)) { - x1[i] = (cang > 0) ? CW : 0; - y1[i] = cch+cch*sang*SR2; - } else { - y1[i] = (sang > 0) ? CH : 0; - x1[i] = ccw+ccw*cang*SR2; - } - ang += OFF; - } - for (int i = 0; i < segs; ++i) { - x2[i] = x1[(i+1)%segs]; - y2[i] = y1[(i+1)%segs]; - } - - //Draw the triangles - can.pauseDrawing(); - for (int i = 0; i < segs; drawn[i++] = false); - for (int i = 0; i < segs; ++i) { - int next = -1; - float bdist = 999999; - //Draw the triangles closest to the mouse first (lazy depth test) - for (int j = 0; j < segs; ++j) { - if (drawn[j]) - continue; - float d = dist(mx,my,x1[j],y1[j]) + dist(mx,my,x2[j],y2[j]); - if (d < bdist) { - bdist = d; - next = j; - } - } - if (next >= 0) { - can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); - drawn[next] = true; - } - } - can.resumeDrawing(); - can.sleep(); - } - - //Clean up - delete [] x1; delete [] y1; - delete [] x2; delete [] y2; - delete [] drawn; delete [] cf; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : -1; - int h = (argc > 2) ? atoi(argv[2]) : w; - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs()*2; - Canvas c(-1, -1, w, h, "Aura"); - c.setBackgroundColor(BLACK); - c.run(auraFunction,t); -} diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile deleted file mode 100644 index f1487e646..000000000 --- a/src/tests/testAura/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testAura - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testAura - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testAura/testAura.cpp b/src/tests/testAura/testAura.cpp deleted file mode 100644 index 5620f36d7..000000000 --- a/src/tests/testAura/testAura.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * testMouse.cpp - * - * Usage: ./testMouse - */ - -#include - -using namespace tsgl; - -inline float dist(float x1, float y1, float x2, float y2) { - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -inline void scatter(float& f, float max) { - float am = 1.0f - ((rand() % 20000) / 10000.0f); - f += max*am; -} - -/*! - * - */ -void auraFunction(Canvas& can, int segs) { - const float SR2 = sqrt(2); - const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); - const int ccw = CW/2, cch = CH/2; - const float ROT = 0.01f; - const float HUEDELTA = 0.01f; - const float OFF = (2*PI/segs); - const float START = PI/2; - - int mx, my; - ColorHSV *cf = new ColorHSV[segs]; - bool *drawn = new bool[segs]; - float *x1 = new float[segs], *y1 = new float[segs], - *x2 = new float[segs], *y2 = new float[segs]; - - float mangle = 0; - float mdist = 0; - - for (int i = 0; i < segs; ++i) { - cf[i] = Colors::highContrastColor(i); - cf[i].A = 0.01f; - } - - while(can.isOpen()) { - //Update mouse coordinates - scatter(mangle,0.02f); - scatter(mdist,2.0f); - if (mdist > 100) mdist *= 0.99f; - mx = can.getMouseX()+mdist*cos(mangle); - my = can.getMouseY()+mdist*sin(mangle); - - //Update positions of the edges of the triangles - float ang = START + ROT*can.getFrameNumber(); - for (int i = 0; i < segs; ++i) { - cf[i].H += HUEDELTA; - if (cf[i].H > 6.0f) cf[i].H = 0.0f; - float sang = sin(ang), cang = cos(ang); - if (fabs(cang) > fabs(sang)) { - x1[i] = (cang > 0) ? CW : 0; - y1[i] = cch+cch*sang*SR2; - } else { - y1[i] = (sang > 0) ? CH : 0; - x1[i] = ccw+ccw*cang*SR2; - } - ang += OFF; - } - for (int i = 0; i < segs; ++i) { - x2[i] = x1[(i+1)%segs]; - y2[i] = y1[(i+1)%segs]; - } - - //Draw the triangles - can.pauseDrawing(); - for (int i = 0; i < segs; drawn[i++] = false); - for (int i = 0; i < segs; ++i) { - int next = -1; - float bdist = 999999; - //Draw the triangles closest to the mouse first (lazy depth test) - for (int j = 0; j < segs; ++j) { - if (drawn[j]) - continue; - float d = dist(mx,my,x1[j],y1[j]) + dist(mx,my,x2[j],y2[j]); - if (d < bdist) { - bdist = d; - next = j; - } - } - if (next >= 0) { - can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); - drawn[next] = true; - } - } - can.resumeDrawing(); - can.sleep(); - } - - //Clean up - delete [] x1; delete [] y1; - delete [] x2; delete [] y2; - delete [] drawn; delete [] cf; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : -1; - int h = (argc > 2) ? atoi(argv[2]) : w; - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs()*2; - Canvas c(-1, -1, w, h, "Aura", BLACK); - c.run(auraFunction,t); -} diff --git a/src/tests/testBG.cpp b/src/tests/testBG.cpp deleted file mode 100644 index 0b55619ef..000000000 --- a/src/tests/testBG.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * testBG.cpp - * - * Usage: ./testBG - */ - -#include -#include - -using namespace tsgl; - -void squareFunction(Canvas& can) { - Background * bg = new Background(0,0,0, can.getWindowWidth(), can.getWindowHeight(), 0,0,0,WHITE); - // printf("draw square\n"); - // Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); - // can.add(cube); - bg->drawSquare(0); - can.setBackground(bg); - can.add(bg); - while (can.isOpen()) { - can.sleep(); - bg->setPitch(can.getFrameNumber()/50); - // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); - } - // delete cube; - delete bg; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Square"); - c.setBackgroundColor(BLACK); - c.run(squareFunction); -} \ No newline at end of file diff --git a/src/tests/testBackground.cpp b/src/tests/testBackground.cpp deleted file mode 100644 index 3839b6a79..000000000 --- a/src/tests/testBackground.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * testColorPoints.cpp - * - * Usage: ./testColorPoints - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line - * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. - * - The actual number of threads created is stored in: \b nthreads . - * - The number of lines per thread is calculated and stored in: \b myPart . - * - The starting position of each given thread is calculated and stored in: \b myStart . - * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. - * - The color for a thread is calculated. - * - If the point's coordinate is even: - * - Draw a point on the Canvas in the thread's color. - * - Else: - * - Draw the point normally. - * . - * - The function breaks from the outer for loop if the Canvas is closed. - * . - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Number of threads to use. - */ -void colorPointsFunction(Canvas& can, int numberOfThreads) { - Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); - can.add(background); - - /* this is the part of the test for drawPixel */ - #pragma omp parallel num_threads(numberOfThreads) - { - int nthreads = omp_get_num_threads(); //Actual number of threads to use - // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. - // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. - int myPart = can.getWindowHeight() / nthreads; - int myStart = myPart * omp_get_thread_num(); - for (int i = myStart; i < myStart + myPart; i++) { - for (int j = 0; j < can.getWindowWidth(); j++) { - // int id = omp_get_thread_num(); - if (i % 2 == 0) { - background->drawPixel(i, j, BLACK); - } else { - background->drawPixel(i, j, ColorInt(i % 255, j % 255, (i*j) % 255)); - } - } - if (!can.isOpen()) break; - } - } - /* end drawPixel. while loop only contains can.sleep() */ - - /* the getPixel portion of the test */ - // bool print = false; - // int mouseX = 0; - // int mouseY = 0; - - // ColorInt colors[] = { ColorInt(255,255,255,255), - // ColorInt(255,0,0,255), ColorInt(0,255,0,255), - // ColorInt(0,0,255,255), ColorInt(255,255,0,255), - // ColorInt(255,0,255,255), ColorInt(0,255,255,255), - // ColorInt(0,0,0,255)}; - // for (int k = 0; k < 8; k++) - // for (int j = k * background->getHeight() / 8; j < (k+1) * background->getHeight() / 8; j++) - // for (int i = 0; i < background->getWidth(); i++) - // if (k * background->getWidth() / 8 <= i && i < (k+1) * background->getWidth() / 8) - // background->drawPixel(j, i, ColorInt(123,123,123,255)); - // else - // background->drawPixel(j, i, colors[k]); - - - // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { - // print = true; - // }); - - // ColorInt c; - /* end getPixel(). uncomment entirety of while loop */ - - while (can.isOpen()) { - can.sleep(); - // mouseX = can.getMouseX(); - // mouseY = can.getMouseY(); - // if (print) { - // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. - // printf("%d, %d; ", mouseY, mouseX); - // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); - // print = false; - // } - } - delete background; -} - -//Takes in command line arguments for the window width and height as well -//as for the number of threads to use -int main(int argc, char* argv[]) { - int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); - int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Dithered Points"); - c.run(colorPointsFunction,t); -} diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile deleted file mode 100644 index 9389a941a..000000000 --- a/src/tests/testBackground/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testBackground - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testBackground - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testBackground/testBackground.cpp b/src/tests/testBackground/testBackground.cpp deleted file mode 100644 index 58d1362bf..000000000 --- a/src/tests/testBackground/testBackground.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * testBackground.cpp tests the core functions of TSGL::Background - * - * Usage: ./testBackground - */ - -#include -#include - -using namespace tsgl; - -void backgroundFunction(Canvas& can) { - Background * bg = can.getBackground(); - Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); - float x = 0; - - can.bindToButton(TSGL_LEFT, TSGL_PRESS, [&cube]() { - cube->changeXBy(-10); - }); - - can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&cube]() { - cube->changeXBy(10); - }); - - can.bindToButton(TSGL_UP, TSGL_PRESS, [&cube]() { - cube->changeYBy(10); - }); - - can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&cube]() { - cube->changeYBy(-10); - }); - - can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&cube]() { - cube->changeZBy(-50); - }); - - can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&cube]() { - cube->changeZBy(50); - }); - - // bg->drawSquare(0,0,0,200,0,0,0,RED); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&bg, &can]() { - bg->setClearColor(Colors::randomColor()); - // can.setBackgroundColor(Colors::randomColor()); - bg->clear(); - // can.clearBackground(); - // printf("%f, %f, %f, %f\n", can.getBackgroundColor().R, can.getBackgroundColor().G, can.getBackgroundColor().B, can.getBackgroundColor().A); - // printf("%f, %f, %f, %f\n", bg->getClearColor().R, bg->getClearColor().G, bg->getClearColor().B, bg->getClearColor().A); - }); - - can.add(cube); - while (can.isOpen()) { - can.sleep(); - // bg->clear(); - x = 200 * sin( (float) can.getFrameNumber()/90); - bg->drawSquare(x,0,0,200,0,0,0,RED, true); - // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); - } - delete cube; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Background", BLUE); - c.run(backgroundFunction); -} \ No newline at end of file diff --git a/src/tests/testBallroom.cpp b/src/tests/testBallroom.cpp deleted file mode 100644 index 722639ca3..000000000 --- a/src/tests/testBallroom.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - * testBallroom.cpp - * - * Usage: ./testBallroom - */ - -#include -#include -#include - -using namespace tsgl; - -struct Vector2 { - float x,y; - Vector2() { - x = y = 0; - } - Vector2(float xx,float yy) { - x = xx; y = yy; - } - Vector2 operator+(const Vector2 &o) { - return Vector2(x+o.x,y+o.y); - } - Vector2& operator+=(const Vector2 &o) { - x += o.x; y += o.y; - return (*this); - } - Vector2 operator-(const Vector2 &o) { - return Vector2(x-o.x,y-o.y); - } - Vector2 operator-() { - return Vector2(-x,-y); - } - Vector2& operator-=(const Vector2 &o) { - x -= o.x; y -= o.y; - return (*this); - } - Vector2 operator*(const float f) { - return Vector2(x*f,y*f); - } - Vector2& operator*=(const float f) { - x *= f; y *= f; - return (*this); - } - float dot(const Vector2 &o) const { - return x*o.x + y*o.y; - } - float length() const { - return sqrt(x*x+y*y); - } - float angle() const { - return atan2(y,x); - } - float angle(const Vector2 &o) { - return acos(angle(o)); - } - float cosangle(const Vector2 &o) { - return dot(o)/( length() * o.length() ); - } -}; -Vector2 operator+(const Vector2 &v1, const Vector2 &v2) { - return Vector2(v1.x+v2.x,v1.y+v2.y); -} -Vector2 operator-(const Vector2 &v1, const Vector2 &v2) { - return Vector2(v1.x-v2.x,v1.y-v2.y); -} -Vector2 operator*(const Vector2 &v, const float f) { - return Vector2(v.x*f,v.y*f); -} - -class BouncingBall { -private: - float mySpeed, myDir; - int rw, rh; - Circle * circle; - Canvas * can; -public: - Vector2 pos, vel, acc; - ColorFloat color; - int rad; - bool bounced; - BouncingBall(int x, int y, int r, int w, int h, ColorFloat c, Canvas * can) { - pos = Vector2(x,y); - vel = Vector2(0,0); - acc = Vector2(0,0); - mySpeed = myDir = 0; - rad = r; - rw = w; - rh = h; - color = c; - bounced = false; - circle = new Circle(x,y,0,r,0,0,0,c); - // circle->setLayer(1); - can->add(circle); - } - BouncingBall(int x, int y, float vx, float vy, int r, int w, int h, ColorFloat c, Canvas * canvas) { - pos = Vector2(x,y); - vel = Vector2(vx,vy); - acc = Vector2(0,0.1f); - calcSpeed(); - calcDir(); - rad = r; - rw = w; - rh = h; - color = c; - bounced = false; - can = canvas; - circle = new Circle(x,y,0,r,0,0,0,c); - // circle->setLayer(1); - can->add(circle); - } - ~BouncingBall() { - can->remove(circle); - delete circle; - } - void calcSpeed() { - mySpeed = vel.length(); - } - void setSpeed(float s) { - mySpeed = s; - vel.x = s*cos(myDir); - vel.y = s*sin(myDir); - } - void calcDir() { - myDir = vel.angle(); - } - void setDir(float d) { - myDir = d; - vel.x = mySpeed*cos(d); - vel.y = mySpeed*sin(d); - } - void step() { - bounced = false; - vel += acc; - pos += vel; - if (pos.x <= -rw / 2 + rad) { - pos.x = -rw / 2 + rad; - vel.x *= -0.5f; - } else if (pos.x >= rw / 2 -rad) { - pos.x = rw / 2-rad; - vel.x *= -0.5f; - } - if (pos.y <= -rh / 2 + rad) { - pos.y = -rh / 2 + rad; - vel.y *= -1.0f; - } else if (pos.y >= rh / 2 -rad) { - pos.y = rh / 2 -rad; - vel.y *= -1.0f; - } - calcSpeed(); - calcDir(); - circle->setCenter(pos.x,pos.y,0); - } - void setRoomSize(int w, int h) { - rw = w; - rh = h; - } - void bounce(BouncingBall *o) { - if (bounced) - return; - Vector2 dist = pos-o->pos; - float radii = rad+o->rad; - if (dist.length() > radii) - return; - Vector2 vdelta = vel-o->vel; - pos -= vel; - Vector2 pdelta = pos-o->pos; - float ps = pdelta.length()*pdelta.length(); - vel -= pdelta*(vdelta.dot(pdelta)/ps); - o->vel += pdelta*((-vdelta).dot(-pdelta)/ps); - calcSpeed(); - calcDir(); - o->calcSpeed(); - o->calcDir(); - bounced = true; - circle->setCenter(pos.x, pos.y,0); - } - bool collides(BouncingBall *o) { - return ((pos-o->pos).length() <= (rad+o->rad)); - } -}; - -class BallRoom { -private: - int width, height; - float friction, gravity; - bool attract; - std::list balls; - std::list::const_iterator it, jt; - Circle * mouseCircle; - Canvas * can; -public: - BallRoom(int w, int h, Canvas * canvas) { - width = w; - height = h; - friction = 0.99f; - gravity = 0.1f; - attract = true; - can = canvas; - mouseCircle = new Circle(0,0,0,20,0,0,0,ColorFloat(1.0,0.5,0.5,0.5)); - // mouseCircle->setLayer(2); - can->add(mouseCircle); - } - ~BallRoom() { - while (!balls.empty()) { - BouncingBall* b = balls.front(); - balls.pop_front(); - delete b; - } - delete mouseCircle; - } - void addBall(int x, int y, int r, ColorFloat c = WHITE) { - addBall(x,y,0,0,r,c); - } - void addBall(int x, int y, int vx, int vy, int r, ColorFloat c = WHITE) { - BouncingBall* b = new BouncingBall(x,y,vx,vy,r,width,height,c, can); - const int MAXFAIL = 1000; - int fails = 0; - for (it = balls.begin(); it != balls.end(); ++it) { - while (b->collides((*it))) { - ++fails; - if (fails == MAXFAIL) { - delete b; - return; - } - } - } - balls.push_back(b); - } - void step(Canvas* c) { - int mx = c->getMouseX() - c->getWindowWidth()/2, my = c->getWindowHeight()/2 - c->getMouseY(); - Vector2 mvec(mx,my); - mouseCircle->setCenter(mx, my, 0); - if (attract) { - mouseCircle->setColor(ColorFloat(0.5,1.0,1.0,0.5)); - } else { - mouseCircle->setColor(ColorFloat(1.0,0.5,0.5,0.5)); - } - for (it = balls.begin(); it != balls.end(); ++it) { - BouncingBall *b = (*it); - - float mdir; - if (attract) - mdir = (mvec - b->pos).angle(); - else - mdir = (b->pos-mvec).angle(); - b->acc = Vector2(cos(mdir),sin(mdir))*gravity; - b->vel *= friction; - - b->step(); - for (jt = balls.begin(); jt != balls.end(); ++jt) { - if (jt == it) - continue; - b->bounce(*jt); - if (b->bounced) - break; - } - } - c->pauseDrawing(); - c->resumeDrawing(); - } - inline void toggleAttract() { - attract ^= true; - } -}; - -/*! - * \brief Lots and lots of multicolored balls! - * \details Draws a lot of multicolored balls onto the Canvas that follow the mouse around. - * - It is drawn in this way: - * - Get the window width and height for convenience of use. - * - Create the area for the balls based off of the window width and height. - * - For each ball: - * - Set its speed to 5. - * - Randomize its initial direction. - * - Add it to the area created with the calculated speed and direction as well as with a random color. - * . - * - Bind the left mouse button so that when you click the screen the attraction of the balls will change. - * (If they are attracted to the mouse then they will be repelled. If they are repelled, then they will be attracted - * to the mouse). - * - While the Canvas is open: - * - Sleep the internal timer until the next draw cycle. - * - Animate the balls and have them bounce off of one another. - * . - * . - * \param can Reference to the Canvas to draw on. - */ -void ballroomFunction(Canvas& can) { - const int WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(); // Window height - BallRoom b(WW,WH, &can); - for (int i = 0; i < 100; ++ i) { - float speed = 5.0f; - float dir = 2 * PI * saferand(0,100) / 100.0f; - ColorInt c = ColorInt(64 + saferand(0,191),64 + saferand(0,191),64 + saferand(0,191),255); - b.addBall(saferand(-WW/2,WW/2), saferand(-WH/2, WH/2), speed*cos(dir),speed*sin(dir),10,c); - } - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&b]() { - b.toggleAttract(); - }); - - - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - b.step(&can); - } -} - -//Take command-line arguments for the width and height of the Canvas -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "The Ballroom"); - c.setBackgroundColor(BLACK); - c.run(ballroomFunction); -} diff --git a/src/tests/testBlurImage.cpp b/src/tests/testBlurImage.cpp deleted file mode 100644 index 005d6399d..000000000 --- a/src/tests/testBlurImage.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * testBlurImage.cpp - * - * Usage: ./testBlurImage - */ - -#include -#include - -using namespace tsgl; - -int depthtest(int xmin, int ymin, int xmax, int ymax) { - int xd = 0, yd = 0; - for (float d = xmax-xmin; d > 1; d=ceil(d/2), ++xd); - for (float d = ymax-ymin; d > 1; d=ceil(d/2), ++yd); - return ((xd > yd) ? xd : yd); -} - -bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { - if (xmin > xmax || ymin > ymax) - return false; - if (depth > 0) { - int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; - blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); - blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); - blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); - blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); - return false; - } - ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); - ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); - for (int j = ymin; j <= ymax; ++j) - for (int i = xmin; i <= xmax; ++i) - can.drawPoint(i,j,Colors::blend(top,bot)); - return true; -} - -void blurImageFunction(Canvas& can, std::string fpath, int threads) { - int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - int side = sqrt(threads); //Square root of the number of threads, rounded down - can.drawImage(fpath, 0, 0, cww, cwh); - can.sleepFor(0.5f); - #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square - { - side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads - int tid = omp_get_thread_num(); - int ndrawn = 0, xblock = cww/side, yblock = cwh/side; - int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; - int xmax = xmin+xblock; clamp(xmax,0,cww-1); - int ymax = ymin+yblock; clamp(ymax,0,cwh-1); - int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); - for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); - } -} - -int main(int argc, char* argv[]) { - int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; - TextureHandler::getDimensions(fname,w,h); - Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); - c.run(blurImageFunction,fname,t); -} diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile deleted file mode 100644 index a41f766fc..000000000 --- a/src/tests/testBlurImage/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testBlurImage - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testBlurImage - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testBlurImage/testBlurImage.cpp b/src/tests/testBlurImage/testBlurImage.cpp deleted file mode 100644 index 005d6399d..000000000 --- a/src/tests/testBlurImage/testBlurImage.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * testBlurImage.cpp - * - * Usage: ./testBlurImage - */ - -#include -#include - -using namespace tsgl; - -int depthtest(int xmin, int ymin, int xmax, int ymax) { - int xd = 0, yd = 0; - for (float d = xmax-xmin; d > 1; d=ceil(d/2), ++xd); - for (float d = ymax-ymin; d > 1; d=ceil(d/2), ++yd); - return ((xd > yd) ? xd : yd); -} - -bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { - if (xmin > xmax || ymin > ymax) - return false; - if (depth > 0) { - int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; - blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); - blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); - blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); - blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); - return false; - } - ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); - ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); - for (int j = ymin; j <= ymax; ++j) - for (int i = xmin; i <= xmax; ++i) - can.drawPoint(i,j,Colors::blend(top,bot)); - return true; -} - -void blurImageFunction(Canvas& can, std::string fpath, int threads) { - int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - int side = sqrt(threads); //Square root of the number of threads, rounded down - can.drawImage(fpath, 0, 0, cww, cwh); - can.sleepFor(0.5f); - #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square - { - side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads - int tid = omp_get_thread_num(); - int ndrawn = 0, xblock = cww/side, yblock = cwh/side; - int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; - int xmax = xmin+xblock; clamp(xmax,0,cww-1); - int ymax = ymin+yblock; clamp(ymax,0,cwh-1); - int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); - for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); - } -} - -int main(int argc, char* argv[]) { - int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; - TextureHandler::getDimensions(fname,w,h); - Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); - c.run(blurImageFunction,fname,t); -} diff --git a/src/tests/testCalcPi.cpp b/src/tests/testCalcPi.cpp deleted file mode 100644 index 6a3a6074c..000000000 --- a/src/tests/testCalcPi.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * testCalcPi.cpp - * - * Usage: ./testCalcPi - */ - -#include // printf(), ... -#include // stoll(), ... -#include // exit() -#include // OpenMP functions -#include // IntegralViewer - -using namespace tsgl; - -/*! - * \brief Compute a y-coordinate. - * \details Takes in an x-coordinate and calculates its corresponding y-coordinate. - * The IntegralViewer class then plots that point. - * \param x The x-coordinate to calculate the y-coordinate for. - * \return The calculated y-coordinate for the passed x value. - * \see IntegralViewer class. - */ -inline Decimal unitCircleFunction(Decimal x) { - return (fabs(x) < 1.0L) ? sqrt( 1.0L - (x*x) ) : 0.0L; -} - -/*! - * \brief Computes the Cosine value for an x-coordinate. - * \param x The x value to calculate the Cosine value for. - * \return The Cosine value for the passed x value. - */ -inline Decimal sineFunction(Decimal x) { - return cos(8*x); -} - -/*! - * \brief testCalcPi's main method. - * \details Everything that is needed in order to run testCalcPi is in this main method. - * - Handle command-line arguments that were passed. If more than 2 were passed, print an error message and - * exit the process. - * - Now, check and see if any command-line arguments were passed at all. If not, set default values - * for the number of intervals and the number of threads to use. - * - Setup the IntegralViewer object; set the number of threads to use and create the IntergralViewer - * object with the information given and calculated. - * - Evaluate the integral of the unit circle function using rectangles, then evaluate it using trapezoids. - * - Now evaluate the Cosine function integral using rectangles and trapezoids. - * . - */ -int main(int argc, char** argv) { - //Handle command line - if (argc > 3) { - fprintf(stderr, "\nUsage: calcPI2 [intervals] [numThreads]\n\n"); - exit(1); - } - - //Check if the number of intervals and the number of threads was passed - //If one was not, set it to a default value - long long numIntervals = (argc > 1) ? std::stoll(argv[1], 0, 10) : 1; - unsigned numThreads = (argc > 2) ? std::stoll(argv[2], 0, 10) : 1; - - //Setup - omp_set_num_threads(numThreads); - IntegralViewer i1(&unitCircleFunction, 800, 800, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); - - //Go! - printf("Reference pi: 3.141592653589793238462643383279...)\n"); - long double rectanglesPi = i1.rectangleEvaluate(numIntervals) * 4.0; - printf("Rectangles pi: %32.30Lf in %f secs\n", rectanglesPi, i1.getRecTime() ); - long double trapezoidsPi = i1.trapezoidEvaluate(numIntervals) * 4.0; - printf("Trapezoids pi: %32.30Lf in %f secs\n", trapezoidsPi, i1.getTrapTime() ); - - //Bonus! - IntegralViewer i2(&sineFunction, 1200, 800, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); - i2.rectangleEvaluate(numIntervals); - i2.trapezoidEvaluate(numIntervals); -} diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile deleted file mode 100644 index 4d79e6724..000000000 --- a/src/tests/testCalcPi/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCalcPi - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCalcPi - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCalcPi/testCalcPi.cpp b/src/tests/testCalcPi/testCalcPi.cpp deleted file mode 100644 index 6a3a6074c..000000000 --- a/src/tests/testCalcPi/testCalcPi.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * testCalcPi.cpp - * - * Usage: ./testCalcPi - */ - -#include // printf(), ... -#include // stoll(), ... -#include // exit() -#include // OpenMP functions -#include // IntegralViewer - -using namespace tsgl; - -/*! - * \brief Compute a y-coordinate. - * \details Takes in an x-coordinate and calculates its corresponding y-coordinate. - * The IntegralViewer class then plots that point. - * \param x The x-coordinate to calculate the y-coordinate for. - * \return The calculated y-coordinate for the passed x value. - * \see IntegralViewer class. - */ -inline Decimal unitCircleFunction(Decimal x) { - return (fabs(x) < 1.0L) ? sqrt( 1.0L - (x*x) ) : 0.0L; -} - -/*! - * \brief Computes the Cosine value for an x-coordinate. - * \param x The x value to calculate the Cosine value for. - * \return The Cosine value for the passed x value. - */ -inline Decimal sineFunction(Decimal x) { - return cos(8*x); -} - -/*! - * \brief testCalcPi's main method. - * \details Everything that is needed in order to run testCalcPi is in this main method. - * - Handle command-line arguments that were passed. If more than 2 were passed, print an error message and - * exit the process. - * - Now, check and see if any command-line arguments were passed at all. If not, set default values - * for the number of intervals and the number of threads to use. - * - Setup the IntegralViewer object; set the number of threads to use and create the IntergralViewer - * object with the information given and calculated. - * - Evaluate the integral of the unit circle function using rectangles, then evaluate it using trapezoids. - * - Now evaluate the Cosine function integral using rectangles and trapezoids. - * . - */ -int main(int argc, char** argv) { - //Handle command line - if (argc > 3) { - fprintf(stderr, "\nUsage: calcPI2 [intervals] [numThreads]\n\n"); - exit(1); - } - - //Check if the number of intervals and the number of threads was passed - //If one was not, set it to a default value - long long numIntervals = (argc > 1) ? std::stoll(argv[1], 0, 10) : 1; - unsigned numThreads = (argc > 2) ? std::stoll(argv[2], 0, 10) : 1; - - //Setup - omp_set_num_threads(numThreads); - IntegralViewer i1(&unitCircleFunction, 800, 800, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); - - //Go! - printf("Reference pi: 3.141592653589793238462643383279...)\n"); - long double rectanglesPi = i1.rectangleEvaluate(numIntervals) * 4.0; - printf("Rectangles pi: %32.30Lf in %f secs\n", rectanglesPi, i1.getRecTime() ); - long double trapezoidsPi = i1.trapezoidEvaluate(numIntervals) * 4.0; - printf("Trapezoids pi: %32.30Lf in %f secs\n", trapezoidsPi, i1.getTrapTime() ); - - //Bonus! - IntegralViewer i2(&sineFunction, 1200, 800, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); - i2.rectangleEvaluate(numIntervals); - i2.trapezoidEvaluate(numIntervals); -} diff --git a/src/tests/testCircle.cpp b/src/tests/testCircle.cpp deleted file mode 100644 index 3017ff708..000000000 --- a/src/tests/testCircle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * testCircle.cpp - * - * Usage: ./testCircle - */ - -#include -#include - -using namespace tsgl; - -void circleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Circle * circle = new Circle(0,0,0,100,0,0,0,colors); - - // printf("%f\n", circle->getAlpha()); - // circle->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", circle->getAlpha()); - // circle->setColor(colors); - // printf("%f\n", circle->getAlpha()); - // circle->setCenterX(200); - // circle->setRotationPoint(0,0,0); - can.add(circle); - float floatVal = 0.0f; - GLfloat delta = 1; - while (can.isOpen()) { - can.sleep(); - // circle->setCenterX(sin(floatVal/90) * 100); - // circle->setCenterY(sin(floatVal/90) * 100); - // circle->setCenterZ(sin(floatVal/90) * 100); - // circle->setYaw(floatVal); - // circle->setPitch(floatVal); - // circle->setRoll(floatVal); - // circle->setRadius(sin(floatVal/90) * 100 + 100); - if (circle->getRadius() > 300 || circle->getRadius() < 100) { - delta *= -1; - } - circle->changeRadiusBy(delta); - if (delta > 0) { - circle->setColor(colors); - } else { - circle->setColor(RED); - } - floatVal += 1; - } - - delete circle; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Basic Circle"); - c.setBackgroundColor(BLACK); - c.run(circleFunction); -} \ No newline at end of file diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile deleted file mode 100644 index dbd7c9653..000000000 --- a/src/tests/testCircle/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCircle - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCircle - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCircle/testCircle.cpp b/src/tests/testCircle/testCircle.cpp deleted file mode 100644 index e1740776d..000000000 --- a/src/tests/testCircle/testCircle.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * testCircle.cpp - * - * Usage: ./testCircle - */ - -#include -#include - -using namespace tsgl; - -void circleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Circle * circle = new Circle(0,0,0,100,0,0,0,colors); - - // printf("%f\n", circle->getAlpha()); - // circle->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", circle->getAlpha()); - // circle->setColor(colors); - // printf("%f\n", circle->getAlpha()); - // circle->setCenterX(200); - // circle->setRotationPoint(0,0,0); - can.add(circle); - float floatVal = 0.0f; - GLfloat delta = 1; - while (can.isOpen()) { - can.sleep(); - // circle->setCenterX(sin(floatVal/90) * 100); - // circle->setCenterY(sin(floatVal/90) * 100); - // circle->setCenterZ(sin(floatVal/90) * 100); - // circle->setYaw(floatVal); - // circle->setPitch(floatVal); - // circle->setRoll(floatVal); - // circle->setRadius(sin(floatVal/90) * 100 + 100); - if (circle->getRadius() > 300 || circle->getRadius() < 100) { - delta *= -1; - } - circle->changeRadiusBy(delta); - if (delta > 0) { - circle->setColor(colors); - } else { - circle->setColor(RED); - } - floatVal += 1; - } - - delete circle; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Basic Circle", BLACK); - c.run(circleFunction); -} \ No newline at end of file diff --git a/src/tests/testClock.cpp b/src/tests/testClock.cpp deleted file mode 100644 index d2fccf8b6..000000000 --- a/src/tests/testClock.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * testClock.cpp - * - * Usage: ./testClock - */ - -#include -#include -#include - -using namespace tsgl; - -void clockFunction(Canvas& can) { - Prism * head = new Prism(0,133,101,12,100,59,0,0,90,ColorFloat(.6,.3,0,1)); - can.add(head); - - Cuboid * left = new Cuboid(-45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1) ); - can.add(left); - - Cuboid * right = new Cuboid(45,-50,100,10,300,100,0,0,0,ColorFloat(.6,.3,0,1)); - can.add(right); - - Cuboid * back = new Cuboid(0,-50,55,80,300,10,0,0,0,ColorFloat(.6,.3,0,1) ); - can.add(back); - - Cuboid * bottom = new Cuboid(0,-195,110,79,10,80,0,0,0,ColorFloat(.6,.3,0,1) ); - can.add(bottom); - - Circle * face = new Circle(0,130,161,45,0,0,0,ColorFloat(1,1,0.8,1)); - can.add(face); - - Arrow * second = new Arrow(-19,130,163,38,2,0,0,0,ColorFloat(1,.8,.2,1),false); - can.add(second); - second->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - - Arrow * minute = new Arrow(-19,130,162,38,2,0,0,0,BLACK,false); - can.add(minute); - minute->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - - Arrow * hour = new Arrow(-10,130,162,20,2,0,0,0,BLACK,false); - can.add(hour); - hour->setRotationPoint(face->getCenterX(), face->getCenterY(), face->getCenterZ()); - - Ellipsoid * pendulum = new Ellipsoid(0, -150, 100,10, 10,2,0,0,0,ColorFloat(0.75,0.6,.19, 1) ); - pendulum->setRotationPoint(0,80,10); - can.add(pendulum); - - Rectangle * cord = new Rectangle(-110,80,100,220,5,90,0,0,BLACK); - cord->setIsOutlined(false); - cord->setRotationPoint(0,80,10); - can.add(cord); - - time_t t = time(NULL); - // printf("local: %s", asctime(localtime(&t))); - // printf("local: %d:%d:%d\n", localtime(&t)->tm_hour, localtime(&t)->tm_min, localtime(&t)->tm_sec); - - second->setYaw(localtime(&t)->tm_sec * -6 - 90); - minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); - hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); - - float speed = -0.28; - bool accelerationPositive = true; - while (can.isOpen()) { - can.sleep(); - t = time(NULL); - second->setYaw(localtime(&t)->tm_sec * -6 - 90); - minute->setYaw((localtime(&t)->tm_min * -6) + (localtime(&t)->tm_sec / -10) - 90); - hour->setYaw((localtime(&t)->tm_hour * -30) + (localtime(&t)->tm_min / -2) + (localtime(&t)->tm_sec / -120) - 90); - if (cord->getYaw() > 97 || cord->getYaw() < 83) { - speed = 0; - } - if (cord->getYaw() > 90 && accelerationPositive == true) { - accelerationPositive = false; - } else if (cord->getYaw() < 90 && accelerationPositive == false) { - accelerationPositive = true; - } - if (accelerationPositive) { - speed += 0.01; - } else { - speed -= 0.01; - } - cord->changeYawBy(speed); - pendulum->changeYawBy(speed); - - } - - delete head; - delete left; - delete right; - delete back; - delete bottom; - delete face; - delete second; - delete minute; - delete hour; - delete pendulum; - delete cord; -} - -int main(int argc, char* argv[]) { - // int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - // int h = (argc > 2) ? atoi(argv[2]) : w; - // if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - // w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 500, 700, "Grandfather Clock"); - c.setBackgroundColor(WHITE); - c.run(clockFunction); -} \ No newline at end of file diff --git a/src/tests/testColorWheel.cpp b/src/tests/testColorWheel.cpp deleted file mode 100644 index 3a7404d33..000000000 --- a/src/tests/testColorWheel.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * testColorWheel.cpp - * - * Usage: ./testColorWheel - */ - -#include -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/*! - * \brief Draws a gradient color wheel using OMP with multiple threads per processor and private per-thread variables. - * \details - * - \b THREADS is set to a number greater than the number of physical processors. - * - The center of the canvas is computed and stored. - * - The radius of the wheel is computed (using the minimum of the Canvas width / height) and stored. - * - The size of the \b GRADIENT is computed and stored. - * - Variables for the second and third vertices of a triangle and the current shading are initialized. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - The predetermined number of parallel threads is forked off using OMP, pulling along the coordinate - * and shading variables. - * - The actual number of threads is stored in: \b nthreads. - * - A color \b delta is computed. - * - Each thread's thread id ( \b tid ) is stored. - * - Each thread's shading is computed using it's id and \b nthreads. - * - While the Canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - Each thread's \b start is computed using the timer's lifetime and it's current id. - * - The second and third coordinates of a triangle approximating an arc of a circle are - * computed using the \b GRADIENT and the thread's \b start position. - * - A triangle is drawn on the Canvas for each thread, with the first vertex in the center, and - * the second and third vertices as computed above, with a hue based on the precomputed \b start, - * full saturation, and a value of \b shading. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void colorWheelFunction(Canvas& can, int threads) { - const int CW = can.getWindowWidth() / 2, // Half the window's width - CH = can.getWindowHeight() / 2; // Half the window's height - const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel - GRADIENT = 2 * PI / NUM_COLORS; // Gap between wedges - #pragma omp parallel num_threads(threads) - { - float x2, x3, y2, y3, shading; - int tid = omp_get_thread_num(); - int delta = tid * NUM_COLORS / threads; // Distance between threads to compute - shading = 1 - (float) tid / threads; - while (can.isOpen()) { - can.sleep(); - int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; - x2 = CW + RADIUS * sin(GRADIENT * start); - y2 = CH + RADIUS * cos(GRADIENT * start); - x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); - y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); - can.drawTriangle(CW, CH, x2, y2, x3, y3, - ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); - } - } -} - - -//Takes command line arguments for the height and width of the window -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : 64; - Canvas c(-1, -1, w, h, "Color Wheel"); - c.run(colorWheelFunction,t); -} diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile deleted file mode 100644 index 5fbc43185..000000000 --- a/src/tests/testColorWheel/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testColorWheel - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testColorWheel - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testColorWheel/testColorWheel.cpp b/src/tests/testColorWheel/testColorWheel.cpp deleted file mode 100644 index 3a7404d33..000000000 --- a/src/tests/testColorWheel/testColorWheel.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * testColorWheel.cpp - * - * Usage: ./testColorWheel - */ - -#include -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/*! - * \brief Draws a gradient color wheel using OMP with multiple threads per processor and private per-thread variables. - * \details - * - \b THREADS is set to a number greater than the number of physical processors. - * - The center of the canvas is computed and stored. - * - The radius of the wheel is computed (using the minimum of the Canvas width / height) and stored. - * - The size of the \b GRADIENT is computed and stored. - * - Variables for the second and third vertices of a triangle and the current shading are initialized. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - The predetermined number of parallel threads is forked off using OMP, pulling along the coordinate - * and shading variables. - * - The actual number of threads is stored in: \b nthreads. - * - A color \b delta is computed. - * - Each thread's thread id ( \b tid ) is stored. - * - Each thread's shading is computed using it's id and \b nthreads. - * - While the Canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - Each thread's \b start is computed using the timer's lifetime and it's current id. - * - The second and third coordinates of a triangle approximating an arc of a circle are - * computed using the \b GRADIENT and the thread's \b start position. - * - A triangle is drawn on the Canvas for each thread, with the first vertex in the center, and - * the second and third vertices as computed above, with a hue based on the precomputed \b start, - * full saturation, and a value of \b shading. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void colorWheelFunction(Canvas& can, int threads) { - const int CW = can.getWindowWidth() / 2, // Half the window's width - CH = can.getWindowHeight() / 2; // Half the window's height - const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel - GRADIENT = 2 * PI / NUM_COLORS; // Gap between wedges - #pragma omp parallel num_threads(threads) - { - float x2, x3, y2, y3, shading; - int tid = omp_get_thread_num(); - int delta = tid * NUM_COLORS / threads; // Distance between threads to compute - shading = 1 - (float) tid / threads; - while (can.isOpen()) { - can.sleep(); - int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; - x2 = CW + RADIUS * sin(GRADIENT * start); - y2 = CH + RADIUS * cos(GRADIENT * start); - x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); - y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); - can.drawTriangle(CW, CH, x2, y2, x3, y3, - ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); - } - } -} - - -//Takes command line arguments for the height and width of the window -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : 64; - Canvas c(-1, -1, w, h, "Color Wheel"); - c.run(colorWheelFunction,t); -} diff --git a/src/tests/testConcavePolygon.cpp b/src/tests/testConcavePolygon.cpp deleted file mode 100644 index 547c07364..000000000 --- a/src/tests/testConcavePolygon.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void concavePolygonFunction(Canvas& can) { - const int PSIZE = 64; - - float xx[PSIZE]; - float yy[PSIZE]; - ColorFloat color[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) - color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); - - color[1] = color[PSIZE-1]; - - xx[0] = 0; - yy[0] = 0; - for (int i = 0; i < PSIZE-1; ++i) { - if (i % 2 == 0) { - xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); - } else { - xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); - } - } - - // for (int i = 0; i < PSIZE; ++i) { - // if (i % 2 == 0) { - // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); - // } else { - // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); - // } - // } - - ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); - // printf("%f\n", c2->getAlpha()); - // c2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", c2->getAlpha()); - // c2->setColor(color); - // printf("%f\n", c2->getAlpha()); - can.add(c2); - - float floatVal = 0.0f; - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - // c2->setCenterX(sin(floatVal/90)); - // c2->setCenterY(sin(floatVal/90)); - // c2->setCenterZ(sin(floatVal/90)); - // c2->setYaw(floatVal); - // c2->setPitch(floatVal); - // c2->setRoll(floatVal); - floatVal += 1; - } - - delete c2; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Concave Polygons"); - c.setBackgroundColor(WHITE); - c.run(concavePolygonFunction); -} diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile deleted file mode 100644 index b6163fc7e..000000000 --- a/src/tests/testConcavePolygon/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testConcavePolygon - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testConcavePolygon - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testConcavePolygon/testConcavePolygon.cpp b/src/tests/testConcavePolygon/testConcavePolygon.cpp deleted file mode 100644 index 00cf81104..000000000 --- a/src/tests/testConcavePolygon/testConcavePolygon.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void concavePolygonFunction(Canvas& can) { - const int PSIZE = 64; - - float xx[PSIZE]; - float yy[PSIZE]; - ColorFloat color[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) - color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); - - color[1] = color[PSIZE-1]; - - xx[0] = 0; - yy[0] = 0; - for (int i = 0; i < PSIZE-1; ++i) { - if (i % 2 == 0) { - xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); - } else { - xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); - yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); - } - } - - // for (int i = 0; i < PSIZE; ++i) { - // if (i % 2 == 0) { - // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); - // } else { - // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); - // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); - // } - // } - - ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); - // printf("%f\n", c2->getAlpha()); - // c2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", c2->getAlpha()); - // c2->setColor(color); - // printf("%f\n", c2->getAlpha()); - can.add(c2); - - float floatVal = 0.0f; - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - // c2->setCenterX(sin(floatVal/90)); - // c2->setCenterY(sin(floatVal/90)); - // c2->setCenterZ(sin(floatVal/90)); - // c2->setYaw(floatVal); - // c2->setPitch(floatVal); - // c2->setRoll(floatVal); - floatVal += 1; - } - - delete c2; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Concave Polygons", WHITE); - c.run(concavePolygonFunction); -} diff --git a/src/tests/testCone.cpp b/src/tests/testCone.cpp deleted file mode 100644 index bcb7f9cab..000000000 --- a/src/tests/testCone.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * testCone.cpp - * - * Usage: ./testCone - */ - -#include -#include - -using namespace tsgl; - -void coneFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; - Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); - Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); - can.add(testCone); - can.add(testCone2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testCone->setCenterX(sin(rotation)*2); - // testCone->setCenterY(cos(rotation)*2); - // testCone->setCenterZ(sin(rotation)); - // testCone->setYaw(rotation*45); - // testCone->setPitch(rotation*45); - testCone->setRoll(rotation*45); - // testCone->setHeight(sin(rotation)+1.01); - // testCone->setRadius(sin(rotation)+1.01); - // if(testCone->getHeight() >= 2) { - // delta = -0.05; - // } - // if(testCone->getHeight() <= 0.05) { - // delta = 0.05; - // } - // testCone->changeHeightBy(delta); - // if(testCone->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCone->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCone->changeRadiusBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testCone->setColor(RED); - } else { - testCone->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCone; - delete testCone2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cone"); - c.setBackgroundColor(BLACK); - c.run(coneFunction); -} \ No newline at end of file diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile deleted file mode 100644 index 38b60a4c2..000000000 --- a/src/tests/testCone/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCone - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCone - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCone/testCone.cpp b/src/tests/testCone/testCone.cpp deleted file mode 100644 index 951d05b18..000000000 --- a/src/tests/testCone/testCone.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * testCone.cpp - * - * Usage: ./testCone - */ - -#include -#include - -using namespace tsgl; - -void coneFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), - ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; - Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); - Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); - can.add(testCone); - can.add(testCone2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testCone->setCenterX(sin(rotation)*2); - // testCone->setCenterY(cos(rotation)*2); - // testCone->setCenterZ(sin(rotation)); - // testCone->setYaw(rotation*45); - // testCone->setPitch(rotation*45); - testCone->setRoll(rotation*45); - // testCone->setHeight(sin(rotation)+1.01); - // testCone->setRadius(sin(rotation)+1.01); - // if(testCone->getHeight() >= 2) { - // delta = -0.05; - // } - // if(testCone->getHeight() <= 0.05) { - // delta = 0.05; - // } - // testCone->changeHeightBy(delta); - // if(testCone->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCone->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCone->changeRadiusBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testCone->setColor(RED); - } else { - testCone->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCone; - delete testCone2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cone", BLACK); - c.run(coneFunction); -} \ No newline at end of file diff --git a/src/tests/testConstructors.cpp b/src/tests/testConstructors.cpp deleted file mode 100644 index ff241b947..000000000 --- a/src/tests/testConstructors.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void constructorFunction(Canvas& can) { - // srand(time(NULL)); - const int PSIZE = 50; - - ColorFloat fillColor[PSIZE]; - ColorFloat outlineColor[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) { - fillColor[i] = Colors::randomColor(1.0f); - outlineColor[i] = Colors::randomColor(1.0f); - } - - can.drawRectangle(15, 5, 70, 95, fillColor[0], true); - can.drawRectangle(115, 5, 70, 95, fillColor[0], false); - can.drawRectangle(215, 5, 70, 95, fillColor, true); - can.drawRectangle(315, 5, 70, 95, fillColor, false); - - can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); - can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); - can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); - can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); - - can.drawSquare(5, 105, 90, fillColor[0], true); - can.drawSquare(105, 105, 90, fillColor[0], false); - can.drawSquare(205, 105, 90, fillColor, true); - can.drawSquare(305, 105, 90, fillColor, false); - - can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); - can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); - can.drawSquare(605, 105, 90, fillColor[0], outlineColor); - can.drawSquare(705, 105, 90, fillColor, outlineColor); - - can.drawStar(50, 250, 45, 6, fillColor[0], true, false); - can.drawStar(150, 250, 45, 6, fillColor[0], false, true); - can.drawStar(250, 250, 45, 6, fillColor, true, false); - can.drawStar(350, 250, 45, 6, fillColor, false, true); - - can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); - can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); - can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); - can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); - - can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); - can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); - can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); - can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); - - can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); - can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); - can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); - can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); - - can.drawEllipse(50, 450, 35, 45, fillColor[0], true); - can.drawEllipse(150, 450, 35, 45, fillColor[0], false); - can.drawEllipse(250, 450, 35, 45, fillColor, true); - can.drawEllipse(350, 450, 35, 45, fillColor, false); - - can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); - can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); - can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); - can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); - - can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); - can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); - can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); - can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); - - can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); - can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); - can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); - can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); - - can.drawCircle(50, 650, 45, fillColor[0], true); - can.drawCircle(150, 650, 45, fillColor[0], false); - can.drawCircle(250, 650, 45, fillColor, true); - can.drawCircle(350, 650, 45, fillColor, false); - - can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); - can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); - can.drawCircle(650, 650, 45, fillColor[0], outlineColor); - can.drawCircle(750, 650, 45, fillColor, outlineColor); - - int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; - - x1[0] = x1[1] = 5; - x1[2] = 50; - x1[3] = x1[4] = 95; - - x2[0] = x2[1] = 105; - x2[2] = 150; - x2[3] = x2[4] = 195; - - x3[0] = x3[1] = 205; - x3[2] = 250; - x3[3] = x3[4] = 295; - - x4[0] = x4[1] = 305; - x4[2] = 350; - x4[3] = x4[4] = 395; - - x5[0] = x5[1] = 405; - x5[2] = 450; - x5[3] = x5[4] = 495; - - x6[0] = x6[1] = 505; - x6[2] = 550; - x6[3] = x6[4] = 595; - - x7[0] = x7[1] = 605; - x7[2] = 650; - x7[3] = x7[4] = 695; - - x8[0] = x8[1] = 705; - x8[2] = 750; - x8[3] = x8[4] = 795; - - y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; - y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; - y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; - y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; - y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; - - can.drawTriangleStrip(5, x1, y1, fillColor[0], true); - can.drawTriangleStrip(5, x2, y2, fillColor[0], false); - can.drawTriangleStrip(5, x3, y3, fillColor, true); - can.drawTriangleStrip(5, x4, y4, fillColor, false); - - can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); - can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); - can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); - can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); - - int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], - y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; - - x9[0] = x9[1] = 5; - x9[2] = x9[5] = 50; - x9[3] = x9[4] = 95; - - x10[0] = x10[1] = 105; - x10[2] = x10[5] = 150; - x10[3] = x10[4] = 195; - - x11[0] = x11[1] = 205; - x11[2] = x11[5] = 250; - x11[3] = x11[4] = 295; - - x12[0] = x12[1] = 305; - x12[2] = x12[5] = 350; - x12[3] = x12[4] = 395; - - x13[0] = x13[1] = 405; - x13[2] = x13[5] = 450; - x13[3] = x13[4] = 495; - - x14[0] = x14[1] = 505; - x14[2] = x14[5] = 550; - x14[3] = x14[4] = 595; - - x15[0] = x15[1] = 605; - x15[2] = x15[5] = 650; - x15[3] = x15[4] = 695; - - x16[0] = x16[1] = 705; - x16[2] = x16[5] = 750; - x16[3] = x16[4] = 795; - - y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; - y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; - y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; - y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; - y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; - y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; - - can.drawConvexPolygon(6, x9, y9, fillColor[0], true); - can.drawConvexPolygon(6, x10, y10, fillColor[0], false); - can.drawConvexPolygon(6, x11, y11, fillColor, true); - can.drawConvexPolygon(6, x12, y12, fillColor, false); - - can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); - can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); - can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); - can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); - - int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], - y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; - - x17[0] = x17[1] = 5; - x17[2] = x17[5] = 50; - x17[3] = x17[4] = 95; - - x18[0] = x18[1] = 105; - x18[2] = x18[5] = 150; - x18[3] = x18[4] = 195; - - x19[0] = x19[1] = 205; - x19[2] = x19[5] = 250; - x19[3] = x19[4] = 295; - - x20[0] = x20[1] = 305; - x20[2] = x20[5] = 350; - x20[3] = x20[4] = 395; - - x21[0] = x21[1] = 405; - x21[2] = x21[5] = 450; - x21[3] = x21[4] = 495; - - x22[0] = x22[1] = 505; - x22[2] = x22[5] = 550; - x22[3] = x22[4] = 595; - - x23[0] = x23[1] = 605; - x23[2] = x23[5] = 650; - x23[3] = x23[4] = 695; - - x24[0] = x24[1] = 705; - x24[2] = x24[5] = 750; - x24[3] = x24[4] = 795; - - y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; - y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; - y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; - y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; - y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; - y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; - - can.drawConcavePolygon(6, x17, y17, fillColor[0], true); - can.drawConcavePolygon(6, x18, y18, fillColor[0], true); - can.drawConcavePolygon(6, x19, y19, fillColor, true); - can.drawConcavePolygon(6, x20, y20, fillColor, true); - - can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); - can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); - can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); - can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); - - can.drawArrow(805, 5, 895, 95, fillColor[3], true); - can.drawArrow(805, 105, 895, 195, fillColor, true); - - can.drawLine(805, 205, 895, 295, fillColor[3]); - can.drawLine(805, 305, 895, 395, fillColor); - - int x25[5], x26[5], y25[5], y26[5]; - - x25[0] = x26[0] = 820; - x25[1] = x26[1] = 805; - x25[2] = x26[2] = 880; - x25[3] = x26[3] = 895; - x25[4] = x26[4] = 870; - - y25[0] = 450; - y25[1] = 405; - y25[2] = 420; - y25[3] = 460; - y25[4] = 495; - - y26[0] = 550; - y26[1] = 505; - y26[2] = 520; - y26[3] = 560; - y26[4] = 595; - - can.drawPolyline(5, x25, y25, fillColor[3]); - can.drawPolyline(5, x26, y26, outlineColor); - - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - - } -} - -int main(int argc, char* argv[]) { - int w = 0.9*Canvas::getDisplayHeight(); - int h = w; - Canvas c(-1, -1, w, h, "Constructors"); - c.setBackgroundColor(WHITE); - c.run(constructorFunction); -} diff --git a/src/tests/testConstructors/Makefile b/src/tests/testConstructors/Makefile deleted file mode 100644 index c01fe882d..000000000 --- a/src/tests/testConstructors/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testConstructors - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testConstructors - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testConstructors/testConstructors.cpp b/src/tests/testConstructors/testConstructors.cpp deleted file mode 100644 index 062fa79e5..000000000 --- a/src/tests/testConstructors/testConstructors.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void constructorFunction(Canvas& can) { - // srand(time(NULL)); - const int PSIZE = 50; - - ColorFloat fillColor[PSIZE]; - ColorFloat outlineColor[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) { - fillColor[i] = Colors::randomColor(1.0f); - outlineColor[i] = Colors::randomColor(1.0f); - } - - can.drawRectangle(15, 5, 70, 95, fillColor[0], true); - can.drawRectangle(115, 5, 70, 95, fillColor[0], false); - can.drawRectangle(215, 5, 70, 95, fillColor, true); - can.drawRectangle(315, 5, 70, 95, fillColor, false); - - can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); - can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); - can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); - can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); - - can.drawSquare(5, 105, 90, fillColor[0], true); - can.drawSquare(105, 105, 90, fillColor[0], false); - can.drawSquare(205, 105, 90, fillColor, true); - can.drawSquare(305, 105, 90, fillColor, false); - - can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); - can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); - can.drawSquare(605, 105, 90, fillColor[0], outlineColor); - can.drawSquare(705, 105, 90, fillColor, outlineColor); - - can.drawStar(50, 250, 45, 6, fillColor[0], true, false); - can.drawStar(150, 250, 45, 6, fillColor[0], false, true); - can.drawStar(250, 250, 45, 6, fillColor, true, false); - can.drawStar(350, 250, 45, 6, fillColor, false, true); - - can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); - can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); - can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); - can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); - - can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); - can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); - can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); - can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); - - can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); - can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); - can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); - can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); - - can.drawEllipse(50, 450, 35, 45, fillColor[0], true); - can.drawEllipse(150, 450, 35, 45, fillColor[0], false); - can.drawEllipse(250, 450, 35, 45, fillColor, true); - can.drawEllipse(350, 450, 35, 45, fillColor, false); - - can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); - can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); - can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); - can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); - - can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); - can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); - can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); - can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); - - can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); - can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); - can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); - can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); - - can.drawCircle(50, 650, 45, fillColor[0], true); - can.drawCircle(150, 650, 45, fillColor[0], false); - can.drawCircle(250, 650, 45, fillColor, true); - can.drawCircle(350, 650, 45, fillColor, false); - - can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); - can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); - can.drawCircle(650, 650, 45, fillColor[0], outlineColor); - can.drawCircle(750, 650, 45, fillColor, outlineColor); - - int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; - - x1[0] = x1[1] = 5; - x1[2] = 50; - x1[3] = x1[4] = 95; - - x2[0] = x2[1] = 105; - x2[2] = 150; - x2[3] = x2[4] = 195; - - x3[0] = x3[1] = 205; - x3[2] = 250; - x3[3] = x3[4] = 295; - - x4[0] = x4[1] = 305; - x4[2] = 350; - x4[3] = x4[4] = 395; - - x5[0] = x5[1] = 405; - x5[2] = 450; - x5[3] = x5[4] = 495; - - x6[0] = x6[1] = 505; - x6[2] = 550; - x6[3] = x6[4] = 595; - - x7[0] = x7[1] = 605; - x7[2] = 650; - x7[3] = x7[4] = 695; - - x8[0] = x8[1] = 705; - x8[2] = 750; - x8[3] = x8[4] = 795; - - y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; - y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; - y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; - y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; - y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; - - can.drawTriangleStrip(5, x1, y1, fillColor[0], true); - can.drawTriangleStrip(5, x2, y2, fillColor[0], false); - can.drawTriangleStrip(5, x3, y3, fillColor, true); - can.drawTriangleStrip(5, x4, y4, fillColor, false); - - can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); - can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); - can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); - can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); - - int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], - y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; - - x9[0] = x9[1] = 5; - x9[2] = x9[5] = 50; - x9[3] = x9[4] = 95; - - x10[0] = x10[1] = 105; - x10[2] = x10[5] = 150; - x10[3] = x10[4] = 195; - - x11[0] = x11[1] = 205; - x11[2] = x11[5] = 250; - x11[3] = x11[4] = 295; - - x12[0] = x12[1] = 305; - x12[2] = x12[5] = 350; - x12[3] = x12[4] = 395; - - x13[0] = x13[1] = 405; - x13[2] = x13[5] = 450; - x13[3] = x13[4] = 495; - - x14[0] = x14[1] = 505; - x14[2] = x14[5] = 550; - x14[3] = x14[4] = 595; - - x15[0] = x15[1] = 605; - x15[2] = x15[5] = 650; - x15[3] = x15[4] = 695; - - x16[0] = x16[1] = 705; - x16[2] = x16[5] = 750; - x16[3] = x16[4] = 795; - - y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; - y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; - y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; - y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; - y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; - y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; - - can.drawConvexPolygon(6, x9, y9, fillColor[0], true); - can.drawConvexPolygon(6, x10, y10, fillColor[0], false); - can.drawConvexPolygon(6, x11, y11, fillColor, true); - can.drawConvexPolygon(6, x12, y12, fillColor, false); - - can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); - can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); - can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); - can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); - - int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], - y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; - - x17[0] = x17[1] = 5; - x17[2] = x17[5] = 50; - x17[3] = x17[4] = 95; - - x18[0] = x18[1] = 105; - x18[2] = x18[5] = 150; - x18[3] = x18[4] = 195; - - x19[0] = x19[1] = 205; - x19[2] = x19[5] = 250; - x19[3] = x19[4] = 295; - - x20[0] = x20[1] = 305; - x20[2] = x20[5] = 350; - x20[3] = x20[4] = 395; - - x21[0] = x21[1] = 405; - x21[2] = x21[5] = 450; - x21[3] = x21[4] = 495; - - x22[0] = x22[1] = 505; - x22[2] = x22[5] = 550; - x22[3] = x22[4] = 595; - - x23[0] = x23[1] = 605; - x23[2] = x23[5] = 650; - x23[3] = x23[4] = 695; - - x24[0] = x24[1] = 705; - x24[2] = x24[5] = 750; - x24[3] = x24[4] = 795; - - y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; - y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; - y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; - y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; - y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; - y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; - - can.drawConcavePolygon(6, x17, y17, fillColor[0], true); - can.drawConcavePolygon(6, x18, y18, fillColor[0], true); - can.drawConcavePolygon(6, x19, y19, fillColor, true); - can.drawConcavePolygon(6, x20, y20, fillColor, true); - - can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); - can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); - can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); - can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); - - can.drawArrow(805, 5, 895, 95, fillColor[3], true); - can.drawArrow(805, 105, 895, 195, fillColor, true); - - can.drawLine(805, 205, 895, 295, fillColor[3]); - can.drawLine(805, 305, 895, 395, fillColor); - - int x25[5], x26[5], y25[5], y26[5]; - - x25[0] = x26[0] = 820; - x25[1] = x26[1] = 805; - x25[2] = x26[2] = 880; - x25[3] = x26[3] = 895; - x25[4] = x26[4] = 870; - - y25[0] = 450; - y25[1] = 405; - y25[2] = 420; - y25[3] = 460; - y25[4] = 495; - - y26[0] = 550; - y26[1] = 505; - y26[2] = 520; - y26[3] = 560; - y26[4] = 595; - - can.drawPolyline(5, x25, y25, fillColor[3]); - can.drawPolyline(5, x26, y26, outlineColor); - - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - - } -} - -int main(int argc, char* argv[]) { - int w = 0.9*Canvas::getDisplayHeight(); - int h = w; - Canvas c(-1, -1, w, h, "Constructors", WHITE); - c.run(constructorFunction); -} diff --git a/src/tests/testConvexPolygon.cpp b/src/tests/testConvexPolygon.cpp deleted file mode 100644 index 8e7b77932..000000000 --- a/src/tests/testConvexPolygon.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * testConvexPolygon.cpp - * - * Usage: ./testConvexPolygon - */ - -#include -#include - -using namespace tsgl; - -void convexPolygonFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { -50,-50, 0,25,50, 50, 25 }; - float y[] = { -50, 25,50,40,10,-10,-50 }; - ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); - // cp->setCenterX(2); - // cp->setRotationPoint(0,0,0); - can.add(cp); - float floatVal = 0.0f; - while (can.isOpen()) { - can.sleep(); - // cp->setCenterX(sin(floatVal/90) * 100); - // cp->setCenterY(sin(floatVal/90) * 100); - // cp->setCenterZ(sin(floatVal/90) * 100); - // cp->setYaw(floatVal); - // cp->setPitch(floatVal); - // cp->setRoll(floatVal); - // if (floatVal < 200) { - // cp->setColor(colors); - // } else { - // cp->setColor(RED); - // if (floatVal > 400) { - // floatVal = 0; - // } - // } - floatVal += 1; - } - - delete cp; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon"); - c.setBackgroundColor(BLACK); - c.run(convexPolygonFunction); -} \ No newline at end of file diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile deleted file mode 100644 index 642cd99a6..000000000 --- a/src/tests/testConvexPolygon/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testConvexPolygon - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testConvexPolygon - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testConvexPolygon/testConvexPolygon.cpp b/src/tests/testConvexPolygon/testConvexPolygon.cpp deleted file mode 100644 index 43174f924..000000000 --- a/src/tests/testConvexPolygon/testConvexPolygon.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * testConvexPolygon.cpp - * - * Usage: ./testConvexPolygon - */ - -#include -#include - -using namespace tsgl; - -void convexPolygonFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { -50,-50, 0,25,50, 50, 25 }; - float y[] = { -50, 25,50,40,10,-10,-50 }; - ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); - // cp->setCenterX(2); - // cp->setRotationPoint(0,0,0); - can.add(cp); - float floatVal = 0.0f; - while (can.isOpen()) { - can.sleep(); - // cp->setCenterX(sin(floatVal/90) * 100); - // cp->setCenterY(sin(floatVal/90) * 100); - // cp->setCenterZ(sin(floatVal/90) * 100); - // cp->setYaw(floatVal); - // cp->setPitch(floatVal); - // cp->setRoll(floatVal); - // if (floatVal < 200) { - // cp->setColor(colors); - // } else { - // cp->setColor(RED); - // if (floatVal > 400) { - // floatVal = 0; - // } - // } - floatVal += 1; - } - - delete cp; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon", BLACK); - c.run(convexPolygonFunction); -} \ No newline at end of file diff --git a/src/tests/testConway.cpp b/src/tests/testConway.cpp deleted file mode 100644 index f474bc1df..000000000 --- a/src/tests/testConway.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * testConway.cpp - * - * Usage: ./testConway - */ - -#include -#include "Conway/LifeFarm.h" - -using namespace tsgl; - -/*! - * \brief Simulates Conway's Game of Life! (Now interactive!) - * \note See https://en.wikipedia.org/wiki/Conway's_Game_of_Life - * \details It is drawn in this way: - * - Get the iterations per frame, window width and window height and store them. - * - Create a LifeFarm object to hold the objects (ants) that move around on the screen. - * - Set the ability to draw ants that have "died" in the game to true. - * - Set boolean flags that determine when the animation has been paused and when the left mouse button - * has been clicked. - * - Bind the spacebar so that when it is pressed a screenshot is taken of the current frame. - * Also, set the paused boolean flag to true. - * - Bind the left mouse button so that when it is clicked the boolean flag for keeping track of the mouse's - * state is set to true. When it is released, set that flag to false. - * - While the Canvas has not been closed: - * - Sleep the internal timer until the next draw cycle. - * - If the paused boolean flag is not set: - * - Clear the Canvas. - * - For 0 to the number of iterations: - * - If the mouse has been clicked: - * - Add an ant to the LifeFarm object. - * - Draw it on the Canvas. - * . - * - Move the ants in the LifeFarm object. - * . - * . - * - If the mouse has been clicked while the Canvas has been paused, - * add an ant to the LifeFarm object and draw it to the Canvas. - * . - * . - * \param can Reference to the Canvas to draw to. - */ -void conwayFunction(Canvas& can) { - const int IPF = 100, // Iterations per frame - WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(); // Window height - LifeFarm farm(WW,WH,&can,false); //Change the false to true for something awesome! - farm.setDrawdead(true); - bool paused = false; - bool mouseDown = false; - // can.drawRectangle(1,1,can.getWindowWidth()-2,can.getWindowHeight()-2,GREEN,false,PI/4); - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can, &paused]() { - paused = !paused; - can.recordForNumFrames(1); //Screenshot - }); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown]() { - mouseDown = true; - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown]() { - mouseDown = false; - }); - - while (can.isOpen()) { - can.sleep(); - if(!paused) { - for (int i = 0; i < IPF; i++) { - if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); - } - farm.moveAnts(); - } - } - if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); - } - } -} - -//Take command-line arguments for the width and height of the Canvas -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Conway's Game of Life"); - c.setBackgroundColor(BLACK); - c.run(conwayFunction); -} diff --git a/src/tests/testCosineIntegral.cpp b/src/tests/testCosineIntegral.cpp deleted file mode 100644 index c2dd5b3fe..000000000 --- a/src/tests/testCosineIntegral.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testCosineIntegral.cpp - * - * Usage: ./testCosineIntegral - */ - -#include -#include -#include -#include -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/*! - * \brief Draws the area under a predefined function (the integral) using CartesianCanvas - * and takes a command line argument for the number of threads to use. - * \details - * - Use the number of threads passed via command-line arguments. - * - If that number is negative, just use one thread. - * - Set up the internal timer of the Canvas to expire once every \b FRAME / 2 seconds . - * - Draw axes through the origin, with spacing PI/4 between x ticks and 0.5 between y ticks. - * - Store the width of the canvas's pixel in \b pw to avoid thousands of multiple function calls. - * - Initialize and draw a CosineFunction using the currently rendered area of the CartesianCanvas. - * - Set the CartesianCanvas' font from an external font file using setFont(). - * - Draw some labels on the CartesianCanvas to make things look pretty. - * - Set up a parallel block with OMP using \b threads as the number of threads to use. - * - Set \b nthreads to the actual number of threads spawned. - * - Calculate each thread's share of the work and store it in: \b offset. - * - Calculate each thread's starting position and store it in: \b start. - * - Calculate each thread's stopping position and store it in: \b stop. - * - For each thread, from \b start to \b stop with step size \b pw: - * - If the Canvas was closed, break. - * - Sleep the internal timer until it's ready to render. - * - Draw a line from x,0 to x,f(x) for the current x. - * . - * . - * \param can Reference to the CartesianCanvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void cosineIntegralFunction(Cart& can, int numberOfThreads) { - int threads = numberOfThreads; - if (threads <= 0) { - threads = 1; - } - - can.drawAxes(0, 0, PI/4, .5); - long double pw = can.getPixelWidth(); - CosineFunction function1; - can.drawFunction(function1); - - //\u03C0 = Ï€ - can.setFont("../assets/freefont/FreeSerif.ttf"); - can.drawText(L"-1.5\u03C0", -1.5 * PI - .1, .25, 20); // Note the important capital L, used to support Unicode. - can.drawText(L"1.5\u03C0", 1.5 * PI - .2, .25, 20); - can.drawText(L"1", .1, 1.05, 20); - can.drawText(L"-1", .1, -1.1, 20); - -#pragma omp parallel num_threads(threads) - { - threads = omp_get_num_threads(); - long double offset = 3*PI / threads; - long double start = -1.5*PI + omp_get_thread_num() * offset; - long double stop = start + offset; - for (long double i = start; i < stop; i += pw) { - if (!can.isOpen()) break; - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - can.drawLine(i, 0, i, function1.valueAt(i), Colors::highContrastColor(omp_get_thread_num())); - } - } -} - -//Takes in command line arguments for the width and height of the window -//as well as the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads to use - Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", FRAME / 2); - c.setBackgroundColor(WHITE); - c.run(cosineIntegralFunction,t); -} diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile deleted file mode 100644 index 7190a88d7..000000000 --- a/src/tests/testCosineIntegral/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCosineIntegral - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCosineIntegral - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCosineIntegral/testCosineIntegral.cpp b/src/tests/testCosineIntegral/testCosineIntegral.cpp deleted file mode 100644 index 470c99be9..000000000 --- a/src/tests/testCosineIntegral/testCosineIntegral.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * testCosineIntegral.cpp - * - * Usage: ./testCosineIntegral - */ - -#include -#include -#include -#include -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/*! - * \brief Draws the area under a predefined function (the integral) using CartesianCanvas - * and takes a command line argument for the number of threads to use. - * \details - * - Use the number of threads passed via command-line arguments. - * - If that number is negative, just use one thread. - * - Set up the internal timer of the Canvas to expire once every \b FRAME / 2 seconds . - * - Draw axes through the origin, with spacing PI/4 between x ticks and 0.5 between y ticks. - * - Store the width of the canvas's pixel in \b pw to avoid thousands of multiple function calls. - * - Initialize and draw a CosineFunction using the currently rendered area of the CartesianCanvas. - * - Set the CartesianCanvas' font from an external font file using setFont(). - * - Draw some labels on the CartesianCanvas to make things look pretty. - * - Set up a parallel block with OMP using \b threads as the number of threads to use. - * - Set \b nthreads to the actual number of threads spawned. - * - Calculate each thread's share of the work and store it in: \b offset. - * - Calculate each thread's starting position and store it in: \b start. - * - Calculate each thread's stopping position and store it in: \b stop. - * - For each thread, from \b start to \b stop with step size \b pw: - * - If the Canvas was closed, break. - * - Sleep the internal timer until it's ready to render. - * - Draw a line from x,0 to x,f(x) for the current x. - * . - * . - * \param can Reference to the CartesianCanvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void cosineIntegralFunction(Cart& can, int numberOfThreads) { - int threads = numberOfThreads; - if (threads <= 0) { - threads = 1; - } - - can.drawAxes(0, 0, PI/4, .5); - long double pw = can.getPixelWidth(); - CosineFunction function1; - can.drawFunction(function1); - - //\u03C0 = Ï€ - can.setFont("../assets/freefont/FreeSerif.ttf"); - can.drawText(L"-1.5\u03C0", -1.5 * PI - .1, .25, 20); // Note the important capital L, used to support Unicode. - can.drawText(L"1.5\u03C0", 1.5 * PI - .2, .25, 20); - can.drawText(L"1", .1, 1.05, 20); - can.drawText(L"-1", .1, -1.1, 20); - -#pragma omp parallel num_threads(threads) - { - threads = omp_get_num_threads(); - long double offset = 3*PI / threads; - long double start = -1.5*PI + omp_get_thread_num() * offset; - long double stop = start + offset; - for (long double i = start; i < stop; i += pw) { - if (!can.isOpen()) break; - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - can.drawLine(i, 0, i, function1.valueAt(i), Colors::highContrastColor(omp_get_thread_num())); - } - } -} - -//Takes in command line arguments for the width and height of the window -//as well as the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads to use - Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", WHITE, FRAME / 2); - c.run(cosineIntegralFunction,t); -} diff --git a/src/tests/testCube.cpp b/src/tests/testCube.cpp deleted file mode 100644 index 3994dcd81..000000000 --- a/src/tests/testCube.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * testCube.cpp - * - * Usage: ./testCube - */ - -#include -#include - -using namespace tsgl; - -void cubeFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); - Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); - can.add(testCube); - - // printf("%f\n", testCube2->getAlpha()); - // testCube2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testCube2->getAlpha()); - // testCube2->setColor(colors); - // printf("%f\n", testCube2->getAlpha()); - can.add(testCube2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { - testCube->setIsOutlined(boolean); - boolean = !boolean; - }); - - bool ss = false; - while (can.isOpen()) { - can.sleep(); - // testCube->setCenterX(sin(rotation)*200); - // testCube->setCenterY(cos(rotation)*200); - // testCube->setCenterZ(sin(rotation)*100); - // testCube->setYaw(rotation*45); - testCube->setPitch(rotation*45); - // testCube->setRoll(rotation*45); - // testCube->setSideLength(cos(rotation) * 100 +101); - // if(testCube->getSideLength() >= 2) { - // delta = -5; - // } - // if(testCube->getSideLength() <= 5) { - // delta = 5; - // } - // testCube->changeSideLengthBy(delta); - //testCube2->setRoll(rotation); - // if (rotation*45 >= 360) { - // if (boolean) { - // testCube->setColor(RED); - // } else { - // testCube->setColor(colors); - // } - // boolean = !boolean; - // rotation = 0; - // } - if (can.getFrameNumber() > 50 && !ss) { - can.takeScreenShot(); - ss = true; - } - rotation+=0.01; - } - - delete testCube; - delete testCube2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cube"); - c.setBackgroundColor(BLACK); - c.run(cubeFunction); -} \ No newline at end of file diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile deleted file mode 100644 index 9373a2ea4..000000000 --- a/src/tests/testCube/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCube - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCube - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCube/testCube.cpp b/src/tests/testCube/testCube.cpp deleted file mode 100644 index 30b640e4b..000000000 --- a/src/tests/testCube/testCube.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * testCube.cpp - * - * Usage: ./testCube - */ - -#include -#include - -using namespace tsgl; - -void cubeFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); - Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); - can.add(testCube); - - // printf("%f\n", testCube2->getAlpha()); - // testCube2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testCube2->getAlpha()); - // testCube2->setColor(colors); - // printf("%f\n", testCube2->getAlpha()); - can.add(testCube2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { - testCube->setIsOutlined(boolean); - boolean = !boolean; - }); - - bool ss = false; - while (can.isOpen()) { - can.sleep(); - // testCube->setCenterX(sin(rotation)*200); - // testCube->setCenterY(cos(rotation)*200); - // testCube->setCenterZ(sin(rotation)*100); - // testCube->setYaw(rotation*45); - testCube->setPitch(rotation*45); - // testCube->setRoll(rotation*45); - // testCube->setSideLength(cos(rotation) * 100 +101); - // if(testCube->getSideLength() >= 2) { - // delta = -5; - // } - // if(testCube->getSideLength() <= 5) { - // delta = 5; - // } - // testCube->changeSideLengthBy(delta); - //testCube2->setRoll(rotation); - // if (rotation*45 >= 360) { - // if (boolean) { - // testCube->setColor(RED); - // } else { - // testCube->setColor(colors); - // } - // boolean = !boolean; - // rotation = 0; - // } - if (can.getFrameNumber() > 50 && !ss) { - can.takeScreenShot(); - ss = true; - } - rotation+=0.01; - } - - delete testCube; - delete testCube2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cube", BLACK); - c.run(cubeFunction); -} \ No newline at end of file diff --git a/src/tests/testCuboid.cpp b/src/tests/testCuboid.cpp deleted file mode 100644 index b5893b27a..000000000 --- a/src/tests/testCuboid.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * testCuboid.cpp - * - * Usage: ./testCuboid - */ - -#include -#include - -using namespace tsgl; - -void cuboidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); - Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); - // printf("%f\n", testCuboid2->getAlpha()); - // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testCuboid2->getAlpha()); - // testCuboid2->setColor(colors); - // printf("%f\n", testCuboid2->getAlpha()); - can.add(testCuboid); - can.add(testCuboid2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false;; - while (can.isOpen()) { - can.sleep(); - // testCuboid->setCenterX(sin(rotation)*200); - // testCuboid->setCenterY(cos(rotation)*200); - // testCuboid->setCenterZ(sin(rotation)*100); - // testCuboid->setYaw(rotation*45); - testCuboid->setPitch(rotation*45); - // testCuboid->setRoll(rotation*45); - // testCuboid->setWidth(cos(rotation)*100+101); - // testCuboid->setHeight(cos(rotation)*100+301); - // testCuboid->setLength(cos(rotation)*100+201); - // if(testCuboid->getWidth() >= 200) { - // delta = -5; - // } - // if(testCuboid->getWidth() <= 5) { - // delta = 5; - // } - // testCuboid->changeWidthBy(delta); - - // if(testCuboid->getHeight() >= 500) { - // delta = -5; - // } - // if(testCuboid->getHeight() <= 300) { - // delta = 5; - // } - // testCuboid->changeHeightBy(delta); - - // if(testCuboid->getLength() >= 300) { - // delta = -5; - // } - // if(testCuboid->getLength() <= 100) { - // delta = 5; - // } - // testCuboid->changeLengthBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testCuboid->setColor(RED); - } else { - testCuboid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCuboid; - delete testCuboid2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cuboid"); - c.setBackgroundColor(BLACK); - c.run(cuboidFunction); -} \ No newline at end of file diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile deleted file mode 100644 index 4a5120ec3..000000000 --- a/src/tests/testCuboid/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCuboid - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCuboid - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCuboid/testCuboid.cpp b/src/tests/testCuboid/testCuboid.cpp deleted file mode 100644 index ac407e5e9..000000000 --- a/src/tests/testCuboid/testCuboid.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testCuboid.cpp - * - * Usage: ./testCuboid - */ - -#include -#include - -using namespace tsgl; - -void cuboidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; - Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); - Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); - // printf("%f\n", testCuboid2->getAlpha()); - // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testCuboid2->getAlpha()); - // testCuboid2->setColor(colors); - // printf("%f\n", testCuboid2->getAlpha()); - can.add(testCuboid); - can.add(testCuboid2); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false;; - while (can.isOpen()) { - can.sleep(); - // testCuboid->setCenterX(sin(rotation)*200); - // testCuboid->setCenterY(cos(rotation)*200); - // testCuboid->setCenterZ(sin(rotation)*100); - // testCuboid->setYaw(rotation*45); - testCuboid->setPitch(rotation*45); - // testCuboid->setRoll(rotation*45); - // testCuboid->setWidth(cos(rotation)*100+101); - // testCuboid->setHeight(cos(rotation)*100+301); - // testCuboid->setLength(cos(rotation)*100+201); - // if(testCuboid->getWidth() >= 200) { - // delta = -5; - // } - // if(testCuboid->getWidth() <= 5) { - // delta = 5; - // } - // testCuboid->changeWidthBy(delta); - - // if(testCuboid->getHeight() >= 500) { - // delta = -5; - // } - // if(testCuboid->getHeight() <= 300) { - // delta = 5; - // } - // testCuboid->changeHeightBy(delta); - - // if(testCuboid->getLength() >= 300) { - // delta = -5; - // } - // if(testCuboid->getLength() <= 100) { - // delta = 5; - // } - // testCuboid->changeLengthBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testCuboid->setColor(RED); - } else { - testCuboid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCuboid; - delete testCuboid2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cuboid", BLACK); - c.run(cuboidFunction); -} \ No newline at end of file diff --git a/src/tests/testCylinder.cpp b/src/tests/testCylinder.cpp deleted file mode 100644 index 6e8075e45..000000000 --- a/src/tests/testCylinder.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * testCylinder.cpp - * - * Usage: ./testCylinder - */ - -#include -#include - -using namespace tsgl; - -void cylinderFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); - can.add(testCylinder); - can.add(testCylinder2); - float rotation = 0.0f; - // GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testCylinder->setCenterX(sin(rotation)*2); - // testCylinder->setCenterY(cos(rotation)*2); - // testCylinder->setCenterZ(sin(rotation)); - // testCylinder->setYaw(rotation*45); - testCylinder->setPitch(rotation*45); - // testCylinder->setRoll(rotation*45); - // testCylinder->setHeight(sin(rotation)+1.01); - // testCylinder->setRadius(sin(rotation)+1.01); - // if(testCylinder->getHeight() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getHeight() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeHeightBy(delta); - // if(testCylinder->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testCylinder->setColor(RED); - } else { - testCylinder->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCylinder; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cylinder"); - c.setBackgroundColor(BLACK); - c.run(cylinderFunction); -} \ No newline at end of file diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile deleted file mode 100644 index aff15ef0d..000000000 --- a/src/tests/testCylinder/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testCylinder - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testCylinder - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testCylinder/testCylinder.cpp b/src/tests/testCylinder/testCylinder.cpp deleted file mode 100644 index 8df38a692..000000000 --- a/src/tests/testCylinder/testCylinder.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * testCylinder.cpp - * - * Usage: ./testCylinder - */ - -#include -#include - -using namespace tsgl; - -void cylinderFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); - can.add(testCylinder); - can.add(testCylinder2); - float rotation = 0.0f; - // GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testCylinder->setCenterX(sin(rotation)*2); - // testCylinder->setCenterY(cos(rotation)*2); - // testCylinder->setCenterZ(sin(rotation)); - // testCylinder->setYaw(rotation*45); - testCylinder->setPitch(rotation*45); - // testCylinder->setRoll(rotation*45); - // testCylinder->setHeight(sin(rotation)+1.01); - // testCylinder->setRadius(sin(rotation)+1.01); - // if(testCylinder->getHeight() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getHeight() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeHeightBy(delta); - // if(testCylinder->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testCylinder->setColor(RED); - } else { - testCylinder->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCylinder; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); - c.run(cylinderFunction); -} \ No newline at end of file diff --git a/src/tests/testDice.cpp b/src/tests/testDice.cpp deleted file mode 100644 index f3fafa2d1..000000000 --- a/src/tests/testDice.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * testDice.cpp - * - * Usage: ./testDice - * Note: currently has some interesting rotation issues that mean that the - * API will probably have to be updated. Not compiling since it won't - * really work, alter the Makefile to understand the issue. Has to do with composite - * Euler angles. - */ - -#include -#include - -using namespace tsgl; - -void diceFunction(Canvas& can) { - Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); - can.add(die); - - RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); - can.add(spot1); - spot1->setRotationPoint(0,0,0); - - - RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); - spot2_1->setRotationPoint(0,0,0); - can.add(spot2_1); - RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); - spot2_2->setRotationPoint(0,0,0); - can.add(spot2_2); - - RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); - spot3_1->setRotationPoint(0,0,0); - can.add(spot3_1); - RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); - spot3_2->setRotationPoint(0,0,0); - can.add(spot3_2); - RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); - spot3_3->setRotationPoint(0,0,0); - can.add(spot3_3); - - // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_1->setRotationPoint(0,0,0); - // can.add(spot4_1); - // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_2->setRotationPoint(0,0,0); - // can.add(spot4_2); - // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_3->setRotationPoint(0,0,0); - // can.add(spot4_3); - // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_4->setRotationPoint(0,0,0); - // can.add(spot4_4); - - RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); - spot5_1->setRotationPoint(0,0,0); - can.add(spot5_1); - RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_2->setRotationPoint(0,0,0); - can.add(spot5_2); - RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_3->setRotationPoint(0,0,0); - can.add(spot5_3); - RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_4->setRotationPoint(0,0,0); - can.add(spot5_4); - RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_5->setRotationPoint(0,0,0); - can.add(spot5_5); - - RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_1); - RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_2); - RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_3); - RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_4); - RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_5); - RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_6); - spot6_1->setRotationPoint(0,0,0); - spot6_2->setRotationPoint(0,0,0); - spot6_3->setRotationPoint(0,0,0); - spot6_4->setRotationPoint(0,0,0); - spot6_5->setRotationPoint(0,0,0); - spot6_6->setRotationPoint(0,0,0); - - // die->setRoll(45); - // spot1->setRoll(45); - // spot2_1->setRoll(45-90); - // spot2_2->setRoll(45-90); - // spot3_1->setRoll(180); - // spot3_2->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot4_1->setRoll(45); - // spot4_2->setRoll(45); - // spot4_3->setRoll(45); - // spot4_4->setRoll(45); - // spot5_1->setRoll(45+90); - // spot5_2->setRoll(45+90); - // spot5_3->setRoll(45+90); - // spot5_4->setRoll(45+90); - // spot5_5->setRoll(45+90); - // spot6_1->setRoll(45+180); - // spot6_2->setRoll(45+180); - // spot6_3->setRoll(45+180); - // spot6_4->setRoll(45+180); - // spot6_5->setRoll(45+180); - // spot6_6->setRoll(45+180); - - float rotation = 0; - while (can.isOpen()) { - can.sleep(); - // die->setRoll(rotation); - // spot1->setRoll(rotation); - // spot2_1->setRoll(rotation-90); - // spot2_2->setRoll(rotation-90); - // spot3_1->setPitch(rotation); - // spot3_2->setPitch(rotation); - // spot3_3->setPitch(rotation); - // spot4_1->setRoll(rotation); - // spot4_2->setRoll(rotation); - // spot4_3->setRoll(rotation); - // spot4_4->setRoll(rotation); - // spot5_1->setRoll(rotation+90); - // spot5_2->setRoll(rotation+90); - // spot5_3->setRoll(rotation+90); - // spot5_4->setRoll(rotation+90); - // spot5_5->setRoll(rotation+90); - // spot6_1->setRoll(rotation+180); - // spot6_2->setRoll(rotation+180); - // spot6_3->setRoll(rotation+180); - // spot6_4->setRoll(rotation+180); - // spot6_5->setRoll(rotation+180); - // spot6_6->setRoll(rotation+180); - - die->setPitch(rotation); - spot1->setPitch(rotation); - spot2_1->setPitch(rotation); - spot2_2->setPitch(rotation); - spot3_1->setPitch(rotation-90); - spot3_2->setPitch(rotation-90); - spot3_3->setPitch(rotation-90); - // spot4_1->setPitch(rotation+90); - // spot4_2->setPitch(rotation+90); - // spot4_3->setPitch(rotation+90); - // spot4_4->setPitch(rotation+90); - spot5_1->setPitch(rotation); - spot5_2->setPitch(rotation); - spot5_3->setPitch(rotation); - spot5_4->setPitch(rotation); - spot5_5->setPitch(rotation); - spot6_1->setPitch(rotation); - spot6_2->setPitch(rotation); - spot6_3->setPitch(rotation); - spot6_4->setPitch(rotation); - spot6_5->setPitch(rotation); - spot6_6->setPitch(rotation); - rotation += 1; - } - - delete die; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Dice Rolling"); - c.setBackgroundColor(GRAY); - c.run(diceFunction); -} \ No newline at end of file diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile deleted file mode 100644 index eef80cbac..000000000 --- a/src/tests/testDice/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testDice - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testDice - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testDice/testDice.cpp b/src/tests/testDice/testDice.cpp deleted file mode 100644 index 5d674296b..000000000 --- a/src/tests/testDice/testDice.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * testDice.cpp - * - * Usage: ./testDice - * Note: currently has some interesting rotation issues that mean that the - * API will probably have to be updated. Not compiling since it won't - * really work, alter the Makefile to understand the issue. Has to do with composite - * Euler angles. - */ - -#include -#include - -using namespace tsgl; - -void diceFunction(Canvas& can) { - Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); - can.add(die); - - RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); - can.add(spot1); - spot1->setRotationPoint(0,0,0); - - - RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); - spot2_1->setRotationPoint(0,0,0); - can.add(spot2_1); - RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); - spot2_2->setRotationPoint(0,0,0); - can.add(spot2_2); - - RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); - spot3_1->setRotationPoint(0,0,0); - can.add(spot3_1); - RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); - spot3_2->setRotationPoint(0,0,0); - can.add(spot3_2); - RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); - spot3_3->setRotationPoint(0,0,0); - can.add(spot3_3); - - // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_1->setRotationPoint(0,0,0); - // can.add(spot4_1); - // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_2->setRotationPoint(0,0,0); - // can.add(spot4_2); - // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_3->setRotationPoint(0,0,0); - // can.add(spot4_3); - // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); - // spot4_4->setRotationPoint(0,0,0); - // can.add(spot4_4); - - RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); - spot5_1->setRotationPoint(0,0,0); - can.add(spot5_1); - RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_2->setRotationPoint(0,0,0); - can.add(spot5_2); - RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_3->setRotationPoint(0,0,0); - can.add(spot5_3); - RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_4->setRotationPoint(0,0,0); - can.add(spot5_4); - RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); - spot5_5->setRotationPoint(0,0,0); - can.add(spot5_5); - - RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_1); - RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_2); - RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_3); - RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_4); - RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_5); - RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); - can.add(spot6_6); - spot6_1->setRotationPoint(0,0,0); - spot6_2->setRotationPoint(0,0,0); - spot6_3->setRotationPoint(0,0,0); - spot6_4->setRotationPoint(0,0,0); - spot6_5->setRotationPoint(0,0,0); - spot6_6->setRotationPoint(0,0,0); - - // die->setRoll(45); - // spot1->setRoll(45); - // spot2_1->setRoll(45-90); - // spot2_2->setRoll(45-90); - // spot3_1->setRoll(180); - // spot3_2->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot3_3->setRoll(180); - // spot4_1->setRoll(45); - // spot4_2->setRoll(45); - // spot4_3->setRoll(45); - // spot4_4->setRoll(45); - // spot5_1->setRoll(45+90); - // spot5_2->setRoll(45+90); - // spot5_3->setRoll(45+90); - // spot5_4->setRoll(45+90); - // spot5_5->setRoll(45+90); - // spot6_1->setRoll(45+180); - // spot6_2->setRoll(45+180); - // spot6_3->setRoll(45+180); - // spot6_4->setRoll(45+180); - // spot6_5->setRoll(45+180); - // spot6_6->setRoll(45+180); - - float rotation = 0; - while (can.isOpen()) { - can.sleep(); - // die->setRoll(rotation); - // spot1->setRoll(rotation); - // spot2_1->setRoll(rotation-90); - // spot2_2->setRoll(rotation-90); - // spot3_1->setPitch(rotation); - // spot3_2->setPitch(rotation); - // spot3_3->setPitch(rotation); - // spot4_1->setRoll(rotation); - // spot4_2->setRoll(rotation); - // spot4_3->setRoll(rotation); - // spot4_4->setRoll(rotation); - // spot5_1->setRoll(rotation+90); - // spot5_2->setRoll(rotation+90); - // spot5_3->setRoll(rotation+90); - // spot5_4->setRoll(rotation+90); - // spot5_5->setRoll(rotation+90); - // spot6_1->setRoll(rotation+180); - // spot6_2->setRoll(rotation+180); - // spot6_3->setRoll(rotation+180); - // spot6_4->setRoll(rotation+180); - // spot6_5->setRoll(rotation+180); - // spot6_6->setRoll(rotation+180); - - die->setPitch(rotation); - spot1->setPitch(rotation); - spot2_1->setPitch(rotation); - spot2_2->setPitch(rotation); - spot3_1->setPitch(rotation-90); - spot3_2->setPitch(rotation-90); - spot3_3->setPitch(rotation-90); - // spot4_1->setPitch(rotation+90); - // spot4_2->setPitch(rotation+90); - // spot4_3->setPitch(rotation+90); - // spot4_4->setPitch(rotation+90); - spot5_1->setPitch(rotation); - spot5_2->setPitch(rotation); - spot5_3->setPitch(rotation); - spot5_4->setPitch(rotation); - spot5_5->setPitch(rotation); - spot6_1->setPitch(rotation); - spot6_2->setPitch(rotation); - spot6_3->setPitch(rotation); - spot6_4->setPitch(rotation); - spot6_5->setPitch(rotation); - spot6_6->setPitch(rotation); - rotation += 1; - } - - delete die; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Dice Rolling"); - c.run(diceFunction); -} \ No newline at end of file diff --git a/src/tests/testDiorama.cpp b/src/tests/testDiorama.cpp deleted file mode 100644 index 01dffe79b..000000000 --- a/src/tests/testDiorama.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * testDiorama.cpp - * - * Usage: ./testDiorama - */ - -#include -#include - -using namespace tsgl; - -void dioramaFunction(Canvas& can) { - Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); - // can.add(blankCanvas); - - Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaLeft); - Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaRight); - Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaTop); - Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaBottom); - - Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); - // can.add(trunk); - - Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); - // can.add(leaves); - - Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); - // can.add(trunkFlat); - - Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); - // can.add(leavesFlat); - - float counter = 0; - while (can.isOpen()) { - // can.sleepFor(0.5); - can.sleep(); - if (can.getFrameNumber() > 700 && counter < 1) { - can.add(blankCanvas); - counter++; - } - if(can.getFrameNumber() > 1700 && counter < 2) { - can.add(trunkFlat); - counter++; - } - if(can.getFrameNumber() > 1800 && counter < 3) { - can.add(leavesFlat); - counter++; - } - if(can.getFrameNumber() > 2300 && counter < 4) { - can.add(emptyDioramaLeft); - can.add(emptyDioramaRight); - can.add(emptyDioramaTop); - can.add(emptyDioramaBottom); - counter++; - } - if(can.getFrameNumber() > 3500 && counter < 5) { - can.add(trunk); - counter++; - } - if(can.getFrameNumber() > 3600 && counter < 6) { - can.add(leaves); - counter++; - } - if(can.getFrameNumber() > 4000 && counter < 7) { - if(emptyDioramaLeft->getWidth() > 15) { - emptyDioramaLeft->changeWidthBy(-270/20); - emptyDioramaRight->changeWidthBy(-270/20); - emptyDioramaTop->changeHeightBy(-270/20); - emptyDioramaBottom->changeHeightBy(-270/20); - emptyDioramaTop->changeZBy(135/20); - emptyDioramaBottom->changeZBy(135/20); - emptyDioramaLeft->changeZBy(135/20); - emptyDioramaRight->changeZBy(135/20); - trunk->changeLengthBy(-25/20); - trunk->changeZBy(135/20); - leaves->changeZRadiusBy(-40/20); - leaves->changeZBy(135/20); - } else { - emptyDioramaLeft->setWidth(1); - emptyDioramaRight->setWidth(1); - emptyDioramaTop->setHeight(1); - emptyDioramaBottom->setHeight(1); - emptyDioramaTop->setCenterZ(135); - emptyDioramaBottom->setCenterZ(135); - emptyDioramaLeft->setCenterZ(135); - emptyDioramaRight->setCenterZ(135); - trunk->setLength(1); - trunk->setCenterZ(135); - leaves->setZRadius(1); - leaves->setCenterZ(135); - counter++; - } - } - } - - delete blankCanvas; - delete emptyDioramaLeft; - delete emptyDioramaRight; - delete emptyDioramaTop; - delete emptyDioramaBottom; - delete leaves; - delete trunkFlat; - delete leavesFlat; - -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting"); - c.setBackgroundColor(WHITE); - c.run(dioramaFunction); -} \ No newline at end of file diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile deleted file mode 100644 index 1b880fb14..000000000 --- a/src/tests/testDiorama/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testDiorama - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testDiorama - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testDiorama/testDiorama.cpp b/src/tests/testDiorama/testDiorama.cpp deleted file mode 100644 index 82214f2f6..000000000 --- a/src/tests/testDiorama/testDiorama.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * testDiorama.cpp - * - * Usage: ./testDiorama - */ - -#include -#include - -using namespace tsgl; - -void dioramaFunction(Canvas& can) { - Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); - // can.add(blankCanvas); - - Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaLeft); - Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaRight); - Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaTop); - Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); - // can.add(emptyDioramaBottom); - - Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); - // can.add(trunk); - - Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); - // can.add(leaves); - - Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); - // can.add(trunkFlat); - - Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); - // can.add(leavesFlat); - - float counter = 0; - while (can.isOpen()) { - // can.sleepFor(0.5); - can.sleep(); - if (can.getFrameNumber() > 700 && counter < 1) { - can.add(blankCanvas); - counter++; - } - if(can.getFrameNumber() > 1700 && counter < 2) { - can.add(trunkFlat); - counter++; - } - if(can.getFrameNumber() > 1800 && counter < 3) { - can.add(leavesFlat); - counter++; - } - if(can.getFrameNumber() > 2300 && counter < 4) { - can.add(emptyDioramaLeft); - can.add(emptyDioramaRight); - can.add(emptyDioramaTop); - can.add(emptyDioramaBottom); - counter++; - } - if(can.getFrameNumber() > 3500 && counter < 5) { - can.add(trunk); - counter++; - } - if(can.getFrameNumber() > 3600 && counter < 6) { - can.add(leaves); - counter++; - } - if(can.getFrameNumber() > 4000 && counter < 7) { - if(emptyDioramaLeft->getWidth() > 15) { - emptyDioramaLeft->changeWidthBy(-270/20); - emptyDioramaRight->changeWidthBy(-270/20); - emptyDioramaTop->changeHeightBy(-270/20); - emptyDioramaBottom->changeHeightBy(-270/20); - emptyDioramaTop->changeZBy(135/20); - emptyDioramaBottom->changeZBy(135/20); - emptyDioramaLeft->changeZBy(135/20); - emptyDioramaRight->changeZBy(135/20); - trunk->changeLengthBy(-25/20); - trunk->changeZBy(135/20); - leaves->changeZRadiusBy(-40/20); - leaves->changeZBy(135/20); - } else { - emptyDioramaLeft->setWidth(1); - emptyDioramaRight->setWidth(1); - emptyDioramaTop->setHeight(1); - emptyDioramaBottom->setHeight(1); - emptyDioramaTop->setCenterZ(135); - emptyDioramaBottom->setCenterZ(135); - emptyDioramaLeft->setCenterZ(135); - emptyDioramaRight->setCenterZ(135); - trunk->setLength(1); - trunk->setCenterZ(135); - leaves->setZRadius(1); - leaves->setCenterZ(135); - counter++; - } - } - } - - delete blankCanvas; - delete emptyDioramaLeft; - delete emptyDioramaRight; - delete emptyDioramaTop; - delete emptyDioramaBottom; - delete leaves; - delete trunkFlat; - delete leavesFlat; - -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting", WHITE); - c.run(dioramaFunction); -} \ No newline at end of file diff --git a/src/tests/testEllipse.cpp b/src/tests/testEllipse.cpp deleted file mode 100644 index b64990098..000000000 --- a/src/tests/testEllipse.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * testEllipse.cpp - * - * Usage: ./testEllipse - */ - -#include -#include - -using namespace tsgl; - -void ellipseFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); - // ellipse->setCenterX(200); - // ellipse->setRotationPoint(0,0,0); - // printf("%f\n", ellipse->getAlpha()); - // ellipse->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", ellipse->getAlpha()); - // ellipse->setColor(colors); - // printf("%f\n", ellipse->getAlpha()); - can.add(ellipse); - float floatVal = 0.0f; - GLfloat delta = 5; - while (can.isOpen()) { - can.sleep(); - // ellipse->setCenterX(sin(floatVal/90) * 100); - // ellipse->setCenterY(sin(floatVal/90) * 100); - // ellipse->setCenterZ(sin(floatVal/90) * 100); - // ellipse->setYaw(floatVal); - // ellipse->setPitch(floatVal); - // ellipse->setRoll(floatVal); - // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); - // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); - // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { - // delta *= -1; - // } - // ellipse->changeXRadiusBy(delta); - if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { - delta *= -1; - } - ellipse->changeYRadiusBy(delta); - if (delta > 0) { - ellipse->setColor(colors); - } else { - ellipse->setColor(RED); - } - floatVal += 1; - } - - delete ellipse; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipse"); - c.setBackgroundColor(BLACK); - c.run(ellipseFunction); -} \ No newline at end of file diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile deleted file mode 100644 index 1e88f9d23..000000000 --- a/src/tests/testEllipse/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testEllipse - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testEllipse - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testEllipse/testEllipse.cpp b/src/tests/testEllipse/testEllipse.cpp deleted file mode 100644 index dacee93d4..000000000 --- a/src/tests/testEllipse/testEllipse.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * testEllipse.cpp - * - * Usage: ./testEllipse - */ - -#include -#include - -using namespace tsgl; - -void ellipseFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); - // ellipse->setCenterX(200); - // ellipse->setRotationPoint(0,0,0); - // printf("%f\n", ellipse->getAlpha()); - // ellipse->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", ellipse->getAlpha()); - // ellipse->setColor(colors); - // printf("%f\n", ellipse->getAlpha()); - can.add(ellipse); - float floatVal = 0.0f; - GLfloat delta = 5; - while (can.isOpen()) { - can.sleep(); - // ellipse->setCenterX(sin(floatVal/90) * 100); - // ellipse->setCenterY(sin(floatVal/90) * 100); - // ellipse->setCenterZ(sin(floatVal/90) * 100); - // ellipse->setYaw(floatVal); - // ellipse->setPitch(floatVal); - // ellipse->setRoll(floatVal); - // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); - // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); - // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { - // delta *= -1; - // } - // ellipse->changeXRadiusBy(delta); - if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { - delta *= -1; - } - ellipse->changeYRadiusBy(delta); - if (delta > 0) { - ellipse->setColor(colors); - } else { - ellipse->setColor(RED); - } - floatVal += 1; - } - - delete ellipse; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipse", BLACK); - c.run(ellipseFunction); -} \ No newline at end of file diff --git a/src/tests/testEllipsoid.cpp b/src/tests/testEllipsoid.cpp deleted file mode 100644 index d317b523d..000000000 --- a/src/tests/testEllipsoid.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * testEllipsoid.cpp - * - * Usage: ./testEllipsoid - */ - -#include -#include - -using namespace tsgl; - -void ellipsoidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); - // testEllipsoid->setIsFilled(false); - Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); - testEllipsoid2->setOutlineColor(BLUE); - - // printf("%f\n", testEllipsoid->getAlpha()); - // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testEllipsoid->getAlpha()); - // testEllipsoid->setColor(colors); - // printf("%f\n", testEllipsoid->getAlpha()); - can.add(testEllipsoid); - can.add(testEllipsoid2); - float rotation = 0.0f; - // GLfloat delta = 0.05; - bool boolean = true; - bool b2 = true; - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { - testEllipsoid->setIsOutlined(b2); - testEllipsoid2->setIsOutlined(b2); - b2 = !b2; - }); - - // testEllipsoid->setXRadius(150); - // testEllipsoid->setYRadius(150); - // testEllipsoid->setZRadius(150); - // testEllipsoid->changeXRadiusBy(140); - // testEllipsoid->changeYRadiusBy(140); - // testEllipsoid->changeZRadiusBy(140); - while (can.isOpen()) { - can.sleep(); - // testEllipsoid->setCenterX(sin(rotation)); - // testEllipsoid->setCenterY(cos(rotation)); - // testEllipsoid->setCenterZ(sin(rotation)); - // testEllipsoid->setYaw(rotation*45); - testEllipsoid->setPitch(rotation*45); - testEllipsoid2->setPitch(rotation*45); - // if(boolean) - // testEllipsoid->setRoll(rotation*45); - // testEllipsoid->setXRadius(cos(rotation) * 100 +101); - // testEllipsoid->setYRadius(sin(rotation) * 100 +201); - // testEllipsoid->setZRadius(sin(rotation) * 100 +301); - // if(testEllipsoid->getXRadius() >= 200) { - // delta = -5; - // } - // if(testEllipsoid->getXRadius() <= 5) { - // delta = 5; - // } - // testEllipsoid->changeXRadiusBy(delta); - - // if(testEllipsoid->getYRadius() >= 500) { - // delta = -5; - // } - // if(testEllipsoid->getYRadius() <= 300) { - // delta = 5; - // } - // testEllipsoid->changeYRadiusBy(delta); - - // if(testEllipsoid->getZRadius() >= 300) { - // delta = -5; - // } - // if(testEllipsoid->getZRadius() <= 100) { - // delta = 5; - // } - // testEllipsoid->changeZRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testEllipsoid->setColor(RED); - } else { - testEllipsoid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testEllipsoid; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid"); - c.setBackgroundColor(BLACK); - c.run(ellipsoidFunction); -} \ No newline at end of file diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile deleted file mode 100644 index 2b2ce5104..000000000 --- a/src/tests/testEllipsoid/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testEllipsoid - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testEllipsoid - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testEllipsoid/testEllipsoid.cpp b/src/tests/testEllipsoid/testEllipsoid.cpp deleted file mode 100644 index 69d279ebb..000000000 --- a/src/tests/testEllipsoid/testEllipsoid.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * testEllipsoid.cpp - * - * Usage: ./testEllipsoid - */ - -#include -#include - -using namespace tsgl; - -void ellipsoidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); - // testEllipsoid->setIsFilled(false); - Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); - testEllipsoid2->setOutlineColor(BLUE); - - // printf("%f\n", testEllipsoid->getAlpha()); - // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testEllipsoid->getAlpha()); - // testEllipsoid->setColor(colors); - // printf("%f\n", testEllipsoid->getAlpha()); - can.add(testEllipsoid); - can.add(testEllipsoid2); - float rotation = 0.0f; - // GLfloat delta = 0.05; - bool boolean = true; - bool b2 = true; - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { - testEllipsoid->setIsOutlined(b2); - testEllipsoid2->setIsOutlined(b2); - b2 = !b2; - }); - - // testEllipsoid->setXRadius(150); - // testEllipsoid->setYRadius(150); - // testEllipsoid->setZRadius(150); - // testEllipsoid->changeXRadiusBy(140); - // testEllipsoid->changeYRadiusBy(140); - // testEllipsoid->changeZRadiusBy(140); - while (can.isOpen()) { - can.sleep(); - // testEllipsoid->setCenterX(sin(rotation)); - // testEllipsoid->setCenterY(cos(rotation)); - // testEllipsoid->setCenterZ(sin(rotation)); - // testEllipsoid->setYaw(rotation*45); - testEllipsoid->setPitch(rotation*45); - testEllipsoid2->setPitch(rotation*45); - // if(boolean) - // testEllipsoid->setRoll(rotation*45); - // testEllipsoid->setXRadius(cos(rotation) * 100 +101); - // testEllipsoid->setYRadius(sin(rotation) * 100 +201); - // testEllipsoid->setZRadius(sin(rotation) * 100 +301); - // if(testEllipsoid->getXRadius() >= 200) { - // delta = -5; - // } - // if(testEllipsoid->getXRadius() <= 5) { - // delta = 5; - // } - // testEllipsoid->changeXRadiusBy(delta); - - // if(testEllipsoid->getYRadius() >= 500) { - // delta = -5; - // } - // if(testEllipsoid->getYRadius() <= 300) { - // delta = 5; - // } - // testEllipsoid->changeYRadiusBy(delta); - - // if(testEllipsoid->getZRadius() >= 300) { - // delta = -5; - // } - // if(testEllipsoid->getZRadius() <= 100) { - // delta = 5; - // } - // testEllipsoid->changeZRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testEllipsoid->setColor(RED); - } else { - testEllipsoid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testEllipsoid; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid", BLACK); - c.run(ellipsoidFunction); -} \ No newline at end of file diff --git a/src/tests/testFireworks.cpp b/src/tests/testFireworks.cpp deleted file mode 100644 index 7de3a96f1..000000000 --- a/src/tests/testFireworks.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * testFireworks.cpp - * - * Usage: ./testFireworks - */ - -#include -#include "Fireworks/Arc.h" - -using namespace tsgl; - -/*! - * \brief Creates a bunch of fireworks. - * \details Creates a bunch of Arcs, which explode into new arcs - * \param can Canvas reference to which the fireworks will be drawn. - * \param threads Number of threads to use to draw the fireworks. - * \param numFireworks Number of fireworks to draw. - * \param speed How fast the fireworks move. - */ -void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { - Arc** arcs = new Arc*[numFireworks]; - for (int i = 0; i < numFireworks; i++) { - arcs[i] = new Arc(can); - } - ColorFloat col = can.getBackgroundColor(); - col.A = 0.04f; - const int CWW = can.getWindowWidth(), CWH = can.getWindowHeight(); - #pragma omp parallel num_threads(threads) - { - while(can.isOpen()) { - can.sleep(); - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - for (int n = 0; n < speed; ++n) { - for (int i = tid; i < numFireworks; i += nthreads) - arcs[i]->step(); - if (tid == 0) - can.drawRectangle(0,0,CWW,CWH,col); - #pragma omp barrier - } - } - } - for (int i = 0; i < numFireworks; i++) { - delete arcs[i]; - } - delete [] arcs; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - int f = (argc > 4) ? atoi(argv[4]) : 50; - int s = (argc > 5) ? atoi(argv[5]) : 10; - Canvas c(-1, -1, w, h, "Fireworks!"); - c.setBackgroundColor(BLACK); - c.run(fireworkFunction,t,f,s); -} diff --git a/src/tests/testForestFire.cpp b/src/tests/testForestFire.cpp deleted file mode 100644 index 60a43ae24..000000000 --- a/src/tests/testForestFire.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * testForestFire.cpp - * - * Usage: ./testForestFire - */ - -#include - -using namespace tsgl; - -float randfloat(int divisor = 10000) { - return (rand() % divisor) / (float) divisor; -} - -/*! - * \brief Pseudo-simulates a forest fire using a lot of probability and randomness. - * \details - * - Store the Canvas's dimensions for ease of use. - * - Set the fire's life, strength, and maximum spread distance to some predetermined numbers. - * - Seed the random number generator. - * - Allocate arrays for storing each pixel's onFire status and flammability. - * - For each pixel: - * - Get its distance from the center of the Canvas. - * - Set its flammability and color based upon a semi-arbitrary single-line function. - * . - * - Draw 32 random square "lakes" with very low flammabilities onto the Canvas. - * - Declare a mini-firePoint struct with coordinates, life, and strength. - * - Make a 3x3 square of fire in the middle of the Canvas, and color the pixels accordingly. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - For each fire point: - * - Pop it from the queue, pushing it back on only if its life > 0. - * - For each cell adjacent to the fire, if it is not on the edge of the screen, not already - * on fire, and the random number generator rolls a number lower than the cell's flammability, - * set that cell on fire. - * . - * . - * - Deallocate the onFire and flammability arrays. - * . - * \param can Reference to the Canvas being drawn to. - */ -void forestFireFunction(Canvas& can) { - const int WINDOW_W = can.getWindowWidth(), // Set the screen sizes - WINDOW_H = can.getWindowHeight(); - const float LIFE = 10, - STRENGTH = 0.03, - MAXDIST = sqrt(WINDOW_W * WINDOW_W + WINDOW_H * WINDOW_H) / 2; - srand(time(NULL)); // Seed the random number generator - bool* onFire = new bool[WINDOW_W * WINDOW_H](); - float* flammability = new float[WINDOW_W * WINDOW_H](); - //Setting each pixel's flammablity - for (int i = 0; i < WINDOW_W; i++) { // For each individual point - for (int j = 0; j < WINDOW_H; j++) { - float xi = std::abs(WINDOW_W / 2 - i); - float yi = std::abs(WINDOW_H / 2 - j); - float tdist = (MAXDIST - sqrt(xi * xi + yi * yi)) / MAXDIST; - float f = 0.01 + (i * j % 100) / 100.0 * randfloat(100) / 2 * tdist; - flammability[i * WINDOW_H + j] = f; - can.drawPoint(i, j, ColorFloat(0.0f, f, 0.0f, 1.0f)); - } - } - //"Lakes" - for (int reps = 0; reps < 32; reps++) { - int x = rand() % WINDOW_W; - int y = rand() % WINDOW_H; - int w = rand() % (WINDOW_W - x); - int h = rand() % (WINDOW_H - y); - if (w > 32) w = 32; - if (h > 32) h = 32; - for (int i = 0; i < w; i++) { - for (int j = 0; j < h; j++) { - flammability[(x + i) * WINDOW_H + (y + j)] = 0.01; - can.drawPoint(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); - } - } - } - struct firePoint { - int x; - int y; - float life; - float strength; - }; - std::queue fires; - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - firePoint fire = { WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, LIFE, STRENGTH }; - fires.push(fire); - can.drawPoint(WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); - } - } - Rectangle *rec = new Rectangle(10,10,10,10,BLUE); - can.add(rec); - while (can.isOpen()) { - can.sleep(); - int l = fires.size(); - for (int i = 0; i < l; i++) { - firePoint f = fires.front(); - fires.pop(); - if (--f.life > 0) fires.push(f); - int myCell = f.x * WINDOW_H + f.y; - if (f.x > 0 && !onFire[myCell - WINDOW_H] && randfloat() < flammability[myCell - WINDOW_H]) { - firePoint fire = { f.x - 1, f.y, LIFE, f.strength }; - fires.push(fire); - onFire[myCell - WINDOW_H] = true; - can.drawPoint(f.x - 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); - } - if (f.x < WINDOW_W - 1 && !onFire[myCell + WINDOW_H] - && randfloat() < flammability[myCell + WINDOW_H]) { - firePoint fire = { f.x + 1, f.y, LIFE, f.strength }; - fires.push(fire); - onFire[myCell + WINDOW_H] = true; - can.drawPoint(f.x + 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); - } - if (f.y > 0 && !onFire[myCell - 1] && randfloat() < flammability[myCell - 1]) { - firePoint fire = { f.x, f.y - 1, LIFE, f.strength }; - fires.push(fire); - onFire[myCell - 1] = true; - can.drawPoint(f.x, f.y - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); - } - if (f.y < WINDOW_H && !onFire[myCell + 1] && randfloat() < flammability[myCell + 1]) { - firePoint fire = { f.x, f.y + 1, LIFE, f.strength }; - fires.push(fire); - onFire[myCell + 1] = true; - can.drawPoint(f.x, f.y + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); - } - } - } - delete rec; - delete[] onFire; - delete[] flammability; -} - -//Takes width and height as command line arguments -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid - w = 1200; - h = 900; //If not, set the width and height to a default value - } - Canvas c(-1, -1, w, h, "Forest Fire"); - c.run(forestFireFunction); -} diff --git a/src/tests/testFunction.cpp b/src/tests/testFunction.cpp deleted file mode 100644 index 342306715..000000000 --- a/src/tests/testFunction.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * testFunction.cpp - * - * Usage: ./testFunction - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws the outputs of some functions using CartesianCanvas. - * \details - * - Draw axes through the origin, with spacing 1.0 between x ticks and 5.0 between y ticks. - * - Initialize a CosineFunction, and draw it using the currently rendered area of the CartesianCanvas. - * - Initialize a PowerFunction with argument 2 (square), and draw it using - * the currently rendered area of the CartesianCanvas. - * - Declare a new function that computes some bizarre polynomial. - * - Initialize the new function, and draw it using the currently rendered area of the CartesianCanvas. - * . - * \param can Reference to the CartesianCanvas being drawn to. - */ -void functionFunction(CartesianCanvas& can) { - can.drawAxes(0, 0, 1, 5); - - CosineFunction function1; - can.drawFunction(function1,FRAME/5); - - PowerFunction function2(2); - can.drawFunction(function2,FRAME/5); - - class myFunction : public Function { - public: - long double valueAt(long double x) const { - return 5 * pow(x, 4) + 2 * pow(x, 3) + x + 15; - } - }; - - myFunction function3; - can.drawFunction(function3,FRAME/5); -} - -//Takes command line arguments for the window width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 1000; //If not, set the width and height to a default value - Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting"); - c.setBackgroundColor(WHITE); - c.run(functionFunction); -} diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile deleted file mode 100644 index 94991da39..000000000 --- a/src/tests/testFunction/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testFunction - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testFunction - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testFunction/testFunction.cpp b/src/tests/testFunction/testFunction.cpp deleted file mode 100644 index a3511f8e6..000000000 --- a/src/tests/testFunction/testFunction.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * testFunction.cpp - * - * Usage: ./testFunction - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws the outputs of some functions using CartesianCanvas. - * \details - * - Draw axes through the origin, with spacing 1.0 between x ticks and 5.0 between y ticks. - * - Initialize a CosineFunction, and draw it using the currently rendered area of the CartesianCanvas. - * - Initialize a PowerFunction with argument 2 (square), and draw it using - * the currently rendered area of the CartesianCanvas. - * - Declare a new function that computes some bizarre polynomial. - * - Initialize the new function, and draw it using the currently rendered area of the CartesianCanvas. - * . - * \param can Reference to the CartesianCanvas being drawn to. - */ -void functionFunction(CartesianCanvas& can) { - can.drawAxes(0, 0, 1, 5); - - CosineFunction function1; - can.drawFunction(function1,FRAME/5); - - PowerFunction function2(2); - can.drawFunction(function2,FRAME/5); - - class myFunction : public Function { - public: - long double valueAt(long double x) const { - return 5 * pow(x, 4) + 2 * pow(x, 3) + x + 15; - } - }; - - myFunction function3; - can.drawFunction(function3,FRAME/5); -} - -//Takes command line arguments for the window width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 1000; //If not, set the width and height to a default value - Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting", WHITE); - c.run(functionFunction); -} diff --git a/src/tests/testGetPixels.cpp b/src/tests/testGetPixels.cpp deleted file mode 100644 index a3b2e55e9..000000000 --- a/src/tests/testGetPixels.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * testGetPixels.cpp - * - * Usage: ./testGetPixels - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Grabs the pixels from an image on the Canvas and plays with them. - * \details - * - Set a predetermined number of threads and store it in: \b THREADS. - * - Store the Canvas' dimensions for easy use. - * - Draw an image on the initially blank Canvas, stretched to fill it. - * - Set up a parallel OMP block with \b THREADS threads. - * - Set up the internal timer of the Canvas to expire every 1/100th of a second. - * - Determine a block size for each thread based on the Canvas' height and the number - * of spawned threads. - * - Determine a starting row for each thread based on \b blocksize and the thread's id. - * - While the Canvas is open: - * - For each row: - * - For each column: - * - Over each old pixel, draw a new pixel with each of the RGB components incremented - * and wrapped. - * . - * . - * - Sleep until the Canvas is ready to draw again. - * - Print the time between sleeps of the Canvas' internal timer. - * . - * . - * - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void getPixelsFunction(Canvas& can, int threads) { - unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); - can.drawImage("../assets/pics/test.png", 0, 0, width, height); - can.sleepFor(0.5f); - #pragma omp parallel num_threads(threads) - { - unsigned blocksize = (double)height / omp_get_num_threads(); - unsigned row = blocksize * omp_get_thread_num(); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (unsigned y = row; y < row + blocksize; y++) { - for (unsigned x = 0; x < width; x++) { - ColorInt c = can.getPoint(x,y); - can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); - } - } - } - } -} - -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - Canvas c(-1, -1, 800, 600, "Pixel Shifter", .01); - c.run(getPixelsFunction,t); -} diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile deleted file mode 100644 index 072c3514f..000000000 --- a/src/tests/testGetPixels/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testAlphaRectangle - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testAlphaRectangle - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testGetPixels/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp deleted file mode 100644 index a3b2e55e9..000000000 --- a/src/tests/testGetPixels/testGetPixels.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * testGetPixels.cpp - * - * Usage: ./testGetPixels - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Grabs the pixels from an image on the Canvas and plays with them. - * \details - * - Set a predetermined number of threads and store it in: \b THREADS. - * - Store the Canvas' dimensions for easy use. - * - Draw an image on the initially blank Canvas, stretched to fill it. - * - Set up a parallel OMP block with \b THREADS threads. - * - Set up the internal timer of the Canvas to expire every 1/100th of a second. - * - Determine a block size for each thread based on the Canvas' height and the number - * of spawned threads. - * - Determine a starting row for each thread based on \b blocksize and the thread's id. - * - While the Canvas is open: - * - For each row: - * - For each column: - * - Over each old pixel, draw a new pixel with each of the RGB components incremented - * and wrapped. - * . - * . - * - Sleep until the Canvas is ready to draw again. - * - Print the time between sleeps of the Canvas' internal timer. - * . - * . - * - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void getPixelsFunction(Canvas& can, int threads) { - unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); - can.drawImage("../assets/pics/test.png", 0, 0, width, height); - can.sleepFor(0.5f); - #pragma omp parallel num_threads(threads) - { - unsigned blocksize = (double)height / omp_get_num_threads(); - unsigned row = blocksize * omp_get_thread_num(); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (unsigned y = row; y < row + blocksize; y++) { - for (unsigned x = 0; x < width; x++) { - ColorInt c = can.getPoint(x,y); - can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); - } - } - } - } -} - -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - Canvas c(-1, -1, 800, 600, "Pixel Shifter", .01); - c.run(getPixelsFunction,t); -} diff --git a/src/tests/testGradientWheel.cpp b/src/tests/testGradientWheel.cpp deleted file mode 100644 index 8eddde4da..000000000 --- a/src/tests/testGradientWheel.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * testGradientWheel.cpp - * - * Usage: ./testGradientWheel - */ - -#include -#include -#include "Util.h" - -using namespace tsgl; - -/*! - * \brief Draws a gradient color wheel using OMP with multiple threads per processor and TSGL's colored polygons. - * \details Same principle as colorWheelFunction(). Since colored polygons take arrays as parameters - * to allow for arbitrary-length polygons, there are some key differences: - * - Colors, x and y coordinates are declared within the \#pragma omp block so they can be - * declared as an array. - * - At the end, drawColoredPolygon() is called on a polygon with 3 vertices, with arrays for the - * x coordinates, y coordinates, and color. - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void gradientWheelFunction(Canvas& can, int threads) { - const int CW = can.getWindowWidth() / 2, // Half the window's width - CH = can.getWindowHeight() / 2; // Half the window's height - const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel - ARCLENGTH = 2 * PI / NUM_COLORS; // Gap between wedges - #pragma omp parallel num_threads(threads) - { - threads = omp_get_num_threads(); // Actual number of threads - int tid = omp_get_thread_num(); // Thread ID - int delta = (NUM_COLORS / threads); // Distance between threads to compute - float shading = 1 - (float)tid / threads; // Shading based on thread ID - ColorFloat color[3]; // RGB color to build - int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices - while (can.isOpen()) { - can.sleep(); - start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment - end = ((start+delta) % NUM_COLORS); - color[0] = ColorHSV(start / (float)NUM_COLORS * 6, 0.0f, shading, 1.0f); - color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - - xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen - xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle - yy[1] = CH + RADIUS * cos(ARCLENGTH * start); - xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); - yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); - - can.drawTriangleStrip(3, xx, yy, color, true); - } - } -} - -//Takes command line arguments for the width and height of the window -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid - w = h = 960; // If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : 256; - Canvas c(-1, -1, w, h, "Gradient Color Wheel"); - c.setBackgroundColor(BLACK); - c.run(gradientWheelFunction,t); -} diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile deleted file mode 100644 index cdc77e86f..000000000 --- a/src/tests/testGradientWheel/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testGradientWheel - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testGradientWheel - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testGradientWheel/testGradientWheel.cpp b/src/tests/testGradientWheel/testGradientWheel.cpp deleted file mode 100644 index 9e590ab01..000000000 --- a/src/tests/testGradientWheel/testGradientWheel.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * testGradientWheel.cpp - * - * Usage: ./testGradientWheel - */ - -#include -#include -#include "Util.h" - -using namespace tsgl; - -/*! - * \brief Draws a gradient color wheel using OMP with multiple threads per processor and TSGL's colored polygons. - * \details Same principle as colorWheelFunction(). Since colored polygons take arrays as parameters - * to allow for arbitrary-length polygons, there are some key differences: - * - Colors, x and y coordinates are declared within the \#pragma omp block so they can be - * declared as an array. - * - At the end, drawColoredPolygon() is called on a polygon with 3 vertices, with arrays for the - * x coordinates, y coordinates, and color. - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void gradientWheelFunction(Canvas& can, int threads) { - const int CW = can.getWindowWidth() / 2, // Half the window's width - CH = can.getWindowHeight() / 2; // Half the window's height - const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel - ARCLENGTH = 2 * PI / NUM_COLORS; // Gap between wedges - #pragma omp parallel num_threads(threads) - { - threads = omp_get_num_threads(); // Actual number of threads - int tid = omp_get_thread_num(); // Thread ID - int delta = (NUM_COLORS / threads); // Distance between threads to compute - float shading = 1 - (float)tid / threads; // Shading based on thread ID - ColorFloat color[3]; // RGB color to build - int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices - while (can.isOpen()) { - can.sleep(); - start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment - end = ((start+delta) % NUM_COLORS); - color[0] = ColorHSV(start / (float)NUM_COLORS * 6, 0.0f, shading, 1.0f); - color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - - xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen - xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle - yy[1] = CH + RADIUS * cos(ARCLENGTH * start); - xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); - yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); - - can.drawTriangleStrip(3, xx, yy, color, true); - } - } -} - -//Takes command line arguments for the width and height of the window -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid - w = h = 960; // If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : 256; - Canvas c(-1, -1, w, h, "Gradient Color Wheel", BLACK); - c.run(gradientWheelFunction,t); -} diff --git a/src/tests/testGraydient.cpp b/src/tests/testGraydient.cpp deleted file mode 100644 index 4d3a2af77..000000000 --- a/src/tests/testGraydient.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * testGraydient.cpp - * - * Usage: ./testGraydient - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command-line argument for the - * number of threads to use. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed as a command-line argument. - * - The outer for loop is set up in a striping pattern, and the inner for loop runs from 0 to the Canvas height. - * - If the Canvas is not open anymore, break out of the function. - * - The color ( \b color ) is set to a shade of gray based on its distance from the top left of the canvas. - * - The point is drawn to the Canvas. - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void graydientFunction(Canvas& can, int threads) { - #pragma omp parallel num_threads(threads) - { - for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { - if (!can.isOpen()) break; - for (int j = 0; j < can.getWindowHeight(); j++) { - int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); - can.drawPoint(i, j, ColorInt(color, color, color)); - } - can.sleep(); - } - } -} - -//Takes in the window width and height as command-line arguments for the Canvas -//as well as for the number of threads to use -//( see http://www.cplusplus.com/articles/DEN36Up4/ ) -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid - w = h = 960; // If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Black-white Gradient"); - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - c.run(graydientFunction,t); -} diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile deleted file mode 100644 index 72b5e97cf..000000000 --- a/src/tests/testGraydient/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testGraydient - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testGraydient - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testGraydient/testGraydient.cpp b/src/tests/testGraydient/testGraydient.cpp deleted file mode 100644 index 4d3a2af77..000000000 --- a/src/tests/testGraydient/testGraydient.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * testGraydient.cpp - * - * Usage: ./testGraydient - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command-line argument for the - * number of threads to use. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed as a command-line argument. - * - The outer for loop is set up in a striping pattern, and the inner for loop runs from 0 to the Canvas height. - * - If the Canvas is not open anymore, break out of the function. - * - The color ( \b color ) is set to a shade of gray based on its distance from the top left of the canvas. - * - The point is drawn to the Canvas. - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void graydientFunction(Canvas& can, int threads) { - #pragma omp parallel num_threads(threads) - { - for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { - if (!can.isOpen()) break; - for (int j = 0; j < can.getWindowHeight(); j++) { - int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); - can.drawPoint(i, j, ColorInt(color, color, color)); - } - can.sleep(); - } - } -} - -//Takes in the window width and height as command-line arguments for the Canvas -//as well as for the number of threads to use -//( see http://www.cplusplus.com/articles/DEN36Up4/ ) -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid - w = h = 960; // If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Black-white Gradient"); - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - c.run(graydientFunction,t); -} diff --git a/src/tests/testGreyscale.cpp b/src/tests/testGreyscale.cpp deleted file mode 100644 index f62b7cfbc..000000000 --- a/src/tests/testGreyscale.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * testGreyScale.cpp - * - * Usage: ./testGreyScale - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Grabs the pixels from an image on the Canvas and converts them to grayscale. - * \details - * - Predetermine the number of threads and line thickness and store them in variables. - * - Check if the passed parameter for the number of threads is valid: - * - If its a negative value, change the sign to be positive. - * - If its greater than 30, assign 30 to the number of threads to use. - * - Else, assign the passed parameter to the number of threads to use. - * . - * - Set up the internal timer of the Canvas to expire every ( \b FRAME * 2 ) seconds. - * - Store the Canvas' dimensions for ease of use. - * - Stretch a fancy image over the Canvas. - * - Tell the internal timer to manually sleep for a quarter of a second (to assure the draw buffer is filled). - * - Initialize a pointer to the Canvas' screen buffer. - * - Set up a parallel OMP block with \b threads threads. - * - Get the actual number of spawned threads and store it in: \b nthreads. - * - Compute the \b blocksize based on the Canvas height and \b nthreads. - * - Compute the current thread's row based on \b blocksize and the thread's id. - * - Generate a nice color based on the thread's id. - * - Set a grayscale color variable to 0. - * - For each row: - * - For each column: - * - Get the pixel color of a point of the Canvas. - * - Set a gray color variable to the average of the RGB components. - * - Draw the grayed point over the old point, and increment the index by one pixel. - * . - * - Break if the Canvas was closed. - * - Sleep until the Canvas is ready to render again. - * . - * - Once a thread is finished grayscaling, draw a box around its rendered area using - * the predetermined high contrast color. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void greyScaleFunction(Canvas& can, int numberOfThreads) { - int threads = numberOfThreads; - clamp(threads,1,30); - const unsigned thickness = 3; - const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); - can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); - can.sleepFor(0.25f); - #pragma omp parallel num_threads(threads) - { - int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); - for (unsigned int y = row; y < row + blocksize; y++) { - for (unsigned int x = 0; x < WW; x++) { - ColorInt pixelColor = can.getPoint(x, y); - int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; - can.drawPoint(x, y, ColorInt(gray, gray, gray)); - } - if (! can.isOpen()) break; - can.sleep(); - } - for (unsigned int i = 0; i < thickness; i++) { - can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); - // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); - } - } -} - -//Takes command line arguments for the width and height of the window -//as well as for the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Image Greyscaling"); - int numberOfThreads = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads - c.run(greyScaleFunction,numberOfThreads); -} diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile deleted file mode 100644 index 6ef2c993b..000000000 --- a/src/tests/testGreyscale/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testGreyscale - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testGreyscale - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testGreyscale/testGreyscale.cpp b/src/tests/testGreyscale/testGreyscale.cpp deleted file mode 100644 index f62b7cfbc..000000000 --- a/src/tests/testGreyscale/testGreyscale.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * testGreyScale.cpp - * - * Usage: ./testGreyScale - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Grabs the pixels from an image on the Canvas and converts them to grayscale. - * \details - * - Predetermine the number of threads and line thickness and store them in variables. - * - Check if the passed parameter for the number of threads is valid: - * - If its a negative value, change the sign to be positive. - * - If its greater than 30, assign 30 to the number of threads to use. - * - Else, assign the passed parameter to the number of threads to use. - * . - * - Set up the internal timer of the Canvas to expire every ( \b FRAME * 2 ) seconds. - * - Store the Canvas' dimensions for ease of use. - * - Stretch a fancy image over the Canvas. - * - Tell the internal timer to manually sleep for a quarter of a second (to assure the draw buffer is filled). - * - Initialize a pointer to the Canvas' screen buffer. - * - Set up a parallel OMP block with \b threads threads. - * - Get the actual number of spawned threads and store it in: \b nthreads. - * - Compute the \b blocksize based on the Canvas height and \b nthreads. - * - Compute the current thread's row based on \b blocksize and the thread's id. - * - Generate a nice color based on the thread's id. - * - Set a grayscale color variable to 0. - * - For each row: - * - For each column: - * - Get the pixel color of a point of the Canvas. - * - Set a gray color variable to the average of the RGB components. - * - Draw the grayed point over the old point, and increment the index by one pixel. - * . - * - Break if the Canvas was closed. - * - Sleep until the Canvas is ready to render again. - * . - * - Once a thread is finished grayscaling, draw a box around its rendered area using - * the predetermined high contrast color. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void greyScaleFunction(Canvas& can, int numberOfThreads) { - int threads = numberOfThreads; - clamp(threads,1,30); - const unsigned thickness = 3; - const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); - can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); - can.sleepFor(0.25f); - #pragma omp parallel num_threads(threads) - { - int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); - for (unsigned int y = row; y < row + blocksize; y++) { - for (unsigned int x = 0; x < WW; x++) { - ColorInt pixelColor = can.getPoint(x, y); - int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; - can.drawPoint(x, y, ColorInt(gray, gray, gray)); - } - if (! can.isOpen()) break; - can.sleep(); - } - for (unsigned int i = 0; i < thickness; i++) { - can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); - // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); - } - } -} - -//Takes command line arguments for the width and height of the window -//as well as for the number of threads to use -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "Image Greyscaling"); - int numberOfThreads = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads - c.run(greyScaleFunction,numberOfThreads); -} diff --git a/src/tests/testHighData.cpp b/src/tests/testHighData.cpp deleted file mode 100644 index 43ce27f05..000000000 --- a/src/tests/testHighData.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * testHighData.cpp - * - * Usage: ./testHighData - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a large number of pixels on a Canvas at a high framerate. - * \details Very basic stress test for the Canvas' drawPoint() function. - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - Set Local variables to track the internal timer's repetitions, and the Canvas' dimensions. - * - While the Canvas is open: - * - Set \b reps to the timer's current number of repetitions. - * - Compute the blue component of the current color based on reps. - * - Attempt to draw every pixel with the current 1.0,1.0,blue. - * - Sleep the timer until the Canvas is ready to draw again. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void highData(Canvas& can, unsigned threads) { - const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values - const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); - #pragma omp parallel num_threads(threads) - { - float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); - int offset = (MAX_COLOR*tid)/nthreads; - unsigned bstart = tid*(width/nthreads); - unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; - ColorHSV tcol= Colors::highContrastColor(tid); - while (can.isOpen()) { - tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); - for (unsigned i = bstart; i <= bend; i++) - for (unsigned int j = 0; j < height; j++) - can.drawPoint(i, j, tcol); - can.handleIO(); - } - } -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = 1.2*Canvas::getDisplayHeight(), h = 0.75*w; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Pixel Drawing Load Test"); - c.run(highData,t); -} diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile deleted file mode 100644 index cc93c6633..000000000 --- a/src/tests/testHighData/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testHighData - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testHighData - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testHighData/testHighData.cpp b/src/tests/testHighData/testHighData.cpp deleted file mode 100644 index 43ce27f05..000000000 --- a/src/tests/testHighData/testHighData.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * testHighData.cpp - * - * Usage: ./testHighData - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a large number of pixels on a Canvas at a high framerate. - * \details Very basic stress test for the Canvas' drawPoint() function. - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - Set Local variables to track the internal timer's repetitions, and the Canvas' dimensions. - * - While the Canvas is open: - * - Set \b reps to the timer's current number of repetitions. - * - Compute the blue component of the current color based on reps. - * - Attempt to draw every pixel with the current 1.0,1.0,blue. - * - Sleep the timer until the Canvas is ready to draw again. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void highData(Canvas& can, unsigned threads) { - const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values - const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); - #pragma omp parallel num_threads(threads) - { - float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); - int offset = (MAX_COLOR*tid)/nthreads; - unsigned bstart = tid*(width/nthreads); - unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; - ColorHSV tcol= Colors::highContrastColor(tid); - while (can.isOpen()) { - tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); - for (unsigned i = bstart; i <= bend; i++) - for (unsigned int j = 0; j < height; j++) - can.drawPoint(i, j, tcol); - can.handleIO(); - } - } -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = 1.2*Canvas::getDisplayHeight(), h = 0.75*w; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Pixel Drawing Load Test"); - c.run(highData,t); -} diff --git a/src/tests/testImage.cpp b/src/tests/testImage.cpp deleted file mode 100644 index e38a07aa4..000000000 --- a/src/tests/testImage.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * testImage.cpp - * - * Usage: ./testImage - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a Canvas. - * \details Very basic test function showcasing image drawing capabilities. - * - The first 6 images are drawn opaque. - * - The 7th image is drawn across the entire Canvas with alpha transparency. - * . - * \param can Reference to the Canvas being drawn to. - */ -void imageFunction(Canvas& can) { - int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; - // Square * s = new Square(5,0,0,50,0,0,0,RED); - // can.add(s); - - // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); - // can.add(p); - - // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); - // can.add(image); - - Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); - can.add(image); - Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); - can.add(image2); - Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); - can.add(image3); - Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); - can.add(image4); - Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); - can.add(image5); - Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); - can.add(image6); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { - image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); - }); - - // image->setHeight((GLfloat)image->getPixelHeight()); - // image->setWidth((GLfloat)image->getPixelWidth()); - - float floatVal = 0.0f; - GLfloat delta = 5; - bool ss = false; - while (can.isOpen()) { - can.sleep(); - image->setAlpha((sin(floatVal) + 1) / 2); - // image->setCenterX(sin(floatVal/90) * 100); - // image->setCenterY(sin(floatVal/90) * 100); - // image->setCenterZ(sin(floatVal/90) * 100); - // image->setYaw(floatVal); - image->setPitch(floatVal * 100); - // image->setRoll(floatVal); - // image->setWidth(sin(floatVal/90) * 100 + 400); - // image->setHeight(sin(floatVal/90) * 100 + 400); - // if (image->getWidth() > 500 || image->getWidth() < 300) { - // delta *= -1; - // } - // image->changeWidthBy(delta); - // if (image->getHeight() > 500 || image->getHeight() < 300) { - // delta *= -1; - // } - // image->changeHeightBy(delta); - // printf("%d\n", can.getFrameNumber()); - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); - // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); - floatVal += 0.01; - } - - // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay - - delete image; - delete image2; - delete image3; - delete image4; - delete image5; - delete image6; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; - } - Canvas c(-1, -1, w, h ,"Images"); - c.setBackgroundColor(WHITE); - c.run(imageFunction); -} diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile deleted file mode 100644 index 9a4b4e9de..000000000 --- a/src/tests/testImage/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testImage - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testImage - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testImage/testImage.cpp b/src/tests/testImage/testImage.cpp deleted file mode 100644 index 3de6187c7..000000000 --- a/src/tests/testImage/testImage.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * testImage.cpp - * - * Usage: ./testImage - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a Canvas. - * \details Very basic test function showcasing image drawing capabilities. - * - The first 6 images are drawn opaque. - * - The 7th image is drawn across the entire Canvas with alpha transparency. - * . - * \param can Reference to the Canvas being drawn to. - */ -void imageFunction(Canvas& can) { - int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; - // Square * s = new Square(5,0,0,50,0,0,0,RED); - // can.add(s); - - // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); - // can.add(p); - - // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); - // can.add(image); - - Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); - can.add(image); - Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); - can.add(image2); - Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); - can.add(image3); - Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); - can.add(image4); - Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); - can.add(image5); - Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); - can.add(image6); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { - image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); - }); - - // image->setHeight((GLfloat)image->getPixelHeight()); - // image->setWidth((GLfloat)image->getPixelWidth()); - - float floatVal = 0.0f; - GLfloat delta = 5; - bool ss = false; - while (can.isOpen()) { - can.sleep(); - image->setAlpha((sin(floatVal) + 1) / 2); - // image->setCenterX(sin(floatVal/90) * 100); - // image->setCenterY(sin(floatVal/90) * 100); - // image->setCenterZ(sin(floatVal/90) * 100); - // image->setYaw(floatVal); - image->setPitch(floatVal * 100); - // image->setRoll(floatVal); - // image->setWidth(sin(floatVal/90) * 100 + 400); - // image->setHeight(sin(floatVal/90) * 100 + 400); - // if (image->getWidth() > 500 || image->getWidth() < 300) { - // delta *= -1; - // } - // image->changeWidthBy(delta); - // if (image->getHeight() > 500 || image->getHeight() < 300) { - // delta *= -1; - // } - // image->changeHeightBy(delta); - // printf("%d\n", can.getFrameNumber()); - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); - // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); - floatVal += 0.01; - } - - // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay - - delete image; - delete image2; - delete image3; - delete image4; - delete image5; - delete image6; -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; - } - Canvas c(-1, -1, w, h ,"Images", WHITE); - c.run(imageFunction); -} diff --git a/src/tests/testImageCart.cpp b/src/tests/testImageCart.cpp deleted file mode 100644 index a7e4aead0..000000000 --- a/src/tests/testImageCart.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * testImageCart.cpp - * - * Usage: ./testImageCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a CartesianCanvas. - * \details Same as imageFunction, but on a CartesianCanvas. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - */ -void imageCartFunction(Cart& can) { - can.drawImage("../assets/pics/test.png", 0, 3, 2, 1.5); - can.drawImage("../assets/pics/ship.bmp", 2, 3, 2, 1.5); // possibly lost - can.drawImage("../assets/pics/shiprgb.bmp", 4, 3, 2, 1.5); // definitely lost - can.drawImage("../assets/pics/sky_main.jpg", 0, 1.5, 2, 1.5); - can.drawImage("../assets/pics/cow.jpg", 2, 1.5, 2, 1.5); - can.drawImage("../assets/pics/colorfulKeyboard.jpg", 4, 1.5, 2, 1.5); - - can.drawImage("../assets/pics/colorful-cars-circle.jpg", 1, 3, 4, 3, 0.25f); //Overlay -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.5 * w; - } - Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); - c.run(imageCartFunction); -} diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile deleted file mode 100644 index eddf3e4c3..000000000 --- a/src/tests/testImageCart/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testImageCart - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testImageCart - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testImageCart/testImageCart.cpp b/src/tests/testImageCart/testImageCart.cpp deleted file mode 100644 index a7e4aead0..000000000 --- a/src/tests/testImageCart/testImageCart.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * testImageCart.cpp - * - * Usage: ./testImageCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws various images on a CartesianCanvas. - * \details Same as imageFunction, but on a CartesianCanvas. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - */ -void imageCartFunction(Cart& can) { - can.drawImage("../assets/pics/test.png", 0, 3, 2, 1.5); - can.drawImage("../assets/pics/ship.bmp", 2, 3, 2, 1.5); // possibly lost - can.drawImage("../assets/pics/shiprgb.bmp", 4, 3, 2, 1.5); // definitely lost - can.drawImage("../assets/pics/sky_main.jpg", 0, 1.5, 2, 1.5); - can.drawImage("../assets/pics/cow.jpg", 2, 1.5, 2, 1.5); - can.drawImage("../assets/pics/colorfulKeyboard.jpg", 4, 1.5, 2, 1.5); - - can.drawImage("../assets/pics/colorful-cars-circle.jpg", 1, 3, 4, 3, 0.25f); //Overlay -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; - if(w <= 0 || h <= 0) { //Check width and height validity - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.5 * w; - } - Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); - c.run(imageCartFunction); -} diff --git a/src/tests/testInverter.cpp b/src/tests/testInverter.cpp deleted file mode 100644 index 370b4f62f..000000000 --- a/src/tests/testInverter.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * testInverter.cpp - * - * Usage: ./testInverter - */ - -#include -#include "ImageInverter/ImageInverter.h" - -using namespace tsgl; - -int main(int argc, char* argv[]) { - int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); - ii.run(numThreads); -} diff --git a/src/tests/testInverter/ImageInverter.cpp b/src/tests/testInverter/ImageInverter.cpp deleted file mode 100644 index f559065b1..000000000 --- a/src/tests/testInverter/ImageInverter.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ImageInverter.cpp - */ - -#include "ImageInverter.h" - -ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsigned height) - : myCanvas1(0, 0, width, height, fileName), - myCanvas2(-1, -1, width, height, fileName), - myWidth(width), myHeight(height), myFileName(fileName) -{ - myCanvas1.start(); - myCanvas1.drawImage(fileName, 0, 0, width, height); - // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); - sleep(1); - myCanvas2.start(); -} - -void ImageInverter::run(unsigned numThreads) { - invertImage(numThreads); - stop(); -} - -void ImageInverter::invertImage(unsigned numThreads) { - ColorInt pixelColor; - // #pragma omp parallel for num_threads(numThreads) - const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); - #pragma omp parallel num_threads(numThreads) - { - int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - for (unsigned int x = row; x < row + blocksize; x++) { - for (unsigned int y = 0; y < WW; y++) { - pixelColor = myCanvas1.getPixel(x, y); - int invertedR = 255 - pixelColor.R; - int invertedG = 255 - pixelColor.G; - int invertedB = 255 - pixelColor.B; - myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); - } - myCanvas1.sleep(); - myCanvas2.sleep(); - } - } -} - -void ImageInverter::stop() { - myCanvas2.wait(); - myCanvas1.wait(); -} - -ImageInverter::~ImageInverter() { -// delete myCanvas1; -// delete myCanvas2; -// std::cout << "ImageInverter terminated normally.\n" << std::endl; -} diff --git a/src/tests/testInverter/ImageInverter.h b/src/tests/testInverter/ImageInverter.h deleted file mode 100644 index 6906b31b6..000000000 --- a/src/tests/testInverter/ImageInverter.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ImageInverter.h declares the ImageInverter class. - */ - -#ifndef IMAGEINVERTER_H_ -#define IMAGEINVERTER_H_ - -#include // Canvas, ColorInt, etc. -#include - -#ifdef _WIN32 - #include -#else - #include // sleep() -#endif - -using namespace tsgl; - -class ImageInverter { -private: - Canvas myCanvas1; - Canvas myCanvas2; - int myWidth; - int myHeight; - std::string myFileName; - #ifdef _WIN32 - void sleep(unsigned seconds) { Sleep(seconds * 1000); } - #endif -protected: - - /* invertImage inverts the image using a given number of threads - * @param: numThreads, the number of threads to use - * when inverting the image (default 1). - * Postcondition: myCanvas2 contains an image that is the - * inverse of the image in myCanvas1. - */ - virtual void invertImage(unsigned numThreads = 1); - - /* helper method to keep Canvases up until the user - * clicks their window-frame's close button. - * - * Postcondition: myCanvas1 and myCanvas2 have been closed. - */ - virtual void stop(); - -public: - - /* explicit constructor - * @param fileName, a string. - * @param width, an unsigned. - * @param height, an unsigned. - * Precondition: fileName contains the name of a valid image file - * && width contains the number of columns in that image - * && height contains the number of rows in the image. - * Postcondition: myCanvas1 contains the image from fileName - * && myCanvas2 is ready for drawing its inverse - * && myWidth = width - * && myHeight = height. - */ - ImageInverter(const std::string& fileName, unsigned width, unsigned height); - - /* destructor - * Postcondition: myCanvas1 and myCanvas2 have been closed - * && myCanvas1 and myCanvas2 have been deallocated - * && glfwTerminate() has shut down GLFW - * && a termination message was written to the console. - */ - virtual ~ImageInverter(); - - /* method to coordinate the image inversion - * @param: numThreads, the number of threads to use - * when inverting the image (default 1). - * PostCondition: myCanvas2 contains the inverse - * of the image in myCanvas1. - */ - virtual void run(unsigned numThreads = 1); -}; - -#endif /* IMAGEINVERTER_H_ */ diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile deleted file mode 100644 index 27d4cd03e..000000000 --- a/src/tests/testInverter/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testInverter - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testInverter - -# Object files -ODIR = obj -_OBJ = ImageInverter.o $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testInverter/testInverter.cpp b/src/tests/testInverter/testInverter.cpp deleted file mode 100644 index 370b4f62f..000000000 --- a/src/tests/testInverter/testInverter.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * testInverter.cpp - * - * Usage: ./testInverter - */ - -#include -#include "ImageInverter/ImageInverter.h" - -using namespace tsgl; - -int main(int argc, char* argv[]) { - int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); - ii.run(numThreads); -} diff --git a/src/tests/testLangton.cpp b/src/tests/testLangton.cpp deleted file mode 100644 index f954dcd9f..000000000 --- a/src/tests/testLangton.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * testLangton.cpp - * - * Usage: ./testLangton - */ - -#include -#include - -#include "Langton/AntFarm.h" - -using namespace tsgl; - -/*! - * \brief Simulates 4 Langton's Ants with alpha transparency used for drawing and a couple - * other neat features. - * \details Mostly the same as langtonColonyFunction(), but with a couple key differences: - * - Each ant is drawn with an alpha (transparency) value of 16 (~0.06). - * - There are four LangtonAnts in the AntFarm object (same as langtonColonyFunction() ) *BUT* they have alpha transparency. - * - We set up an additional timer \b pulse to keep track of intervals between clearing the screen. - * - We set up a function \b tempo, which resets the \b pulse timer, sets its interval to the - * time since the last reset, and makes the Canvas clear itself at that interval. - * - We bind the left mouse button and the enter button to the described \b tempo function. - * - We bind the enter key to pause the animation. - * - We bind the space key to clearing the Canvas. - * - After all the ants are moved on a given frame, if the \b pulse timer is expired, we clear the screen. - * . - * \param can Reference to the Canvas being drawn to. - */ -void alphaLangtonFunction(Canvas& can) { - const int IPF = 5000, // Iterations per frame - WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(), // Window height - R = WH / 6; // How far apart to space the ants - bool paused = false; - - AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); - - Timer pulse(28.72 / 60); - double time = pulse.getTime(); - - auto tempo = [&can, &pulse, &time]() { - std::cout << (pulse.getTime() - time) << std::endl; - pulse.reset(pulse.getTime() - time); - time = pulse.getTime(); - }; - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, tempo); - can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&paused]() { - paused = !paused; - }); - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); - }); - - while (can.isOpen()) { - if (!paused) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = 0; i < IPF; i++) - farm.moveAnts(); - if (pulse.pastPeriod()) - can.clearProcedural(); - } - } -} - -/*! - * \brief Simulates Langton's Ant at speeds faster than the Canvas' framerate. - * \details - * - The Canvas' width and height are stored. - * - An AntFarm object is created that will display the LangtonAnt. - * - The number of iterations per frame is set to a large number. - * - While the Canvas is still open: - * - Sleep the internal timer until the next draw cycle. - * - For 0 to the iterations per frame: - * - Move the LangtonAnt inside of the AntFarm object. - * . - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void langtonFunction(Canvas& can) { - const int IPF = 1000, // Iterations per frame - WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(); // Window height - AntFarm farm(WW,WH,4,&can); - farm.setParallel(false); - farm.addAnt(WW / 2,WH / 2,MAX_COLOR,0,0,0); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = 0; i < IPF; i++) { - farm.moveAnts(); - } - } -} - -/*! - * \brief Simulates 4 LangtonAnts at speeds faster than the Canvas' framerate. - * \details Same principle as langtonFunction(). Key differences: - * - A variable \b R holds the distance from the center for each ant. - * - There are four LangtonAnts inside of the AntFarm object. - * - Each ant is tracked separately, with arrays holding each type of variable. - * - The LangtonAnts are shaded this time. - * . - * \param can Reference to the Canvas being drawn to. - */ -void langtonColonyFunction(Canvas& can) { - const int IPF = 5000, // Iterations per frame - WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(), // Window height - R = WH / 6; // How far apart to space the ants - - AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); - farm.setShading(true); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = 0; i < IPF; i++) - farm.moveAnts(); - } -} - -/*! - * \brief Simulates 4 LangtonAnts at speeds faster than the Canvas' framerate, with nicer colors! - * \details Same as langtonColonyFunction(), but with dynamically-colored LangtonAnts. - * \param can Reference to the Canvas being drawn to. - */ -void langtonRainbowFunction(Canvas& can) { - const int IPF = 5000, // Iterations per frame - WW = can.getWindowWidth(), // Window width - WH = can.getWindowHeight(), // Window height - R = WH / 6; // How far apart to space the ants - - AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); - farm.setShading(true); - for (int j = 0; j < 4; j++) - farm.ants[j]->setAlpha(64); - - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int j = 0; j < 4; j++) - farm.ants[j]->changeColor(ColorHSV((can.getFrameNumber() + 3 * j) % 12 / 2.0f, 1.0f, 1.0f, .25f)); - for (int i = 0; i < IPF; i++) - farm.moveAnts(); - } -} - -//Take command-line arguments for the width and height of the Canvas -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - //Alpha Langton - std::cout << "Alpha Langton's Ant" << std::endl; - Canvas c1(-1, -1, w, h, "Langton's Ant w/Alpha (enter to pause)"); - c1.setBackgroundColor(BLACK); - c1.run(alphaLangtonFunction); - - //Regular Langton - std::cout << "Regular Langton's Ant" << std::endl; - Canvas c2(-1, -1, w, h, "Langton's Ant"); - c2.run(langtonFunction); - - //Colony Langton - std::cout << "Multiple Langton's Ants" << std::endl; - Canvas c3(-1, -1, w, h, "4x Langton's Ants"); - c3.run(langtonColonyFunction); - - //Colorful Langton - std::cout << "Dynamically Colored Langton's Ants" << std::endl; - Canvas c4(-1, -1, w, h, "Colorful Langton's Ants"); - c4.setBackgroundColor(BLACK); - c4.run(langtonRainbowFunction); -} diff --git a/src/tests/testLineChain.cpp b/src/tests/testLineChain.cpp deleted file mode 100644 index 13b92ce7c..000000000 --- a/src/tests/testLineChain.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * testLineChain.cpp - * - * Usage: ./testLineChain - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a spirograph on a given Canvas using the specified number of threads. - * \details - * - The number of iterations, center of the spirograph, distance between threads, and spin are stored in constants. - * - A parallel block is made and the process is forked using the passed number of threads: \b t. - * - The actual number of threads spawned is stored in the constant: \b NTHREADS. - * - The rate at which the spirograph fades is calculated and stored in: \b FADERATE. - * - The current thread's id is stored in: \b TID. - * - \b xOld and \b yOld represent the old x and y-coordinates of the line, - * \b xNew and \b yNew represent the new ones. - * - \b xNew is set to the width of the Canvas, \b yNew is set to the middle of the canvas. - * - Set a variable, \b next, which will be used to determine the next \b xNew and \b yNew and set \b s to \b next. - * - Get a color based off of the thread's id number. - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - While the canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - For 0 to the number of iterations per frame: - * - \b next is incremented by the spacing in between the threads, and \b s is incremented by the spin factor. - * - \b xOld and \b yOld are set to \b xNew and \b yNew. - * - The size of the line is determined by \b s. - * - \b xNew and \b yNew are calculated and set. - * - The line is drawn to the Canvas. - * . - * - If we are working with the main thread, draw a rectangle that is the size of the Canvas and has an alpha transparency - * of: \b FADERATE. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param t The number of threads to use in the function. - */ -void lineChainFunction(Canvas& can, int t) { - const int IPF = 3; - const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; - const float ARC = 2.3f, SPIN = 0.01f; - #pragma omp parallel num_threads(t) - { - const float NTHREADS = omp_get_num_threads(); - const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; - const int TID = omp_get_thread_num(); - int xOld, yOld, xNew = CWW*2, yNew = CWH; - float next = (ARC*TID)/NTHREADS, s = next; - ColorFloat c = Colors::highContrastColor(TID); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = 0; i < IPF; ++i) { - next += ARC; s += SPIN; - xOld = xNew; yOld = yNew; - float size = cos(s); - xNew = CWW + CWW*size*cos(next); - yNew = CWH + CWH*size*sin(next); - can.drawLine(xOld, yOld, xNew, yNew, c); - } - if (TID == 0) - can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); - #pragma omp barrier - } - } -} - -//Takes command line arguments for the window width and height as well as for the number of threads -//to use in the function -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 900; //If not, set the width and height to a default value - unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use - if (t == 0) - t = omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Spirograph"); - c.setBackgroundColor(BLACK); - c.run(lineChainFunction,t); -} diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile deleted file mode 100644 index 48304e949..000000000 --- a/src/tests/testLineChain/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testLineChain - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testLineChain - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testLineChain/testLineChain.cpp b/src/tests/testLineChain/testLineChain.cpp deleted file mode 100644 index 8a2b390ad..000000000 --- a/src/tests/testLineChain/testLineChain.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * testLineChain.cpp - * - * Usage: ./testLineChain - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a spirograph on a given Canvas using the specified number of threads. - * \details - * - The number of iterations, center of the spirograph, distance between threads, and spin are stored in constants. - * - A parallel block is made and the process is forked using the passed number of threads: \b t. - * - The actual number of threads spawned is stored in the constant: \b NTHREADS. - * - The rate at which the spirograph fades is calculated and stored in: \b FADERATE. - * - The current thread's id is stored in: \b TID. - * - \b xOld and \b yOld represent the old x and y-coordinates of the line, - * \b xNew and \b yNew represent the new ones. - * - \b xNew is set to the width of the Canvas, \b yNew is set to the middle of the canvas. - * - Set a variable, \b next, which will be used to determine the next \b xNew and \b yNew and set \b s to \b next. - * - Get a color based off of the thread's id number. - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - While the canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - For 0 to the number of iterations per frame: - * - \b next is incremented by the spacing in between the threads, and \b s is incremented by the spin factor. - * - \b xOld and \b yOld are set to \b xNew and \b yNew. - * - The size of the line is determined by \b s. - * - \b xNew and \b yNew are calculated and set. - * - The line is drawn to the Canvas. - * . - * - If we are working with the main thread, draw a rectangle that is the size of the Canvas and has an alpha transparency - * of: \b FADERATE. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param t The number of threads to use in the function. - */ -void lineChainFunction(Canvas& can, int t) { - const int IPF = 3; - const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; - const float ARC = 2.3f, SPIN = 0.01f; - #pragma omp parallel num_threads(t) - { - const float NTHREADS = omp_get_num_threads(); - const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; - const int TID = omp_get_thread_num(); - int xOld, yOld, xNew = CWW*2, yNew = CWH; - float next = (ARC*TID)/NTHREADS, s = next; - ColorFloat c = Colors::highContrastColor(TID); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = 0; i < IPF; ++i) { - next += ARC; s += SPIN; - xOld = xNew; yOld = yNew; - float size = cos(s); - xNew = CWW + CWW*size*cos(next); - yNew = CWH + CWH*size*sin(next); - can.drawLine(xOld, yOld, xNew, yNew, c); - } - if (TID == 0) - can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); - #pragma omp barrier - } - } -} - -//Takes command line arguments for the window width and height as well as for the number of threads -//to use in the function -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 900; //If not, set the width and height to a default value - unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use - if (t == 0) - t = omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Spirograph", BLACK); - c.run(lineChainFunction,t); -} diff --git a/src/tests/testLineFan.cpp b/src/tests/testLineFan.cpp deleted file mode 100644 index 74aaf0d4a..000000000 --- a/src/tests/testLineFan.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * testLineFan.cpp - * - * Usage: ./testLineFan - */ - -#include -#include -#include "Util.h" - -using namespace tsgl; - -/*! - * \brief Draws a fan of randomly colored lines at the target framerate and a dynamic number of threads using OMP. - * \details - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - The spacing in between the arcs of the fan is stored in the constant: \b ARC . - * - While the canvas is open: - * - The number of threads to use is recalculated, and the process is forked based off of the passed number of threads: \b t. - * - The internal timer sleeps on each thread until the next frame is ready to be drawn. - * - An offset is calculated based on the thread's ID and a predefined arc-length. - * - An angle is then calculated using the offset and the Canvas' current lifespan ( as calculated by \b can.getReps() ). - * - The vertices of the lines to be drawn are chosen using the sines and cosines of the predetermined angle. - * - A random color is chosen. - * - The line is draw to the Canvas. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param t The number of threads to use in the function. - */ -void lineFanFunction(Canvas& can, int t) { - const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan - while (can.isOpen()) { - #pragma omp parallel num_threads(t) - { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - int a, b, c, d, red, green, blue; - double angle, offset = omp_get_thread_num() * ARC; - angle = offset + can.getReps() * RAD; - a = can.getWindowWidth() / 2 * (1 + sin(angle)); - b = can.getWindowHeight() / 2 * (1 + cos(angle)); - c = can.getWindowWidth() / 2 * (1 - sin(angle)); - d = can.getWindowHeight() / 2 * (1 - cos(angle)); - red = (a + can.getReps()) % NUM_COLORS; - green = (b + can.getReps()) % NUM_COLORS; - blue = (a * b + can.getReps()) % NUM_COLORS; - can.drawLine(a, b, c, d, ColorInt(red, green, blue)); - } - } -} - -//Takes command-line arguments for the width and height of the screen as well as for the -//number of threads to use in the function -int main(int argc, char** argv) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid - w = 1200; - h = 900; //If not, set the width and height to a default value - } - unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use - if (t == 0) - t = omp_get_num_procs(); - Canvas c(-1,-1,w,h,"Line Fan"); - c.run(lineFanFunction,t); -} diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile deleted file mode 100644 index 8f2cb68e6..000000000 --- a/src/tests/testLineFan/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testLineFan - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testLineFan - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testLineFan/testLineFan.cpp b/src/tests/testLineFan/testLineFan.cpp deleted file mode 100644 index 74aaf0d4a..000000000 --- a/src/tests/testLineFan/testLineFan.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * testLineFan.cpp - * - * Usage: ./testLineFan - */ - -#include -#include -#include "Util.h" - -using namespace tsgl; - -/*! - * \brief Draws a fan of randomly colored lines at the target framerate and a dynamic number of threads using OMP. - * \details - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - The spacing in between the arcs of the fan is stored in the constant: \b ARC . - * - While the canvas is open: - * - The number of threads to use is recalculated, and the process is forked based off of the passed number of threads: \b t. - * - The internal timer sleeps on each thread until the next frame is ready to be drawn. - * - An offset is calculated based on the thread's ID and a predefined arc-length. - * - An angle is then calculated using the offset and the Canvas' current lifespan ( as calculated by \b can.getReps() ). - * - The vertices of the lines to be drawn are chosen using the sines and cosines of the predetermined angle. - * - A random color is chosen. - * - The line is draw to the Canvas. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param t The number of threads to use in the function. - */ -void lineFanFunction(Canvas& can, int t) { - const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan - while (can.isOpen()) { - #pragma omp parallel num_threads(t) - { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - int a, b, c, d, red, green, blue; - double angle, offset = omp_get_thread_num() * ARC; - angle = offset + can.getReps() * RAD; - a = can.getWindowWidth() / 2 * (1 + sin(angle)); - b = can.getWindowHeight() / 2 * (1 + cos(angle)); - c = can.getWindowWidth() / 2 * (1 - sin(angle)); - d = can.getWindowHeight() / 2 * (1 - cos(angle)); - red = (a + can.getReps()) % NUM_COLORS; - green = (b + can.getReps()) % NUM_COLORS; - blue = (a * b + can.getReps()) % NUM_COLORS; - can.drawLine(a, b, c, d, ColorInt(red, green, blue)); - } - } -} - -//Takes command-line arguments for the width and height of the screen as well as for the -//number of threads to use in the function -int main(int argc, char** argv) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid - w = 1200; - h = 900; //If not, set the width and height to a default value - } - unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use - if (t == 0) - t = omp_get_num_procs(); - Canvas c(-1,-1,w,h,"Line Fan"); - c.run(lineFanFunction,t); -} diff --git a/src/tests/testLines.cpp b/src/tests/testLines.cpp deleted file mode 100644 index 625f32b79..000000000 --- a/src/tests/testLines.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * testLines.cpp tests displaying the Line and Polyline classes. - */ -#include -using namespace tsgl; - -void lineFunction(Canvas& c) { - ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), - ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), - ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), - ColorFloat(0,0,1,0.7) }; - Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); - - // l->setColor(RED); - l->setColor(colors); - - float vertices[] = { -150,-100,-100, - -100,100,0, - -50,-100,100, - 0,-100,-100, - 50,100,0, - 100,-100,100, - 150,-100,-100 }; - - Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); - - // printf("Line: %f\n", l->getAlpha()); - // printf("Pline: %f\n", p->getAlpha()); - - // p->setColor(BLUE); - p->setColor(colors); - c.add(l); - c.add(p); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while( c.isOpen() ) { - c.sleep(); - // l->setCenterX(sin(floatVal/90)); - // l->setCenterY(sin(floatVal/90)); - // l->setCenterZ(sin(floatVal/90)); - // l->setYaw(floatVal); - // l->setPitch(floatVal); - // l->setRoll(floatVal); - // l->setLength(sin(floatVal/90) + 2); - // if (l->getLength() > 3 || l->getLength() < 1) { - // delta *= -1; - // } - // l->changeLengthBy(delta); - // p->setCenterX(sin(floatVal/90)); - // p->setCenterY(sin(floatVal/90)); - // p->setCenterZ(sin(floatVal/90)); - // p->setYaw(floatVal); - // p->setPitch(floatVal); - p->setRoll(floatVal); - floatVal += 1; - } - - delete l; - delete p; -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Lines"); - c.run(lineFunction); -} \ No newline at end of file diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile deleted file mode 100644 index 035a50499..000000000 --- a/src/tests/testLines/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testLines - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testLines - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp deleted file mode 100644 index 625f32b79..000000000 --- a/src/tests/testLines/testLines.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * testLines.cpp tests displaying the Line and Polyline classes. - */ -#include -using namespace tsgl; - -void lineFunction(Canvas& c) { - ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), - ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), - ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), - ColorFloat(0,0,1,0.7) }; - Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); - - // l->setColor(RED); - l->setColor(colors); - - float vertices[] = { -150,-100,-100, - -100,100,0, - -50,-100,100, - 0,-100,-100, - 50,100,0, - 100,-100,100, - 150,-100,-100 }; - - Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); - - // printf("Line: %f\n", l->getAlpha()); - // printf("Pline: %f\n", p->getAlpha()); - - // p->setColor(BLUE); - p->setColor(colors); - c.add(l); - c.add(p); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while( c.isOpen() ) { - c.sleep(); - // l->setCenterX(sin(floatVal/90)); - // l->setCenterY(sin(floatVal/90)); - // l->setCenterZ(sin(floatVal/90)); - // l->setYaw(floatVal); - // l->setPitch(floatVal); - // l->setRoll(floatVal); - // l->setLength(sin(floatVal/90) + 2); - // if (l->getLength() > 3 || l->getLength() < 1) { - // delta *= -1; - // } - // l->changeLengthBy(delta); - // p->setCenterX(sin(floatVal/90)); - // p->setCenterY(sin(floatVal/90)); - // p->setCenterZ(sin(floatVal/90)); - // p->setYaw(floatVal); - // p->setPitch(floatVal); - p->setRoll(floatVal); - floatVal += 1; - } - - delete l; - delete p; -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Lines"); - c.run(lineFunction); -} \ No newline at end of file diff --git a/src/tests/testMandelbrot.cpp b/src/tests/testMandelbrot.cpp deleted file mode 100644 index 91172986d..000000000 --- a/src/tests/testMandelbrot.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * testMandelbrot.cpp - * - * Usage: ./testMandelbrot - */ - -/*testMandelbrot.cpp contains multiple functions that display a Mandelbrot set in similar fashions (and one that displays a Julia set). */ - -#include "Mandelbrot/Buddhabrot.h" -#include "Mandelbrot/Mandelbrot.h" -#include "Mandelbrot/GradientMandelbrot.h" -#include "Mandelbrot/Julia.h" -#include "Mandelbrot/Nova.h" - -using namespace tsgl; - -/*! - * \brief Draws the Mandelbrot set on a CartesianCanvas with custom controls, a specified target update rate, - * and a dynamic number of threads and uses command-line arguments to specify the number of threads to use. - * There is also a ProgressBar that shows the progress made by each thread as the Mandelbrot set is drawn onto the CartesianCanvas. - * \details - * - A class containing all of the data and methods to draw a Mandelbrot set has been made. - * - When you create a Mandelbrot object: - * - The number of threads to use is predetermined (passed as the \b threads parameter) and stored in: \b myThreads. - * - The number of iterations to check is predetermined (passed as the \b depth parameter) and stored in: \b myDepth. - * - The internal timer of the Canvas is set up to go off every ( \b FRAME / 2 ) seconds. - * - A flag telling us to redraw is set to true. - * . - * - When you bind the buttons: - * - The spacebar on-press event is set to tell the Canvas to clear and re-render. - * - The left mouse on-press event is set to grab the mouse's current coordinates. - * - The left mouse on-release event is set to grab the mouse's current coordinates, and tell the Canvas to zoom into the - * bounding rectangle between the current coordinates and those from the left mouse's on press event and to redraw the Mandelbrot - * at that point. - * - The right mouse on-press event is set to grab the mouse's current coordinates, and tell the Canvas to zoom out - * from that area and redraw the Mandlebrot at that point. - * - The mouse's scroll wheel is set to tell the Canvas to zoom in / out by a predetermined amount at the mouse's - * current coordinates and redraw the Mandelbrot at that point. - * . - * - When you actually draw the Mandelbrot object onto the CartesianCanvas: - * - Store the height of the Canvas, the x and y-coordinates for the ProgressBar, and the width of the ProgressBar Canvas. - * - Create the Canvas that will draw the ProgressBar object. - * - Create the ProgressBar object. - * - While the redraw flag is set: - * - Set the redraw flag to false. - * - Reset the internal timer to 0. - * - Fork off the predetermined number of parallel threads using OMP. - * - Store the actual number of threads spawned in: \b nthreads. - * - Assign a color to each thread. - * - Figure the cartesian size of the area each thread is to calculate and store it in: \b blocksize. - * - Figure out the actual number of rows each thread is to calculate and store it in: \b blockheight. - * - Clear the Canvas that holds the ProgressBar. - * - Update the ProgressBar. - * - Draw the ProgressBar onto the Canvas. - * - For 0 to \b blockheight and as long as we aren't trying to render off of the screen: - * - Update the ProgressBar. - * - Redraw the ProgressBar with labels for the ID of each thread above each segment of the ProgressBar. - * - Make an inner loop which determines whether to color the pixels black or a different color based off of whether they've escaped or not. - * - (Basic Mandelbrot calculations; see http://en.wikipedia.org/wiki/Mandelbrot_set#Computer_drawings ). - * - Break if the Canvas is to redraw. - * . - * - Handle any IO events (OS X version only). - * - Break if the Canvas is to redraw. - * . - * - Output the time it took to compute the screen. - * - While the Canvas has not been closed and it isn't time to redraw yet: - * - Sleep the thread for one frame until the Canvas is closed by the user or told to redraw. - * . - * . - * - If the ProgressBar Canvas is still open, close it up. - * . - * \param can Reference to the CartesianCanvas being drawn to. - * \param threads Reference to the number of threads passed via command-line arguments. - * \param depth The number of iterations to go to in order to draw the Mandelbrot set. - */ -void mandelbrotFunction(Cart& can, unsigned threads, unsigned depth) { - Mandelbrot m(threads,depth); //Make the object - m.bindings(can); //Bind the buttons - m.draw(can); //Draw the Mandelbrot object onto the Canvas -} - -/*! - * \brief Draws a Gradient Mandelbrot set on a CartesianCanvas. - * \details Same as mandelbrotFunction(), but with smoother shading and no ProgressBar. - * ( see http://linas.org/art-gallery/escape/smooth.html ). - * \param can Reference to the CartesianCanvas being drawn to. - * \param threads Reference to the number of threads to use. - * \param depth The number of iterations to go to in order to draw the Gradient Mandelbrot set. - * \see mandelbrotFunction(), GradientMandelbrot class. - */ -void gradientMandelbrotFunction(Cart& can, unsigned threads, unsigned depth) { - GradientMandelbrot m(threads,depth); //Create the GradientMandelbrot - m.bindings(can); //Bind the buttons - m.draw(can); //Draw it -} - -/*! - * \brief Draws a Buddhabrot set on a CartesianCanvas. - * \details Same as mandelbrotFunction(), but with a different shading algorithm and no - * ProgressBar. - * ( see https://en.wikipedia.org/wiki/Buddhabrot ). - * \param can Reference to the CartesianCanvas being drawn to. - * \param threads Reference to the number of threads to use. - * \param depth The number of iterations to go to in order to draw the Buddhabrot set. - */ -void buddhabrotFunction(Cart& can, unsigned threads, unsigned depth) { - Buddhabrot b(threads, depth); //Create the Buddhabrot object - b.draw(can); //Draw it -} - -/*! - * \brief Draws a Julia set. - * \details It is drawn in this way: - * - It is drawn in a similar way as the Mandelbrots are. - * - A class contains all of the necessary information to draw the Julia set. - * - When the Julia class object is made: - * - Set class instance variables for keeping track of the number of threads to use, - * the number of iterations, point coordinates for zooming in and out, and a redraw flag - * that determines when we should redraw the Julia object. - * . - * - When you bind buttons to the CartesianCanvas: - * - Bind the spacebar to clear the screen and redraw the Julia object. - * - Bind the left mouse button to zoom in and redraw the Julia object at the - * focused point. - * - Bind the right mouse button to zoom out and redraw the Julia object. - * - Bind the mouse wheel to zoom in and out when scrolled up and down (respectively) - * and redraw the Julia object. - * . - * - When you actually draw the Julia object onto the CartesianCanvas: - * - Store the window width of the Canvas. - * - Create a VisualTaskQueue object that displays how much work each thread did in drawing - * the Julia object. - * - While its time to redraw: - * - Set the redraw flag to false. - * - Reset the Canvas' internal timer to 0. - * - Reset the VisualTaskQueue object. - * - A parallel block is made using: \b myThreads threads. - * - Store the thread id number and the number of threads. - * - Store the thread color. - * - An infinite loop is made where the necessary calculations needed to draw the Julia - * object are made and the Julia object is drawn. Once the Julia object has been drawn, the - * loop is broken out of. Also, if the Canvas is not open or the redraw flag is set, the loop - * is also broken out of. Also, if one of the threads tries to render off of the screen, the loop - * is broken out of. The VisualTaskQueue is also updated in this loop, and if you are a Mac user, - * I/O events are handled here as well. - * . - * - Output the time it took for each iteration. - * - While the Canvas is open and the redraw flag is NOT set: - * - Sleep the internal timer until the next draw cycle. - * . - * . - * - Close the VisualTaskQueue. - * . - * . - * \param can Reference to the CartesianCanvas to draw to. - * \param threads Reference to the number of threads to use when drawing the Julia object. - * \param depth The number of iterations to go to in order to draw the Julia object. - */ -void juliaFunction(Cart& can, unsigned threads, unsigned depth) { - Julia j(threads,depth); //Create the Julia object - j.bindings(can); //Bind the buttons - j.draw(can); //Draw it -} - -/*! - * \brief Draws a Nova fractal (Newton fractal) on a CartesianCanvas. - * \param can Reference to the CartesianCanvas being drawn to. - * \param threads Reference to the number of threads to use. - * \param depth The number of iterations to go to in order to draw the Gradient Mandelbrot set. - * \see mandelbrotFunction(), Nova class. - */ -void novaFunction(Cart& can, unsigned threads, unsigned depth) { - Nova n(threads,depth); //Create the Nova object - n.bindings(can); //Bind the buttons - n.draw(can); //Draw it -} - -//Takes command line arguments for the width and height of the screen -//as well as the number of threads to use and the number of iterations to draw the Mandelbrot set -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - int w2 = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); //Julia - int h2 = (argc > 2) ? atoi(argv[2]) : 0.75*w; //Julia - int x = Canvas::getDisplayWidth() - w - 64; - if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid - w = 1200; - w2 = 1.2 * Canvas::getDisplayHeight(); - h = 900; //If not, set the width and height to a default value - h2 = 0.75 * w2; - } - unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use - if (t == 0) - t = omp_get_num_procs(); - unsigned d = (argc > 4) ? atoi(argv[4]) : MAX_COLOR; //Normal Mandelbrot - unsigned d2 = (argc > 4) ? atoi(argv[4]) : 32; //Gradient Mandelbrot & Nova - unsigned d3 = (argc > 4) ? atoi(argv[4]) : 1000; //Buddhabrot & Julia - //Normal Mandelbrot - std::cout << "Normal Mandelbrot" << std::endl; - Cart c1(-1, -1, w, h, -2, -1.125, 1, 1.125, "Mandelbrot", FRAME / 2); - c1.run(mandelbrotFunction,t,d); - - //Gradient Mandelbrot - std::cout << "Gradient Mandelbrot" << std::endl; - Cart c2(-1, -1, w, h, -2, -1.125, 1, 1.125, "Gradient Mandelbrot", FRAME / 2); - c2.run(gradientMandelbrotFunction,t,d2); - std::cout << "Buddhabrot" << std::endl; - - //Buddhabrot - Cart c3(-1, -1, w, h, -2, -1.125, 1, 1.125, "Buddhabrot", FRAME / 2); - c3.setBackgroundColor(BLACK); - c3.run(buddhabrotFunction,t,d3); - - //Julia #FIXME requires a different library path - std::cout << "Julia set" << std::endl; - Cart c4(x, -1, w2, h2, -2, -1.125, 1, 1.125, "Julia Set", FRAME / 2); - c4.run(juliaFunction,t,d3); - - //Nova - std::cout << "Nova" << std::endl; - Cart c5(x, -1, w, h, -1.0, -0.5, 0, 0.5, "Nova (Newton Fractal)", FRAME / 2); - c5.zoom(-0.361883,-0.217078,0.1f); - c5.run(novaFunction,t,32); -} diff --git a/src/tests/testMergeSort.cpp b/src/tests/testMergeSort.cpp deleted file mode 100644 index 04e95382f..000000000 --- a/src/tests/testMergeSort.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * testMergeSort.cpp - * - * Usage: ./testMergeSort - */ - -#include -#include - -using namespace tsgl; - -enum MergeState { - S_MERGE = 1, - S_SHIFT = 2, - S_WAIT = 3, - S_DONE = 4, - S_HIDE = 5 -}; - -struct sortData { - ColorFloat color; //Color of the thread - MergeState state; //Current state of the threads - int first, last, //Start and end of our block - left, right, //Indices of two numbers to compare - fi, hi, li, //Indices of first middle and last numbers in a set - depth; //Current depth of the merge - float* a; //Array of numbers to sort - int seg, segs; //Current / total segments - int size; - - sortData(float* arr, int f, int l, ColorFloat c) { - fi = hi = li = 0; //Initialize indices - left = right = 0; //Initialize bounds - color = c; //Set the color - a = arr; //Get a pointer to the array we'll be sorting - first = f; //Set the first element we need to worry about - last = l; //Set the last element we need to worry about - depth = 0; //We start at depth 0 - seg = 0; segs = 1; //We start on segment -1, with a total of 1 segment - while(segs < (l-f)) { //If the current number of segments is more than the # of elements, we're done - ++depth; //Otherwise, increment the depth... - segs *= 2; //...and double the number of segments - } - state = S_SHIFT; //Start Merging - size = 2; - } - - void restart(int l) { - depth = 0; - hi = last; - right = hi+1; - last = li = l; - fi = left = first; - state = S_MERGE; - size *= 2; - } - - void sortStep() { - float tmp; - int pivot, jump; - switch(state) { - case S_SHIFT: - pivot = jump = segs/2; - fi = first; li = last; - hi = (fi + li) / 2; //Set our half index to the median of our first and last - for (tmp = depth; tmp > 0; --tmp) { - jump /= 2; - if (seg < pivot) { - pivot -= jump; - li = hi; //Set out last index to our old half index - } else { - pivot += jump; - fi = hi+1; //Set out first index to our old half index plus one - } - hi = (fi + li) / 2; //Set our new half index to the median of our first and last - } - left = fi; right = hi+1; - state = S_MERGE; //We're ready to start Merging - break; - case S_MERGE: - if (left > right || right > last) { - seg = 0; //Reset our segment(s) - segs /= 2; //We're now using half as many segments - state = (depth-- == 0) ? S_WAIT : S_SHIFT; - } else if (right > li) { - ++seg; state = S_SHIFT; //Move on to the next segment and recalculate our first and last indices - } else if (left <= hi && a[left] < a[right]) { - ++left; - } else { - tmp = a[right]; - for (int x = right; x > left; --x) - a[x] = a[x-1]; - a[left] = tmp; - ++left; ++right; ++hi; - } - break; - default: - break; - } - } -}; - -/*! - * \brief Visualization of the bottom-up mergesort algorithm. - * \details Utilizes the sortData struct and sorts a number of items using the mergesort algorithm. - * \details Uses lines to represent the items being sorted. - * \details At the start, the items being sorted are all divided. - * \details Once items have been sorted in one divided section, then sections are merged and the process repeats itself. - * \details Different colors represent different sections being sorted. - * \details Once all items have been sorted and merged, the animation stops and all lines are colored white. - */ -void mergeSortFunction(Canvas& can, int threads, int size) { - const int IPF = 1; // Iterations per frame - float* numbers = new float[size]; // Array to store the data - Rectangle** rectangles = new Rectangle*[size]; // Array to store the data - float start = -can.getWindowWidth() * .45; - float width = can.getWindowWidth() * .9 / size; - for (int i = 0; i < size; i++) { - numbers[i] = saferand(1,can.getWindowHeight()); - rectangles[i] = new Rectangle(start + i * width, 0, 0, width, numbers[i], 0, 0, 0, RED); - can.add(rectangles[i]); - } - - int baseNumVals = size / threads; - int extraVals = size % threads; - sortData** sd = new sortData*[threads]; - int firstIndex = 0; - int lastIndex = (extraVals == 0) ? baseNumVals-1 : baseNumVals; - for (int i = 0; i < threads; ++i) { - sd[i] = new sortData(numbers,firstIndex,lastIndex,Colors::highContrastColor(i)); - firstIndex = lastIndex+1; - if (i < extraVals-1) lastIndex += (baseNumVals + 1); - else lastIndex += baseNumVals; - } - while (can.isOpen()) { - #pragma omp parallel num_threads(threads) - { - int tid = omp_get_thread_num(); - can.sleep(); - if (sd[tid]->state == S_WAIT) { //Merge waiting threads - if ((tid % sd[tid]->size) > 0) - sd[tid]->state = S_DONE; - else { - int next = tid+sd[tid]->size/2; - if (next < threads && sd[next]->state == S_DONE) { - sd[next]->state = S_HIDE; - sd[tid]->restart(sd[next]->last); - } - } - } - for (int i = 0; i < IPF; i++) - sd[tid]->sortStep(); - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - float height; - ColorFloat color; - if (sd[tid]->state != S_HIDE) { - //Draw a black rectangle over our portion of the screen to cover up the old drawing - // can.drawRectangle(start,0,sd[tid]->last - sd[tid]->first,cwh,can.getBackgroundColor()); - for (int i = sd[tid]->first; i <= sd[tid]->last; ++i, ++start) { - height = numbers[i]; - if (sd[tid]->state == S_WAIT || sd[tid]->state == S_DONE) - color = WHITE; - else { - if (i == sd[tid]->right || i == sd[tid]->left) - color = WHITE; - else if (i < sd[tid]->left) - color = sd[tid]->color; - else if (i >= sd[tid]->fi && i <= sd[tid]->li) - color = Colors::blend(sd[tid]->color, WHITE, 0.5f); - else - color = Colors::blend(sd[tid]->color, BLACK, 0.5f); - } - rectangles[i]->setHeight(height); - rectangles[i]->setColor(color); - } - } - can.resumeDrawing(); //Tell the Canvas it can resume updating - } - } - for (int i = 0; i < threads; ++i) - delete sd[i]; - delete [] sd; - delete [] numbers; - for (int i = 0; i < size; i++) { - delete rectangles[i]; - } - delete [] rectangles; -} - -//Takes in command line arguments for the window width and height -//as well as for the number of threads to use -int main(int argc, char* argv[]) { - int s = (argc > 1) ? atoi(argv[1]) : 1024; - if (s < 10) s = 10; - int w = s * 1.3; - int h = w/2; - - int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); - for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 - - Canvas c(0, 0, w, h, "Bottom-up Merge Sort"); - c.setBackgroundColor(BLACK); - c.run(mergeSortFunction, threads, s); -} diff --git a/src/tests/testMouse.cpp b/src/tests/testMouse.cpp deleted file mode 100644 index 5d30116a3..000000000 --- a/src/tests/testMouse.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * testMouse.cpp - * - * Usage: ./testMouse - */ - -#include - -using namespace tsgl; - -inline float dist(float x1, float y1, float x2, float y2) { - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -inline float angle(float x1, float y1, float x2, float y2) { - return atan2(y1 - y2, x1 - x2); -} - -inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { - float scale = cy/cx; - float stretchy = cy + yy/scale - cx; - float mydist = dist(xx,stretchy,cx,cy); - float newang = angle(xx,stretchy,cx,cy)+rot; - xx = cx + mydist*cos(newang); - yy = cy + mydist*sin(newang)*scale; -} - -/*! - * \brief Tiny little painting function for drawing with the mouse. - * \details - * - Initialize and unset a flag for whether the mouse is pressed. - * - Allocate some large arrays for x,y coordinates and colors. - * - Set an array index variable to 0. - * - Declare variables for last x and y coordinates. - * - Bind the spacebar on-press event to clearing the Canvas. - * - Bind the left mouse on-press event to setting the lastX, lastY, and first x,y array - * coordinate to the mouse's current position, and the first color to a random color; also, - * set the array index to 1, and set the mouseDown flag. - * - Bind the left mouse on-release event to draw a Concave & Convex polygon with the built-up vertices, - * and to unset the mouseDown flag. - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - While the Canvas is open: - * - If the mouse is down: - * - Draw a line from the mouse's last coordinates to the current ones. - * - Set the coordinates at position \b index to the mouse's current position. - * - Set the corresponding color randomly. - * - Increment the index. - * . - * - Sleep the timer until the Canvas is ready to draw again. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void mouseFunction(Canvas& can, int threads) { - const int CX = can.getWindowWidth() / 2, CY = can.getWindowHeight() / 2; - int x[3], y[3], index = 0; - bool mouseDown = false; - ColorFloat color[3]; - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown, &can, &index, &x, &y, &color]() { - x[0] = can.getMouseX(); - y[0] = can.getMouseY(); - color[0] = Colors::randomColor(1.0f); - index = 0; - mouseDown = true; - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown, &can, &index, &x, &y, &color]() { - mouseDown = false; - }); - - while (can.isOpen()) { - if (mouseDown) { - color[1] = color[2]; - color[2] = Colors::randomColor(1.0f); - x[1] = x[2]; y[1] = y[2]; - x[2] = can.getMouseX(); y[2] = can.getMouseY(); - if (++index > 2) - #pragma omp parallel num_threads (threads) - { - float tdelta = (2*PI*omp_get_thread_num())/omp_get_num_threads(); - int myx[3], myy[3]; - for (int i = 0; i < 3; ++i) { - myx[i] = x[i]; myy[i] = y[i]; - rotate(CX,CY,myx[i],myy[i],tdelta); - } - can.drawConvexPolygon(3,myx,myy,color,true); - } - } - can.sleep(); - } -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : -1; - int h = (argc > 2) ? atoi(argv[2]) : w; - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Draw With Your Mouse!"); - c.setBackgroundColor(WHITE); - c.run(mouseFunction,t); -} diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile deleted file mode 100644 index 404a455c4..000000000 --- a/src/tests/testMouse/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testMouse - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testMouse - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testMouse/testMouse.cpp b/src/tests/testMouse/testMouse.cpp deleted file mode 100644 index e37e49c34..000000000 --- a/src/tests/testMouse/testMouse.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * testMouse.cpp - * - * Usage: ./testMouse - */ - -#include - -using namespace tsgl; - -inline float dist(float x1, float y1, float x2, float y2) { - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -inline float angle(float x1, float y1, float x2, float y2) { - return atan2(y1 - y2, x1 - x2); -} - -inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { - float scale = cy/cx; - float stretchy = cy + yy/scale - cx; - float mydist = dist(xx,stretchy,cx,cy); - float newang = angle(xx,stretchy,cx,cy)+rot; - xx = cx + mydist*cos(newang); - yy = cy + mydist*sin(newang)*scale; -} - -/*! - * \brief Tiny little painting function for drawing with the mouse. - * \details - * - Initialize and unset a flag for whether the mouse is pressed. - * - Allocate some large arrays for x,y coordinates and colors. - * - Set an array index variable to 0. - * - Declare variables for last x and y coordinates. - * - Bind the spacebar on-press event to clearing the Canvas. - * - Bind the left mouse on-press event to setting the lastX, lastY, and first x,y array - * coordinate to the mouse's current position, and the first color to a random color; also, - * set the array index to 1, and set the mouseDown flag. - * - Bind the left mouse on-release event to draw a Concave & Convex polygon with the built-up vertices, - * and to unset the mouseDown flag. - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - While the Canvas is open: - * - If the mouse is down: - * - Draw a line from the mouse's last coordinates to the current ones. - * - Set the coordinates at position \b index to the mouse's current position. - * - Set the corresponding color randomly. - * - Increment the index. - * . - * - Sleep the timer until the Canvas is ready to draw again. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param threads Number of threads to use. - */ -void mouseFunction(Canvas& can, int threads) { - const int CX = can.getWindowWidth() / 2, CY = can.getWindowHeight() / 2; - int x[3], y[3], index = 0; - bool mouseDown = false; - ColorFloat color[3]; - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown, &can, &index, &x, &y, &color]() { - x[0] = can.getMouseX(); - y[0] = can.getMouseY(); - color[0] = Colors::randomColor(1.0f); - index = 0; - mouseDown = true; - }); - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown, &can, &index, &x, &y, &color]() { - mouseDown = false; - }); - - while (can.isOpen()) { - if (mouseDown) { - color[1] = color[2]; - color[2] = Colors::randomColor(1.0f); - x[1] = x[2]; y[1] = y[2]; - x[2] = can.getMouseX(); y[2] = can.getMouseY(); - if (++index > 2) - #pragma omp parallel num_threads (threads) - { - float tdelta = (2*PI*omp_get_thread_num())/omp_get_num_threads(); - int myx[3], myy[3]; - for (int i = 0; i < 3; ++i) { - myx[i] = x[i]; myy[i] = y[i]; - rotate(CX,CY,myx[i],myy[i],tdelta); - } - can.drawConvexPolygon(3,myx,myy,color,true); - } - } - can.sleep(); - } -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : -1; - int h = (argc > 2) ? atoi(argv[2]) : w; - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Draw With Your Mouse!", WHITE); - c.run(mouseFunction,t); -} diff --git a/src/tests/testNewtonPendulum.cpp b/src/tests/testNewtonPendulum.cpp deleted file mode 100644 index 180361c3c..000000000 --- a/src/tests/testNewtonPendulum.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * testNewtonPendulum.cpp - * - * Usage: ./testNewtonPendulum - */ - -#include "tsgl.h" -#include "Util.h" - -using namespace tsgl; - -/*! - * \brief Simulates Newton's Cradle (or Newton's Pendulum as some call it) ( see http://s.hswstatic.com/gif/newtons-cradle-1.jpg ). - * \details Simulates Newton's Pendulum in the following way: - * - User variables store the sizes of each ball, the number of balls (command-line argument), and the radius of each ball. - * They also store the acceleration, top speed, and the amount to inverse the direction of the swing of the balls. - * - Automatic variables store the window width and height, the center of the window, the line length, and the offset of each ball. - * - Initial positions of the edge balls are determined. - * - The leftmost ball is stationary; the rightmost is moving at top speed. - * - While the Canvas has not been closed: - * - The Canvas' internal timer is put to sleep until the next drawing loop. - * - Conditionals determine the left and right ball motion. - * - The animation loop is paused. - * - The Canvas is cleared. - * - The stationary balls and lines are drawn first, followed by the moving balls and lines. - * - The animation is resumed. - * . - * . - * \param can Reference to the Canvas to draw on. - * \param numberOfBalls The number of balls to use in the function. - */ - -void newtonPendulumFunction(Canvas& can, int numberOfBalls) { - //User variables - const int BALLS = numberOfBalls, //Keep this odd - RADIUS = 20; //Radius of circles - const float ACCEL = 0.5f, //Acceleration of balls - TOPSPEED = 9.0f, //Starting speed of balls - AMP = 100; //Inverse amplitude of balls - - const float LINELEN = can.getWindowHeight() / 2, - OFFSET = RADIUS*(BALLS-1); - - Line ** lines = new Line*[BALLS - 2]; - Circle ** balls = new Circle*[BALLS - 2]; - for (int i = -(BALLS/2)+1; i < BALLS/2; ++i) { - lines[i + BALLS/2 - 1] = new Line(RADIUS*2*i,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); - can.add(lines[i + BALLS/2 - 1]); - balls[i + BALLS/2 - 1] = new Circle(RADIUS*2*i,0,0, RADIUS, 0,0,0,GRAY); - can.add(balls[i + BALLS/2 - 1]); - } - - //Add moving Shapes - Circle* leftCircle = new Circle(-OFFSET,0,0, RADIUS, 0,0,0,GRAY); - leftCircle->setRotationPoint(-OFFSET, LINELEN, 0); - Circle* rightCircle = new Circle(OFFSET,0,0, RADIUS, 0,0,0,GRAY); - rightCircle->setRotationPoint(OFFSET, LINELEN, 0); - Line* leftLine = new Line(-OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); - leftLine->setRotationPoint(-OFFSET, LINELEN, 0); - Line* rightLine = new Line(OFFSET,LINELEN,0, LINELEN * 2, -90,0,0, BLACK); - rightLine->setRotationPoint(OFFSET, LINELEN, 0); - can.add(rightLine); can.add(leftLine); - can.add(leftCircle); can.add(rightCircle); - - //Computation - float rightPos = 0, leftPos = 0; //Initial positions of the edge balls - float leftMoving = 0, rightMoving = TOPSPEED; //Right goes first, left stays stationary - while(can.isOpen()) { - can.sleep(); - - //Drawing conditional for right ball motion - if(rightMoving != 0 || rightPos != 0) { //If the ball isn't stationary - rightMoving -= ACCEL; - rightPos += rightMoving; //Move it - if(rightPos < 0) { //If its hit the stopping point - leftMoving = -TOPSPEED; //Make it stationary and make the left ball move - rightMoving = 0; - rightPos = 0; //Reset the stopping point - } - } - //Drawing conditional for left ball motion - //Similar to the right ball motion, but with the left stop value and left ball - if(leftMoving != 0 || leftPos != 0) { - leftMoving += ACCEL; - leftPos += leftMoving; - if(leftPos > 0) { - rightMoving = TOPSPEED; - leftMoving = 0; - leftPos = 0; - } - } - - //Move the lines and balls! - //Left - leftLine->setYaw(leftPos/AMP * 180 / PI - 90); - leftCircle->setYaw(leftPos/AMP * 180 / PI); - //Right - rightLine->setYaw(rightPos/AMP * 180 / PI - 90); - rightCircle->setYaw(rightPos/AMP * 180 / PI); - } - - delete leftCircle; - delete rightCircle; - delete leftLine; - delete rightLine; - for (int i = 0; i < BALLS - 2; i++) { - delete balls[i]; - delete lines[i]; - } - delete [] balls; - delete [] lines; -} - -//Takes command line arguments for the width and height of the screen -//as well as for the number of balls -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2 * Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75 * w; - int numberOfBalls = atoi(argv[3]); //Number of balls - if(w <= 0 || h <= 0) { - w = 1200; - h = 900; - } - //Determine if the number of balls is valid - if(numberOfBalls <= 0) { //If negative, set it to 7 - numberOfBalls = 7; - } else if(numberOfBalls % 2 == 0) { //If even, add 1 - numberOfBalls++; - } - Canvas c(-1, -1, w, h, "Newton's Pendulum"); - c.setBackgroundColor(WHITE); - c.run(newtonPendulumFunction,numberOfBalls); -} diff --git a/src/tests/testPhilosophers.cpp b/src/tests/testPhilosophers.cpp deleted file mode 100644 index 5b38efbb5..000000000 --- a/src/tests/testPhilosophers.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * testPhilosophers.cpp runs the Dining Philosphers Problem animation using the TSGL library and OpenMP. - * This file includes a main method, Philospher class, Fork class, and Table class. - * - * The program provides a visualization of the Dining Philosophers Problem - * in which philosophers sit around a table, think for a random amount of time, and then want to eat. - * In order to eat, each philosopher needs the forks to their right and left, shared with the other philosophers. - * This visualization includes six different ways of resolving the conflicts. - * See also: https://en.wikipedia.org/wiki/Dining_philosophers_problem. - * - * Usage: ./DiningPhilosophers - * for enter: - * 'w' for waitWhenBlocked, which results in Deadlock - * 'f' for forfeitWhenBlocked, which results in Livelock - * 'n' for nFrameRelease, which does not lock and is mostly fair for N philosophers, N >= 5 - * 'r' for resourceHierarchy, which does not lock and is mostly fair for N philosophers, N >= 2 - * 'o' for oddEven, which does not lock and is perfectly fair for N philosophers, N >= 2 (also default) - * - * for enter: - * a number, such as 2, 5, or 10, to specify speed (increasing with higher numbers). - * 't' or 'y' to turn on step-through. Press the spacebar to proceed at each step. - * - * If step-through is turned off, the spacebar pauses the visualization. - */ - -#include -#include -#include -#include "DiningPhilosophers/Table.h" -#include "DiningPhilosophers/Philosopher.h" - -using namespace tsgl; - -void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step) { - - PhilMethod method; - //switch statement to create table with resolution method - char resolutionMethod = RM[0]; - switch(resolutionMethod) { - case 'w': - method = waitWhenBlocked; //Deadlock - break; - case 'f': - method = forfeitWhenBlocked; //Livelock (when synchronized) - break; - case 'n': - method = nFrameRelease; //No locking; mostly fair for N philosophers, N >= 5 - break; - case 'r': - method = resourceHierarchy; //No locking; mostly fair for N philosophers, N >= 2 - break; - case 'o': - method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 - break; - default: - method = oddEven; //No locking; perfectly fair for N philosophers, N >= 2 - break; - } - - Table t(can,philosophers,method); - - srand(time(NULL)); // seed the random number generator for thinking steps - - bool stepThrough = step; // Flag that determines whether the animation pauses between steps - bool paused = false; // Flag that determines whether the animation is paused - bool philPauses[philosophers]; - for(int i = 0; i < philosophers; i++) { - philPauses[i] = false; - } - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&paused,&philPauses,&philosophers]() { // toggle pause when spacebar is pressed - paused = !paused; - for(int i = 0; i < philosophers; i++) { - philPauses[i] = false; - } - }); - - #pragma omp parallel num_threads(philosophers) - { - while(can.isOpen()) { - can.sleep(); - if ((!stepThrough && !paused) || (stepThrough && !philPauses[omp_get_thread_num()])) { - if(stepThrough) { philPauses[omp_get_thread_num()] = true; } - t.checkStep(); - can.pauseDrawing(); - if(method == forfeitWhenBlocked) { //Synchronize to see Livelock - #pragma omp barrier //Barrier for optional synchronization - } - t.actStep(); - t.drawStep(); - can.resumeDrawing(); - } - } - } -} - -int main(int argc, char* argv[]) { - if( argc == 1) { - std::cout << "\nTo run the program with different values, use the format:\n\t./DiningPhilosophers " - << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in DiningPhilosophers/main.cpp" << std::endl; - } - int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 - int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 - bool stepThrough = (argc > 2 && ((std::string(argv[2]) == "t") || (std::string(argv[2]) == "y"))); - std::string resM = (argc > 3) ? argv[3] : "o"; //ResolutionMethod defaults to oddEven - Canvas c(-1, -1, 1300, 1000, "Dining Philosophers",1.0f/speed); - c.run(philosopherFunction,nphil,resM,stepThrough); -} diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile deleted file mode 100644 index d89316619..000000000 --- a/src/tests/testPixels/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testPixels - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testPixels - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp deleted file mode 100644 index c4b05bbef..000000000 --- a/src/tests/testPixels/testPixels.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * testColorPoints.cpp - * - * Usage: ./testColorPoints - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line - * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. - * \details - * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. - * - The actual number of threads created is stored in: \b nthreads . - * - The number of lines per thread is calculated and stored in: \b myPart . - * - The starting position of each given thread is calculated and stored in: \b myStart . - * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. - * - The color for a thread is calculated. - * - If the point's coordinate is even: - * - Draw a point on the Canvas in the thread's color. - * - Else: - * - Draw the point normally. - * . - * - The function breaks from the outer for loop if the Canvas is closed. - * . - * - Sleep the internal timer of the Canvas until the next draw cycle. - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Number of threads to use. - */ -void colorPointsFunction(Canvas& can, int numberOfThreads) { - // Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); - // can.setBackground(background); - Background * background = can.getBackground(); - - /* this is the part of the test for drawPixel */ - #pragma omp parallel num_threads(numberOfThreads) - { - int nthreads = omp_get_num_threads(); //Actual number of threads to use - // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. - // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. - int myPart = can.getWindowHeight() / nthreads; - int myStart = myPart * omp_get_thread_num(); - for (int i = myStart; i < myStart + myPart; i++) { - for (int j = 0; j < can.getWindowWidth(); j++) { - // int id = omp_get_thread_num(); - if (i % 2 == 0) { - background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, BLACK); - } else { - background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(i % 255, j % 255, (i*j) % 255)); - } - } - if (!can.isOpen()) break; - } - } - - /* end drawPixel. while loop only contains can.sleep() */ - - /* the getPixel portion of the test */ - // bool print = false; - // int mouseX = 0; - // int mouseY = 0; - - // background->drawSquare(-100,100,0,100,0,0,0,RED); - // background->drawSquare(-100,-100,0,100,0,0,0,GREEN); - // background->drawSquare(100,100,0,100,0,0,0,BLUE); - // background->drawSquare(100,-100,0,100,0,0,0,ORANGE); - - // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { - // print = true; - // }); - - // ColorInt c; - /* end getPixel(). uncomment entirety of while loop besides can.sleep */ - - while (can.isOpen()) { - can.sleep(); - // mouseX = can.getMouseX(); - // mouseY = can.getMouseY(); - // if (print) { - // background->drawPixel(mouseY, mouseX, RED); - // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. - // printf("%d, %d - ", mouseY, mouseX); - // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); - // print = false; - // } - } -} - -//Takes in command line arguments for the window width and height as well -//as for the number of threads to use -int main(int argc, char* argv[]) { - int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); - int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); - Canvas c(-1, -1, w, h, "Dithered Points", BLACK); - c.run(colorPointsFunction,t); -} diff --git a/src/tests/testPong.cpp b/src/tests/testPong.cpp deleted file mode 100644 index 4e5535a7a..000000000 --- a/src/tests/testPong.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * testPong.cpp - * - * Usage: ./testPong - */ - -#include "Pong/Pong.h" - -using namespace tsgl; - -/*! - * \brief Let's play some Pong! - * \details - * - Create an instance of the Pong class which encapsulates a lot of the data needed - * in order to draw the game of Pong. - * - Take in command-line arguments for the ball and paddle speed. - * - When you create an instance of the class: - * - Seed the random number generator. - * - Create the Paddle objects and the Ball object needed in order to play Pong. - * - ( see the Paddle and Ball object classes for more details on how they are created ). - * . - * - When you draw: - - Bind the buttons of the Canvas to the two Paddle objects: - * - Bind the up arrow's on-press and on-release events to set the right - * Paddle object's direction to -1 (up) and 0 (static) respectively. - * - Bind the down arrow's on-press and on-release events to set the right - * Paddle object's direction to 1 (down) and 0 respectively. - * - Bind the W key's on-press and on-release events to set the left - * Paddle object's direction to -1 and 0 respectively. - * - Bind the S key's on-press and on-release events to set the left - * Paddle object's direction to 1 and 0 respectively. - * . - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - Move the Ball object in its current direction at its current speed. - * - If the Ball object passed by one of the goal areas, increment the appropriate player's score, - * reset the Ball object's position, and send it off in a random direction and speed. - * - If the Ball object hits the top or bottom of the screen, bounce it. - * - If the Ball object hits a Paddle object, reverse its x-speed and randomly adjust its y-speed. - * - Move the Paddle objects according to their current directions. - * - Draw the Ball object and Paddle objects. - * - Draw the scores at the top of the screen. - * . - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param ballSpeed Reference to the ball speed in the game. - * \param paddleSpeed Reference to the paddle speed in the game. - */ -void pongFunction(Canvas& can, int ballSpeed, int paddleSpeed) { - Pong p1(can, ballSpeed, paddleSpeed); //Create the Pong object - p1.draw(can); //Draw the game -} - -//Takes command-line arguments for the ball and paddle speed -int main(int argc, char * argv[]) { - //Default speeds for the ball and paddles - const int BALL_DEFAULT_SPEED = 8, PADDLE_DEFAULT_SPEED = 4; - //Window width and height - int w = 1.5*Canvas::getDisplayHeight(); - int h = 0.5*w; - //Determine the ball and paddle speed from command-line arguments - int ballSpeed = (argc > 1) ? atoi(argv[1]) : BALL_DEFAULT_SPEED; - int paddleSpeed = (argc > 2) ? atoi(argv[2]) : PADDLE_DEFAULT_SPEED; - //Check if valid - if(ballSpeed > 10 || paddleSpeed > 10) { - ballSpeed = BALL_DEFAULT_SPEED; - paddleSpeed = PADDLE_DEFAULT_SPEED; - } - Canvas c(-1,-1,w,h,"Tennis for Two"); - c.setBackgroundColor(BLACK); - c.run(pongFunction,ballSpeed, paddleSpeed); -} diff --git a/src/tests/testPrism.cpp b/src/tests/testPrism.cpp deleted file mode 100644 index a07561a59..000000000 --- a/src/tests/testPrism.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testPrism.cpp - * - * Usage: ./testPrism - */ - -#include -#include - -using namespace tsgl; - -void prismFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); - Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); - - // printf("%f\n", testPrism2->getAlpha()); - // testPrism2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testPrism2->getAlpha()); - // testPrism2->setColor(colors); - // printf("%f\n", testPrism2->getAlpha()); - can.add(testPrism); - can.add(testPrism2); - can.add(testPrism3); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testPrism->setCenterX(sin(rotation)*200); - // testPrism->setCenterY(cos(rotation)*200); - // testPrism->setCenterZ(sin(rotation)*100); - // testPrism->setYaw(rotation*45); - testPrism->setPitch(rotation*45); - // testPrism->setRoll(rotation*45); - // testPrism->setHeight(sin(rotation)*100+101); - // testPrism->setRadius(sin(rotation)*100+101); - // if(testPrism->getHeight() >= 200) { - // delta = -5; - // } - // if(testPrism->getHeight() <= 5) { - // delta = 5; - // } - // testPrism->changeHeightBy(delta); - // if(testPrism->getRadius() >= 200) { - // delta = -5; - // } - // if(testPrism->getRadius() <= 5) { - // delta = 5; - // } - // testPrism->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testPrism->setColor(RED); - } else { - testPrism->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testPrism; - delete testPrism2; - delete testPrism3; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Prism"); - c.setBackgroundColor(BLACK); - c.run(prismFunction); -} \ No newline at end of file diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile deleted file mode 100644 index 7da1a87b9..000000000 --- a/src/tests/testPrism/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testPrism - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testPrism - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testPrism/testPrism.cpp b/src/tests/testPrism/testPrism.cpp deleted file mode 100644 index 3be365eff..000000000 --- a/src/tests/testPrism/testPrism.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * testPrism.cpp - * - * Usage: ./testPrism - */ - -#include -#include - -using namespace tsgl; - -void prismFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); - Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); - - // printf("%f\n", testPrism2->getAlpha()); - // testPrism2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testPrism2->getAlpha()); - // testPrism2->setColor(colors); - // printf("%f\n", testPrism2->getAlpha()); - can.add(testPrism); - can.add(testPrism2); - can.add(testPrism3); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testPrism->setCenterX(sin(rotation)*200); - // testPrism->setCenterY(cos(rotation)*200); - // testPrism->setCenterZ(sin(rotation)*100); - // testPrism->setYaw(rotation*45); - testPrism->setPitch(rotation*45); - // testPrism->setRoll(rotation*45); - // testPrism->setHeight(sin(rotation)*100+101); - // testPrism->setRadius(sin(rotation)*100+101); - // if(testPrism->getHeight() >= 200) { - // delta = -5; - // } - // if(testPrism->getHeight() <= 5) { - // delta = 5; - // } - // testPrism->changeHeightBy(delta); - // if(testPrism->getRadius() >= 200) { - // delta = -5; - // } - // if(testPrism->getRadius() <= 5) { - // delta = 5; - // } - // testPrism->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testPrism->setColor(RED); - } else { - testPrism->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testPrism; - delete testPrism2; - delete testPrism3; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Prism", BLACK); - c.run(prismFunction); -} \ No newline at end of file diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile deleted file mode 100644 index 0373a8e25..000000000 --- a/src/tests/testProcedural/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testProcedural - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testProcedural - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testProcedural/testProcedural.cpp b/src/tests/testProcedural/testProcedural.cpp deleted file mode 100644 index 2fe19cfc3..000000000 --- a/src/tests/testProcedural/testProcedural.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * testBackground.cpp tests the core functions of TSGL::Background - * - * Usage: ./testBackground - */ - -#include - -using namespace tsgl; - -void testSuite1(Background * bg) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - bg->clear(); - bg->drawSquare(-400, 225, 0, 100, 0,0,0, RED); - bg->drawSquare(-400, 100, 0, 100, 0,0,0, colors); - bg->drawCircle(-400, -100, 0, 50, 0,0,0, RED); - bg->drawCircle(-400, -225, 0, 50, 0,0,0, colors); - bg->drawEllipse(-225, 225, 0, 75,50, 0,0,0, RED); - bg->drawEllipse(-225, 100, 0, 75,50, 0,0,0, colors); - bg->drawRectangle(-225, -100, 0, 150,100, 0,0,0, RED); - bg->drawRectangle(-225, -225, 0, 150,100, 0,0,0, colors); - bg->drawImage(0,225,0,"./assets/pics/launch.bmp",100,100,0,0,0); - bg->drawText(0,100,0,L"ü^xdog","./assets/freefont/FreeMono.ttf",50,0,0,0,RED); - bg->drawRegularPolygon(0,-100,0,50,5,0,0,0,RED); - bg->drawRegularPolygon(0,-225,0,50,7,0,0,0,colors); - bg->drawTriangle(225,275,0,275,175,0,175,175,0,0,0,0,RED); - bg->drawTriangle(225,50,0,275,150,0,175,150,0,0,0,0,colors); - float x1[4] = { 160, 225, 225, 290 }; - float y1[4] = {-100, -50,-150,-100 }; - float z1[4] = { 0, 0, 0, 0 }; - bg->drawTriangleStrip(225,-100,0,4,x1,y1,z1,0,0,0,RED); - float x2[4] = { 160, 225, 225, 290 }; - float y2[4] = {-225,-175,-275,-225 }; - float z2[4] = { 0, 0, 0, 0 }; - bg->drawTriangleStrip(225,-225,0,4,x2,y2,z2,0,0,0,colors); - bg->drawArrow(400,225,0,100,10,45,0,0,RED,true); - bg->drawArrow(400,100,0,100,10,-45,0,0,colors); - bg->drawLine(400,-50,0,100,20,0,0,RED); - bg->drawLine(400,-150,0,100,-20,0,0,colors); - float vertices1[12] = { 350,-175,0, - 350,-200,0, - 450,-250,0, - 450,-275,0 }; - bg->drawPolyline(400,-225,0,4,vertices1,0,0,0,RED); - float vertices2[12] = { 450,-175,0, - 450,-200,0, - 350,-250,0, - 350,-275,0 }; - bg->drawPolyline(400,-225,0,4,vertices2,0,0,0,colors); -} - -void testSuite2(Background * bg) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - bg->clear(); - bg->drawStar(-400,225,0,50,5,0,0,0,RED,false); - bg->drawStar(-400,100,0,50,7,0,0,0,colors,false); - float x1[6] = { -450,-400,-375,-350,-400,-450 }; - float y1[6] = { -50, -50, -60,-150,-150,-100 }; - // renders incorrectly - bg->drawConcavePolygon(-400,-100,0,6,x1,y1,0,0,0,RED); - float x2[6] = { -450,-400,-375,-350,-400,-450 }; - float y2[6] = { -175,-175,-185,-275,-275,-225 }; - // renders correctly, due to shifted vertices - bg->drawConcavePolygon(-400,-225,0,6,x2,y2,0,0,0,colors); - float x3[6] = { -275,-175,-200,-175,-275,-250 }; - float y3[6] = { 275, 275, 225, 175, 175, 225 }; - bg->drawConvexPolygon(-400,225,0,6,x3,y3,0,0,0,RED); - float x4[6] = { -250,-275,-175,-200,-175,-275 }; - float y4[6] = { 100, 150, 150, 100, 50, 50 }; - bg->drawConvexPolygon(-400,100,0,6,x4,y4,0,0,0,colors); - - -} - -void proceduralFunction(Canvas& can) { - Background * bg = can.getBackground(); - // float x1[6] = { -275,-175,-200,-175,-275,-250 }; - // float y1[6] = { 275, 275, 225, 175, 175, 225 }; - // ConcavePolygon * c = new ConcavePolygon(0,0,0,6,x1,y1,0,0,0,RED); - // can.add(c); - - // Star * s = new Star(0,0,0,50,7,0,0,0,RED,false); - // can.add(s); - - // can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&c]() { - // c->changeXBy(10); - // }); - - bool flip = true; - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg, &flip]() { - if (flip) { - testSuite1(bg); - } else { - testSuite2(bg); - } - flip = !flip; - }); - - while (can.isOpen()) { - can.sleep(); - } -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.9*Canvas::getDisplayWidth(); - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Procedural Background", BLACK); - c.run(proceduralFunction); -} \ No newline at end of file diff --git a/src/tests/testProducerConsumer.cpp b/src/tests/testProducerConsumer.cpp deleted file mode 100644 index c6abe052b..000000000 --- a/src/tests/testProducerConsumer.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/** - * main.cpp contains the code that shows the visualization for the Producer-Consumer problem using TSGL and pthreads. - * It utilizes a custom Queue class to make the shared buffer. - * Producer and Consumer classes have been made in order to make the Producers and Consumers - * A Thread class has been made in order to have an encapsulated pthread (which the Producer and Consumer class both inherit from). - * Usage: ./ProducerConsumer - */ - -#include -#include -#include -#include //for try-catch debugging -#include "ProducerConsumer/Producer.h" -#include "ProducerConsumer/Consumer.h" -using namespace tsgl; - - -//Global constants -const int INNERRAD = 75; // radius of the inner circle -const int OUTERRAD = 150; // radius of the outercircle -const int CAPACITY = 8; -const int WINDOW_WIDTH = 600, WINDOW_HEIGHT = 550, MAX_DATA = 8; //Size of Canvas and limit on amount of data to be stored in Queue -Canvas queueDisplay(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Producer-Consumer", FRAME ); //Canvas to draw on -Queue sharedBuffer(MAX_DATA, queueDisplay); //Shared buffer (has colored data) - - -/** - * displayLegend helps the main method by controlling the legendDisplay - */ -void displayLegend(Circle *waitingCircle, Rectangle *waitingSquare, Canvas *queueDisplay) { - Star** bufferArray = sharedBuffer.getArray(); - int produceIndex; - int cap = sharedBuffer.getCapacity(); - int oldFirstIndex = 0; - ColorFloat* prodFillColor; - ColorFloat* consFillColor; - while( queueDisplay->isOpen() ) { - if(!sharedBuffer.isEmpty()) { - produceIndex = (sharedBuffer.getLastIndex() + cap - 1) % cap; - prodFillColor = bufferArray[produceIndex]->getFillColor(); - waitingCircle->setColor( prodFillColor[0], BLACK ); - delete[] prodFillColor; - } - if(oldFirstIndex != sharedBuffer.getFirstIndex()) { - consFillColor = bufferArray[oldFirstIndex]->getFillColor(); - waitingSquare->setColor( consFillColor[0], BLACK ); - delete[] consFillColor; - oldFirstIndex = sharedBuffer.getFirstIndex(); - } - } -} - -//Main method -int main(int argc, char * argv[]) { - int numProducers, numConsumers; //Number of producers, consumers - - if( argc == 1) { - std::cout << "\nTo run the program with different values, use the format:\n\t./ProducerConsumer [numberOfProducers] [numberOfConsumers]" << std::endl; - } - - //Check the command line - numProducers = (argc > 1) ? atoi(argv[1]) : 5; //Producers defaults to 5 - numConsumers = (argc > 2) ? atoi(argv[2]) : 5; //Consumers defaults to 5 - - //Set to max number of producers && consumers if negative, zero values - if(numProducers <= 0 || numConsumers <= 0) { - std::cout << "Invalid input! Now changing to max default values..." << std::endl; - numProducers = numConsumers = 8; - } else if(numProducers > 8 || numConsumers > 8) { - std::cout << "Too many producers/consumers! Now changing to max default values..." << std::endl; - numProducers = numConsumers = 8; - } - - srand(time(NULL)); // seed the random number generator - - //Fire up the visualization - queueDisplay.setBackgroundColor(WHITE); - queueDisplay.start(); - - queueDisplay.bindToButton(TSGL_SPACE, TSGL_PRESS, []() { // toggle pause when spacebar is pressed - PCThread::paused = !PCThread::paused; - }); - - //Prepare the display with background items - int centerY = 175; - int centerX = 300; - for(int i = 0; i < CAPACITY; i++) { - float langle = (i*2*PI)/CAPACITY; // line angle - queueDisplay.drawLine(-INNERRAD*sin(langle)+centerX, INNERRAD*cos(langle)+centerY, -OUTERRAD*sin(langle)+centerX, OUTERRAD*cos(langle)+centerY, BLACK); - } - - queueDisplay.drawRegularPolygon(centerX, centerY, OUTERRAD, CAPACITY, BLACK, false); - queueDisplay.drawRegularPolygon(centerX, centerY, INNERRAD, CAPACITY, BLACK, false); - - //Add notes to bottom of main Canvas - queueDisplay.drawText("*Numbers indicate counts of items produced and consumed", WINDOW_WIDTH-370, WINDOW_HEIGHT-20, 12, BLACK); - // Label Readers and Writers - queueDisplay.drawText("Producers", 30, 20, 24, BLACK); - queueDisplay.drawText("Consumers", WINDOW_WIDTH-150, 20, 24, BLACK); - - int LEGENDOFFSET = 300; - - //Text labels - queueDisplay.drawText("producing",100,70+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("waiting for lock",100,130+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("holding lock",100,190+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("consuming",350,70+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("waiting for lock",350,130+LEGENDOFFSET,24,BLACK); - queueDisplay.drawText("holding lock",350,190+LEGENDOFFSET,24,BLACK); - - //Create legend items - Circle waitingCircle(50, 60+LEGENDOFFSET, 20, BLACK, BLACK); //waiting for lock - Circle thinkingCircle(50, 120+LEGENDOFFSET, 20, BLACK, true); //waiting, not seeking lock - Circle lockCircle(50, 180+LEGENDOFFSET, 20, BLACK, false); //has lock - Rectangle waitingSquare(WINDOW_WIDTH-70, 40+LEGENDOFFSET, 40, 40, BLACK, BLACK); - Rectangle thinkingSquare(WINDOW_WIDTH-70, 100+LEGENDOFFSET, 40, 40, BLACK, true); - Rectangle lockSquare(WINDOW_WIDTH-70, 160+LEGENDOFFSET, 40, 40, BLACK, false); - queueDisplay.add( &waitingCircle ); queueDisplay.add( &thinkingCircle ); - queueDisplay.add( &lockCircle ); queueDisplay.add( &waitingSquare ); - queueDisplay.add( &thinkingSquare ); queueDisplay.add( &lockSquare ); - - //LEGENDEND - - std::thread legendUpdater (displayLegend, &waitingCircle, &waitingSquare, &queueDisplay); - - Producer** pro = new Producer*[numProducers]; //Array of Producers - Consumer** con = new Consumer*[numConsumers]; //Array of Consumers - - //Fill the arrays of Producers and Consumers with Producer and Consumer objects - for(int i = 0; i < numProducers; i++) { - pro[i] = new Producer(sharedBuffer, i, queueDisplay); - } - - for(int j = 0; j < numConsumers; j++) { - con[j] = new Consumer(sharedBuffer, j, queueDisplay); - } - - //Start up the pthreads for Producers and Consumers - for(int k = 0; k < numProducers; k++) { - pro[k]->start(); - sleep(0.3); - } - for(int l = 0; l < numConsumers; l++) { - con[l]->start(); - sleep(0.3); - } - - queueDisplay.wait(); - - //Now join them - for(int p = 0; p < numProducers; p++) { //Join the pthreads for the Producers - pro[p]->join(); - } - - for(int c = 0; c < numConsumers; c++) { //Join the pthreads for the Consumers - con[c]->join(); - } - - legendUpdater.join(); - - while( !sharedBuffer.isEmpty() ) { - Star * tempPtr = sharedBuffer.remove(); - delete tempPtr; - } - - delete [] pro; - delete [] con; - pro = NULL; - con = NULL; - - return 0; -} diff --git a/src/tests/testProgressBar.cpp b/src/tests/testProgressBar.cpp deleted file mode 100644 index fc7e8bd98..000000000 --- a/src/tests/testProgressBar.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * testProgressBar.cpp - * - * Usage: ./testProgressBar - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command line argument for the - * number of threads to use. - * \details - * - Compute and store the necessary information in order to draw the ProgressBar object - * (x-coordinate, y-coordinate, width, height, minimum, maximum, and the number of segments). - * - Create the ProgressBar object with the information calculated in the previous step. - * - Set the progress of drawing the ProgressBar object and store it in: \b progress. - * - While the Canvas is open: - * - Sleep the Canvas' internal timer until the next draw cycle. - * - Increment the progress so far. - * - For 0 to the number of segments: - * - Update the ProgressBar object. - * . - * - Draw the ProgressBar onto the Canvas. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void progressBarFunction(Canvas& can, int numThreads) { - const int X = 100, Y = X, W = can.getWindowWidth()-X*2, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; - ProgressBar pb(X,Y,W,H,MIN,MAX,SEGS); - int progress = 0; - for (int i = 0; i < SEGS; ++i) - can.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - ++progress; - for (int i = 0; i < SEGS; ++i) - pb.update(progress+i*(MAX/SEGS),i); - can.drawProgress(&pb); - } -} - -//Takes in the number of threads to use as a command line argument for the Canvas, defaulting to 8. -//( see http://www.cplusplus.com/articles/DEN36Up4/ ) -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : 8; - int w; - int h; - if (t <= 0 || 10 < t) //Checked the passed threadNumber if it is valid - t = 8; //If not, set numThreads to a default value - w = (t+2)*100; - h = 200; - Canvas c(-1, -1, w, h, "Progress Bar Example"); - c.run(progressBarFunction, t); -} diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile deleted file mode 100644 index 8f0f83322..000000000 --- a/src/tests/testProgressBar/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testProgressBar - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testProgressBar - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testProgressBar/testProgressBar.cpp b/src/tests/testProgressBar/testProgressBar.cpp deleted file mode 100644 index fc7e8bd98..000000000 --- a/src/tests/testProgressBar/testProgressBar.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * testProgressBar.cpp - * - * Usage: ./testProgressBar - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command line argument for the - * number of threads to use. - * \details - * - Compute and store the necessary information in order to draw the ProgressBar object - * (x-coordinate, y-coordinate, width, height, minimum, maximum, and the number of segments). - * - Create the ProgressBar object with the information calculated in the previous step. - * - Set the progress of drawing the ProgressBar object and store it in: \b progress. - * - While the Canvas is open: - * - Sleep the Canvas' internal timer until the next draw cycle. - * - Increment the progress so far. - * - For 0 to the number of segments: - * - Update the ProgressBar object. - * . - * - Draw the ProgressBar onto the Canvas. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void progressBarFunction(Canvas& can, int numThreads) { - const int X = 100, Y = X, W = can.getWindowWidth()-X*2, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; - ProgressBar pb(X,Y,W,H,MIN,MAX,SEGS); - int progress = 0; - for (int i = 0; i < SEGS; ++i) - can.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - ++progress; - for (int i = 0; i < SEGS; ++i) - pb.update(progress+i*(MAX/SEGS),i); - can.drawProgress(&pb); - } -} - -//Takes in the number of threads to use as a command line argument for the Canvas, defaulting to 8. -//( see http://www.cplusplus.com/articles/DEN36Up4/ ) -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : 8; - int w; - int h; - if (t <= 0 || 10 < t) //Checked the passed threadNumber if it is valid - t = 8; //If not, set numThreads to a default value - w = (t+2)*100; - h = 200; - Canvas c(-1, -1, w, h, "Progress Bar Example"); - c.run(progressBarFunction, t); -} diff --git a/src/tests/testProjectiles.cpp b/src/tests/testProjectiles.cpp deleted file mode 100644 index 75ef3f439..000000000 --- a/src/tests/testProjectiles.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * testProjectiles.cpp - * - * Usage: ./testProjectiles - */ - -#include "tsgl.h" - -using namespace tsgl; - -/*! - * \brief Target practice mini-game! - * \details Creates the target practice mini-game in this way: - * - Get coordinates for the target based off of the window size. - * - Set a coordinate changer for the target's x coordinate (so that it moves from left to right on the screen). - * - Get the center of the Canvas. - * - Get the number of targets (10). - * - Get the score counter. - * - Get the colors for the target (outer, middle, and bulls-eye center). - * - Bind the mouse so that when one clicks and hits the target in the middle then - * the score counter goes up. - * - While the Canvas is still open: - * - Sleep the internal timer of the Canvas until the next drawing loop is ready to be drawn. - * - Increment the target's x-coordinate by the coordinate changer. - * - Move the target up vertically by coordinate changer for its y-coordinate. - * - Draw the actual target. - * - If the target hits the middle of the screen: - * - Invert the y change so that the target moves downward. - * . - * - If the target goes off screen to the right: - * - Decrement the number of targets left. - * - Reset the targetX, targetY, and the coordinate changer for y. - * . - * - If we hit a target in the middle: - * - Increment the score. - * - Change the hit to false; - * - Move the target off of the screen. - * . - * - If the number of targets is less than 5: - * - Speed up the movement of the remaining targets. - * . - * - If the number of targets left is 0: - * - Print out the score, clear the Canvas one last time, and get out of the drawing loop. - * . - * . - * . - * \param can Reference to the Canvas being drawn on. - */ -void projectileFunction(Canvas& can) { - const int WINDOW_W = can.getWindowWidth(); - int targetX = 0, targetY = WINDOW_W / 2, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion - int centerX = WINDOW_W / 2;// centerY = WINDOW_H / 2; //Center of screen - int numberOfTargets = 10; //Number of targets - bool hit = false; //Determine if the target has been hit - int score = 0; //Score - ColorInt blueTarget(0, 0, 255); - ColorInt redTarget(255, 0, 0); //Color for targets - ColorInt yellowTarget(255, 255, 0); - //binding to left mouse button - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&hit, &can, &targetX, &targetY]() { - if((can.getMouseX() <= targetX && can.getMouseY() <= targetY) || can.getMouseY() == targetY) { - hit = true; //We hit the target - } - }); - - //Create circles of target and add to Canvas - Circle * blueCircle = new Circle(targetX, targetY, 50, BLUE); //Outer circle - Circle * redCircle = new Circle(targetX, targetY, 30, RED); //Middle - Circle * yellowCircle = new Circle(targetX, targetY, 10, YELLOW); //Inner - can.add(blueCircle); can.add(redCircle); can.add(yellowCircle); - - //Draw loop - while(can.isOpen()) { - can.sleep(); - can.clearProcedural(); - - targetX += coordinateChangerX; //Horizontal movement - targetY -= coordinateChangerY; //Vertical movement - - if(hit) { //If we hit a target.... - score++; - targetX = WINDOW_W + 60; - hit = false; - } - if(targetX >= centerX) { //If it hits the middle of the screen, invert the vertical direction - coordinateChangerY = -1; - } - if(targetX > WINDOW_W + 60) { //If the target is off the screen - numberOfTargets--; //Decrement the number of targets left - targetX = 0; //Reset the target and inverter - targetY = 200; - coordinateChangerY = 1; - } - if(numberOfTargets <= 5) { //Mix it up if there are only five targets left (speed up the targets) - coordinateChangerX = 6; - } - //Move each circle to the target's location - blueCircle->setCenter(targetX, targetY); - redCircle->setCenter(targetX, targetY); - yellowCircle->setCenter(targetX, targetY); - if(numberOfTargets == 0) { //End game - std::cout << "Your score: " << score << std::endl; - can.remove(redCircle); - can.remove(blueCircle); - can.remove(yellowCircle); - numberOfTargets--; - } - } - - delete redCircle; - delete blueCircle; - delete yellowCircle; -} - -//Takes command-line arguments for the width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Click the Target!"); //Can change the size of the window - c.setBackgroundColor(BLACK); - c.run(projectileFunction); -} diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile deleted file mode 100644 index 68e0bf69a..000000000 --- a/src/tests/testProjectiles/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for Projectiles - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testProjectiles - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testProjectiles/testProjectiles.cpp b/src/tests/testProjectiles/testProjectiles.cpp deleted file mode 100644 index 1b3c0dd35..000000000 --- a/src/tests/testProjectiles/testProjectiles.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * testProjectiles.cpp - * - * Usage: ./testProjectiles - */ - -#include "tsgl.h" - -using namespace tsgl; - -/*! - * \brief Target practice mini-game! - * \details Creates the target practice mini-game in this way: - * - Get coordinates for the target based off of the window size. - * - Set a coordinate changer for the target's x coordinate (so that it moves from left to right on the screen). - * - Get the center of the Canvas. - * - Get the number of targets (10). - * - Get the score counter. - * - Get the colors for the target (outer, middle, and bulls-eye center). - * - Bind the mouse so that when one clicks and hits the target in the middle then - * the score counter goes up. - * - While the Canvas is still open: - * - Sleep the internal timer of the Canvas until the next drawing loop is ready to be drawn. - * - Increment the target's x-coordinate by the coordinate changer. - * - Move the target up vertically by coordinate changer for its y-coordinate. - * - Draw the actual target. - * - If the target hits the middle of the screen: - * - Invert the y change so that the target moves downward. - * . - * - If the target goes off screen to the right: - * - Decrement the number of targets left. - * - Reset the targetX, targetY, and the coordinate changer for y. - * . - * - If we hit a target in the middle: - * - Increment the score. - * - Change the hit to false; - * - Move the target off of the screen. - * . - * - If the number of targets is less than 5: - * - Speed up the movement of the remaining targets. - * . - * - If the number of targets left is 0: - * - Print out the score, clear the Canvas one last time, and get out of the drawing loop. - * . - * . - * . - * \param can Reference to the Canvas being drawn on. - */ -void projectileFunction(Canvas& can) { - const int WINDOW_W = can.getWindowWidth(); - int targetX = 0, targetY = WINDOW_W / 2, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion - int centerX = WINDOW_W / 2;// centerY = WINDOW_H / 2; //Center of screen - int numberOfTargets = 10; //Number of targets - bool hit = false; //Determine if the target has been hit - int score = 0; //Score - ColorInt blueTarget(0, 0, 255); - ColorInt redTarget(255, 0, 0); //Color for targets - ColorInt yellowTarget(255, 255, 0); - //binding to left mouse button - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&hit, &can, &targetX, &targetY]() { - if((can.getMouseX() <= targetX && can.getMouseY() <= targetY) || can.getMouseY() == targetY) { - hit = true; //We hit the target - } - }); - - //Create circles of target and add to Canvas - Circle * blueCircle = new Circle(targetX, targetY, 50, BLUE); //Outer circle - Circle * redCircle = new Circle(targetX, targetY, 30, RED); //Middle - Circle * yellowCircle = new Circle(targetX, targetY, 10, YELLOW); //Inner - can.add(blueCircle); can.add(redCircle); can.add(yellowCircle); - - //Draw loop - while(can.isOpen()) { - can.sleep(); - can.clearProcedural(); - - targetX += coordinateChangerX; //Horizontal movement - targetY -= coordinateChangerY; //Vertical movement - - if(hit) { //If we hit a target.... - score++; - targetX = WINDOW_W + 60; - hit = false; - } - if(targetX >= centerX) { //If it hits the middle of the screen, invert the vertical direction - coordinateChangerY = -1; - } - if(targetX > WINDOW_W + 60) { //If the target is off the screen - numberOfTargets--; //Decrement the number of targets left - targetX = 0; //Reset the target and inverter - targetY = 200; - coordinateChangerY = 1; - } - if(numberOfTargets <= 5) { //Mix it up if there are only five targets left (speed up the targets) - coordinateChangerX = 6; - } - //Move each circle to the target's location - blueCircle->setCenter(targetX, targetY); - redCircle->setCenter(targetX, targetY); - yellowCircle->setCenter(targetX, targetY); - if(numberOfTargets == 0) { //End game - std::cout << "Your score: " << score << std::endl; - can.remove(redCircle); - can.remove(blueCircle); - can.remove(yellowCircle); - numberOfTargets--; - } - } - - delete redCircle; - delete blueCircle; - delete yellowCircle; -} - -//Takes command-line arguments for the width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - Canvas c(-1, -1, w, h, "Click the Target!", BLACK); //Can change the size of the window - c.run(projectileFunction); -} diff --git a/src/tests/testPyramid.cpp b/src/tests/testPyramid.cpp deleted file mode 100644 index ac0db8692..000000000 --- a/src/tests/testPyramid.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * testPyramid.cpp - * - * Usage: ./testPyramid - */ - -#include -#include - -using namespace tsgl; - -void pyramidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); - Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); - // printf("%f\n", testPyramid2->getAlpha()); - // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testPyramid2->getAlpha()); - // testPyramid2->setColor(colors); - // printf("%f\n", testPyramid2->getAlpha()); - can.add(testPyramid); - can.add(testPyramid2); - can.add(testPyramid3); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testPyramid->setCenterX(sin(rotation)*200); - // testPyramid->setCenterY(cos(rotation)*200); - // testPyramid->setCenterZ(sin(rotation)*100); - // testPyramid->setYaw(rotation*45); - testPyramid->setPitch(rotation*45); - testPyramid2->setPitch(rotation*45); - testPyramid3->setPitch(rotation*45); - // testPyramid->setRoll(sin(rotation*45)*100+101); - // testPyramid->setHeight(sin(rotation)*100+101); - // testPyramid->setRadius(sin(rotation)*100+101); - // if(testPyramid->getHeight() >= 200) { - // delta = -5; - // } - // if(testPyramid->getHeight() <= 5) { - // delta = 5; - // } - // testPyramid->changeHeightBy(delta); - // if(testPyramid->getRadius() >= 200) { - // delta = -5; - // } - // if(testPyramid->getRadius() <= 5) { - // delta = 5; - // } - // testPyramid->changeRadiusBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testPyramid->setColor(RED); - } else { - testPyramid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testPyramid; - delete testPyramid2; - delete testPyramid3; -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Basic Pyramid"); - c.setBackgroundColor(BLACK); - c.run(pyramidFunction); -} \ No newline at end of file diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile deleted file mode 100644 index c4721dd36..000000000 --- a/src/tests/testPyramid/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testPyramid - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testPyramid - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testPyramid/testPyramid.cpp b/src/tests/testPyramid/testPyramid.cpp deleted file mode 100644 index fdbf30f6a..000000000 --- a/src/tests/testPyramid/testPyramid.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * testPyramid.cpp - * - * Usage: ./testPyramid - */ - -#include -#include - -using namespace tsgl; - -void pyramidFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); - Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); - // printf("%f\n", testPyramid2->getAlpha()); - // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testPyramid2->getAlpha()); - // testPyramid2->setColor(colors); - // printf("%f\n", testPyramid2->getAlpha()); - can.add(testPyramid); - can.add(testPyramid2); - can.add(testPyramid3); - float rotation = 0.0f; - GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testPyramid->setCenterX(sin(rotation)*200); - // testPyramid->setCenterY(cos(rotation)*200); - // testPyramid->setCenterZ(sin(rotation)*100); - // testPyramid->setYaw(rotation*45); - testPyramid->setPitch(rotation*45); - testPyramid2->setPitch(rotation*45); - testPyramid3->setPitch(rotation*45); - // testPyramid->setRoll(sin(rotation*45)*100+101); - // testPyramid->setHeight(sin(rotation)*100+101); - // testPyramid->setRadius(sin(rotation)*100+101); - // if(testPyramid->getHeight() >= 200) { - // delta = -5; - // } - // if(testPyramid->getHeight() <= 5) { - // delta = 5; - // } - // testPyramid->changeHeightBy(delta); - // if(testPyramid->getRadius() >= 200) { - // delta = -5; - // } - // if(testPyramid->getRadius() <= 5) { - // delta = 5; - // } - // testPyramid->changeRadiusBy(delta); - if (rotation*45 >= 360) { - if (boolean) { - testPyramid->setColor(RED); - } else { - testPyramid->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testPyramid; - delete testPyramid2; - delete testPyramid3; -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Basic Pyramid", BLACK); - c.run(pyramidFunction); -} \ No newline at end of file diff --git a/src/tests/testReaderWriter.cpp b/src/tests/testReaderWriter.cpp deleted file mode 100644 index 86019887c..000000000 --- a/src/tests/testReaderWriter.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/** - * testReaderWriter.cpp contains the code to run the Readers-Writers Problem animation using TSGL and POSIX threads. - * The program utilizes Reader and Writer classes as well as a custom monitor class to hold the shared data. - * Usage: ./ReaderWriter - * can be 'w' for writer priority or 'r' for reader priority and defaults to writer priority - * should be 's' for the starved versions, or anything else for the balanced timing - */ - -//#include -#include -#include -#include "ReaderWriter/Reader.h" -#include "ReaderWriter/Writer.h" -#include "ReaderWriter/RWDatabase.h" -#include "ReaderWriter/Lock.h" -#include "ReaderWriter/RLock.h" -#include "ReaderWriter/WLock.h" -#include "ReaderWriter/FLock.h" -using namespace tsgl; - -//Constants -const int WINDOW_WIDTH = 600, WINDOW_HEIGHT = 800, MARGIN = 45; //Size of Canvas and margin around data - -int main(int argc, char* argv[]) { - - if( argc == 1) { - std::cout << "\nTo run the program with different values, use the format:\n\t./ReaderWriter " - << "\nwhere is w or r for reader or writer priority lock and \n\t is s for starving lower priority threads or b for the more balanced version." << std::endl; - } - - //Number of readers is the first argument or defaults to 6 - int numReaders = ( (argc > 1) && (atoi(argv[1]) > 0) && (atoi(argv[1]) <= 9) ) ? atoi(argv[1]) : 6; - //Number of writers is the second argument or defaults to 6 - int numWriters = ( (argc > 2) && (atoi(argv[2]) > 0) && (atoi(argv[2]) <= 9) ) ? atoi(argv[2]) : 6; - - //Start Reader-Writer visualization - Canvas can(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Reader-Writer", 1.0f/2); //Canvas to draw on - - //Start the visualization - can.start(); - can.setBackgroundColor(WHITE); - - //Create monitor - Lock * lock; - wstring lockString; //String description of lock style - int maxItems = floor(RWThread::dataWidth / RWThread::width) * floor(RWThread::dataHeight / RWThread::width); - RWDatabase* database = new RWDatabase(maxItems); - if( argc > 3 && *argv[3] == 'r' ) { - //Reader preference - lock = new RLock(database); - lockString = L"Reader priority"; - } else if (argc > 3 && *argv[3] == 'w' ) { - //Writer preference - lock = new WLock(database); - lockString = L"Writer priority"; - } else { - lock = new FLock(database); - lockString = L"Fair priority"; - } - - Reader ** readers = new Reader*[numReaders]; //Array of Readers - Writer ** writers = new Writer*[numWriters]; //Array of Writers - - //Create labels - can.drawRectangle(RWThread::dataX-MARGIN, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth+2*MARGIN, RWThread::dataHeight, GRAY); - can.drawRectangle(RWThread::dataX, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth, RWThread::dataHeight, DARKGRAY); // draw data area - can.drawLine(RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY, BLACK); - can.drawLine(RWThread::dataX-MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX-MARGIN*2.5, RWThread::dataY, BLACK); - can.drawText(lockString, 100, RWThread::dataY + 40, 20, BLACK); - can.drawText(L"Numbers indicate", WINDOW_WIDTH-200, RWThread::dataY + 40, 20, BLACK); - can.drawText(L"counts of reads/writes", WINDOW_WIDTH-200, RWThread::dataY + 60, 20, BLACK); - can.drawText(L"Writers", 72, 60, 24, BLACK); - can.drawText(L"Readers", WINDOW_WIDTH-140, 60, 24, BLACK); - can.drawText(L"Shared Data Store", 226, 692, 20, BLACK); - - //Create and rotate more labels - can.drawText(L"Thinking", 484, 127, 28, GRAY, "", PI/2); - can.drawText(L"Waiting", 423, 127, 28, GRAY, "", PI/2); - can.drawText(L"Thinking", 14, 127, 28, GRAY, "", -PI/2); - can.drawText(L"Waiting", 88, 127, 28, GRAY, "", -PI/2); - - //Fill the Reader and Writer arrays with their objects - for(int i = 0; i < numReaders; i++) { - readers[i] = new Reader(*database, *lock, i, can); //Reader created - } - for(int i = 0; i < numWriters; i++) { - writers[i] = new Writer(*database, *lock, i, can); //Writer created - } - - //Check if using starved version - //Starves Readers if there are at least 3 Writers - //Nearly starves Writers with 3 or more Readers - if( argc > 4 && *argv[4] == 's' ) { //Set for starved possibility - if( *argv[3] == 'r' ) { //Readers mostly starve Writers - RWThread::WAIT_MIN = 0; - RWThread::WAIT_RANGE = 20; - RWThread::access_wait *= 20.0; - } else { //Writers starve Readers - RWThread::WAIT_MIN = 2; - RWThread::WAIT_RANGE = 10; - } - } //else change nothing - - srand(time(NULL)); //Seed random number generator for colors and wait times - - can.bindToButton(TSGL_SPACE, TSGL_PRESS, []() { // toggle pause when spacebar is pressed - RWThread::paused = !RWThread::paused; - }); - - //Start the Reader and Writer pthreads - for(int i = 0; i < numWriters; i++) { - writers[i]->start(); - sleep(0.1); - } - for(int i = 0; i < numReaders; i++) { - readers[i]->start(); - sleep(0.1); - } - - can.wait(); //Wait for the main Canvas to be closed - - //End threads - for(int i = 0; i < numReaders; i++) { - readers[i]->join(); - } - for(int i = 0; i < numWriters; i++) { - writers[i]->join(); - } - - //Cleanup - delete [] readers; - delete [] writers; - readers = NULL; - writers = NULL; - - return 0; -} diff --git a/src/tests/testRectangle.cpp b/src/tests/testRectangle.cpp deleted file mode 100644 index 89a6a9e46..000000000 --- a/src/tests/testRectangle.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * testRectangle.cpp - * - * Usage: ./testRectangle - */ - -#include -#include - -using namespace tsgl; - -void rectangleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), - ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // rectangle->setCenterX(200); - // rectangle->setRotationPoint(0,0,0); - // printf("%f\n", rectangle->getAlpha()); - // rectangle->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", rectangle->getAlpha()); - // rectangle->setColor(colors); - // printf("%f\n", rectangle->getAlpha()); - can.add(rectangle); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // rectangle->setCenterX(sin(floatVal/90)*100); - // rectangle->setCenterY(sin(floatVal/90)*100); - // rectangle->setCenterZ(sin(floatVal/90)*100); - // rectangle->setYaw(floatVal); - // rectangle->setPitch(floatVal); - // rectangle->setRoll(floatVal); - // rectangle->setWidth(sin(floatVal/90) *100 + 100); - // rectangle->setHeight(sin(floatVal/90) *100 + 200); - // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { - // delta *= -1; - // } - // rectangle->changeWidthBy(delta); - // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { - // delta *= -1; - // } - // rectangle->changeHeightBy(delta); - // if (delta > 0) { - // rectangle->setColor(colors); - // } else { - // rectangle->setColor(RED); - // } - floatVal += 1; - } - - delete rectangle; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Rectangle"); - c.setBackgroundColor(BLACK); - c.run(rectangleFunction); -} \ No newline at end of file diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile deleted file mode 100644 index 5e0cf7fe5..000000000 --- a/src/tests/testRectangle/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testRectangle - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testRectangle - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testRectangle/testRectangle.cpp b/src/tests/testRectangle/testRectangle.cpp deleted file mode 100644 index c83e94fa6..000000000 --- a/src/tests/testRectangle/testRectangle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * testRectangle.cpp - * - * Usage: ./testRectangle - */ - -#include -#include - -using namespace tsgl; - -void rectangleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), - ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); - // rectangle->setCenterX(200); - // rectangle->setRotationPoint(0,0,0); - // printf("%f\n", rectangle->getAlpha()); - // rectangle->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", rectangle->getAlpha()); - // rectangle->setColor(colors); - // printf("%f\n", rectangle->getAlpha()); - can.add(rectangle); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // rectangle->setCenterX(sin(floatVal/90)*100); - // rectangle->setCenterY(sin(floatVal/90)*100); - // rectangle->setCenterZ(sin(floatVal/90)*100); - // rectangle->setYaw(floatVal); - // rectangle->setPitch(floatVal); - // rectangle->setRoll(floatVal); - // rectangle->setWidth(sin(floatVal/90) *100 + 100); - // rectangle->setHeight(sin(floatVal/90) *100 + 200); - // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { - // delta *= -1; - // } - // rectangle->changeWidthBy(delta); - // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { - // delta *= -1; - // } - // rectangle->changeHeightBy(delta); - // if (delta > 0) { - // rectangle->setColor(colors); - // } else { - // rectangle->setColor(RED); - // } - floatVal += 1; - } - - delete rectangle; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Rectangle", BLACK); - c.run(rectangleFunction); -} \ No newline at end of file diff --git a/src/tests/testRegularPolygon.cpp b/src/tests/testRegularPolygon.cpp deleted file mode 100644 index d3b7f54ef..000000000 --- a/src/tests/testRegularPolygon.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * testRegularPolygon.cpp - * - * Usage: ./testRegularPolygon - */ - -#include -#include - -using namespace tsgl; - -void rpFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); - // rp->setCenterX(200); - // rp->setRotationPoint(0,0,0); - // printf("%f\n", rp->getAlpha()); - // rp->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", rp->getAlpha()); - // rp->setColor(colors); - // printf("%f\n", rp->getAlpha()); - can.add(rp); - float floatVal = 0.0f; - GLfloat delta = 5; - while (can.isOpen()) { - can.sleep(); - // rp->setCenterX(sin(floatVal/90)*100); - // rp->setCenterY(sin(floatVal/90)*100); - // rp->setCenterZ(sin(floatVal/90)*100); - // rp->setYaw(floatVal); - // rp->setPitch(floatVal); - // rp->setRoll(floatVal); - // rp->setRadius(sin(floatVal/90)*100 + 300); - if (rp->getRadius() > 300 || rp->getRadius() < 100) { - delta *= -1; - } - rp->changeRadiusBy(delta); - if (delta > 0) { - rp->setColor(colors); - } else { - rp->setColor(RED); - } - floatVal += 1; - } - - delete rp; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon"); - c.setBackgroundColor(BLACK); - c.run(rpFunction); -} \ No newline at end of file diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile deleted file mode 100644 index 9383cba89..000000000 --- a/src/tests/testRegularPolygon/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testRegularPolygon - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testRegularPolygon - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testRegularPolygon/testRegularPolygon.cpp b/src/tests/testRegularPolygon/testRegularPolygon.cpp deleted file mode 100644 index 9a4dd7ea9..000000000 --- a/src/tests/testRegularPolygon/testRegularPolygon.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * testRegularPolygon.cpp - * - * Usage: ./testRegularPolygon - */ - -#include -#include - -using namespace tsgl; - -void rpFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); - // rp->setCenterX(200); - // rp->setRotationPoint(0,0,0); - // printf("%f\n", rp->getAlpha()); - // rp->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", rp->getAlpha()); - // rp->setColor(colors); - // printf("%f\n", rp->getAlpha()); - can.add(rp); - float floatVal = 0.0f; - GLfloat delta = 5; - while (can.isOpen()) { - can.sleep(); - // rp->setCenterX(sin(floatVal/90)*100); - // rp->setCenterY(sin(floatVal/90)*100); - // rp->setCenterZ(sin(floatVal/90)*100); - // rp->setYaw(floatVal); - // rp->setPitch(floatVal); - // rp->setRoll(floatVal); - // rp->setRadius(sin(floatVal/90)*100 + 300); - if (rp->getRadius() > 300 || rp->getRadius() < 100) { - delta *= -1; - } - rp->changeRadiusBy(delta); - if (delta > 0) { - rp->setColor(colors); - } else { - rp->setColor(RED); - } - floatVal += 1; - } - - delete rp; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon", BLACK); - c.run(rpFunction); -} \ No newline at end of file diff --git a/src/tests/testScreenshot.cpp b/src/tests/testScreenshot.cpp deleted file mode 100644 index 96ce86a03..000000000 --- a/src/tests/testScreenshot.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * testScreenshot.cpp - * - * Usage: ./testScreenshot - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a bunch of triangles and outputs each frame to an image. - * \details - * - Declare and initialize variables to keep track of each of three vertices for a triangle. - * - Set the Canvas to record screenshots for 30 seconds (1800 frames). - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - Set the old coordinates to last frame's middle ones. - * - Set the middle coordinates to last frame's new ones. - * - Set the new coordinates to a random position on the Canvas. - * - Draw a triangle on the canvas with the given coordinates and a random color. - * . - * . - * \note The details of the recordForNumFrames() function are handled automatically in Canvas, and - * are by default written to the i frames/ directory. - * \param can Reference to the Canvas being drawn to. - */ -void screenShotFunction(Cart& can) { - int xNew = can.getWindowWidth() / 2, yNew = can.getWindowHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; - can.recordForNumFrames(FPS * 30); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - xOld = xMid; - yOld = yMid; - xMid = xNew; - yMid = yNew; - xNew = rand() % can.getWindowWidth(); - yNew = rand() % can.getWindowHeight(); - can.drawTriangle(xOld, yOld, xMid, yMid, xNew, yNew, Colors::randomColor(), true); - } -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 800; //Width and height - int h = (argc > 2) ? atoi(argv[2]) : 600; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 800; - h = 600; - } - Cart c(-1, -1, w, h, 0, 0, 800, 600,"Screenshot Test"); - c.run(screenShotFunction); -} diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile deleted file mode 100644 index bfc7c5018..000000000 --- a/src/tests/testScreenshot/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testScreenshot - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testScreenshot - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testScreenshot/testScreenshot.cpp b/src/tests/testScreenshot/testScreenshot.cpp deleted file mode 100644 index 96ce86a03..000000000 --- a/src/tests/testScreenshot/testScreenshot.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * testScreenshot.cpp - * - * Usage: ./testScreenshot - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws a bunch of triangles and outputs each frame to an image. - * \details - * - Declare and initialize variables to keep track of each of three vertices for a triangle. - * - Set the Canvas to record screenshots for 30 seconds (1800 frames). - * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. - * - While the Canvas is open: - * - Sleep the internal timer until the Canvas is ready to draw. - * - Set the old coordinates to last frame's middle ones. - * - Set the middle coordinates to last frame's new ones. - * - Set the new coordinates to a random position on the Canvas. - * - Draw a triangle on the canvas with the given coordinates and a random color. - * . - * . - * \note The details of the recordForNumFrames() function are handled automatically in Canvas, and - * are by default written to the i frames/ directory. - * \param can Reference to the Canvas being drawn to. - */ -void screenShotFunction(Cart& can) { - int xNew = can.getWindowWidth() / 2, yNew = can.getWindowHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; - can.recordForNumFrames(FPS * 30); - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - xOld = xMid; - yOld = yMid; - xMid = xNew; - yMid = yNew; - xNew = rand() % can.getWindowWidth(); - yNew = rand() % can.getWindowHeight(); - can.drawTriangle(xOld, yOld, xMid, yMid, xNew, yNew, Colors::randomColor(), true); - } -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 800; //Width and height - int h = (argc > 2) ? atoi(argv[2]) : 600; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 800; - h = 600; - } - Cart c(-1, -1, w, h, 0, 0, 800, 600,"Screenshot Test"); - c.run(screenShotFunction); -} diff --git a/src/tests/testSeaUrchin.cpp b/src/tests/testSeaUrchin.cpp deleted file mode 100644 index ba703305e..000000000 --- a/src/tests/testSeaUrchin.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * testSeaUrchin.cpp - * - * Usage: ./testSeaUrchin - */ - -#include "tsgl.h" -#include - -#include "SeaUrchin/SeaUrchin.h" - -using namespace tsgl; - -// possible FIXME: sometimes this results in a segmentation fault. no discernable pattern+ - -/*! - * \brief Displays different colored sea urchins and takes a command-line argument. - * \details Displays different colored sea urchins where each sea urchin is drawn by a thread - * (the command-line argument is the number of threads to use). - * It is drawn as follows: - * - The sea urchins are drawn in a similar way as the line fan in testLineFan. - * - A class contains all of the necessary data and methods to draw the sea urchins. - * - A parallel block is created and the process is forked. - * - The current thread's id number is stored. - * - When you create the SeaUrchin object: - * - Set old x and y-coordinate values and increment them based off of the current thread's id number. - * - Set new x and y-coordinate values to 0. - * - Assign a color to the current thread. - * . - * - While the Canvas is open: - * - Sleep the Canvas' internal timer until the next draw cycle. - * - Clear the Canvas. - * - When you draw the SeaUrchin onto the Canvas: - * - Set a delta value to make the SeaUrchins spin. - * - For i to the number of spokes of a SeaUrchin: - * - Calculate the new x and y-coordinate values based off of the delta value and the old x and y-coordinate values. - * - Draw a spoke of the SeaUrchin on the Canvas. - * . - * . - * . - * - If the Canvas has been closed, output a message to the console saying "YOU KILLED MY SEA URCHINS! :'(" . - * . - * \param can Reference to the Canvas being drawn on. - * \param threads Reference to the number of threads to use in the process. - * \see testLineFan, SeaUrchin class. - */ -void seaUrchinFunction(Canvas& can, int threads) { - #pragma omp parallel num_threads(threads) - { - SeaUrchin s(can, omp_get_thread_num()); //A thread gets a Sea Urchin - while(can.isOpen()) { //Draw loop - can.sleep(); - s.move(can); //And draws it - } - } -} - -int main(int argc, char * argv[]) { - int nthreads = (argc > 1) ? atoi(argv[1]) : 16; //Number of threads - clamp(nthreads,1,16); //Max number of threads is 16 - Canvas c(-1, -1, 885, 230, "Sea Urchins!", FRAME * 2); - c.setBackgroundColor(BLACK); - c.run(seaUrchinFunction, nthreads); -} - diff --git a/src/tests/testShakerSort.cpp b/src/tests/testShakerSort.cpp deleted file mode 100644 index bef6a0f43..000000000 --- a/src/tests/testShakerSort.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * testShakerSort.cpp - * - * Usage: ./testShakerSort - */ - -#include - -using namespace tsgl; - -/*! - * \brief Provides a visualization for a basic (and slow) shaker sort. - * \details - * - The size of the list of items ( \b SIZE ) and the number of iterations per frame ( \b IPF ) are set. - * - An integer array of size \b SIZE is allocated. - * - A flag \b goingUp is set. - * - Our integer array is filled with random integers under the Canvas' height. - * - The background color is set to gray for visibility. - * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. - * - While the Canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - If the minimum sorted element is greater than or equals the maximum, we're done. - * - At a rate of \b IPF times a second: - * - If we're going up and the element above us is less than us, swap. - * - If we're going down and the element below us is less than us, swap. - * - Move in the current direction, inverting our direction if we've reached the minimum / maximum. - * . - * - Pause the animation. - * - Clear the Canvas. - * - From 0 to \b SIZE: - * - Get the height of each element in the integer array. - * - Draw it as a yellow rectangle if it's the currently-computed member; draw it red otherwise. - * . - * - Resume the animation. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void shakerSortFunction(Canvas& can) { - const int SIZE = 550, // Size of the data pool (set to 550 by default) - IPF = 50; // Iterations per frame - Rectangle* rectangles[SIZE]; // Array to store the data - float numbers[SIZE]; // Array to store the data - int pos = 0, min = 0, max = SIZE - 1, lastSwap = 0; - float temp; - bool goingUp = true; - int canWidth = (can.getWindowWidth() > can.getDisplayWidth()) ? can.getDisplayWidth() : can.getWindowWidth(); - float start = canWidth * -.45; - float rectangleWidth = canWidth * .9 / SIZE; - for (int i = 0; i < SIZE; i++) { - rectangles[i] = new Rectangle(start + i * rectangleWidth, 0, 0, rectangleWidth, saferand(1,can.getWindowHeight()*.9), 0, 0, 0, RED); - numbers[i] = rectangles[i]->getHeight(); - can.add(rectangles[i]); - } - can.setBackgroundColor(GRAY); - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - if (min >= max) { // We are done sorting. - // If we don't call wait(), we segfault. If we call return instead, rectangles[] doesn't get deallocated. - // return would be fine if we hadn't allocated memory in this method to which Canvas needed access. - can.wait(); - } - for (int i = 0; i < IPF; i++) { - if (goingUp) { - if (numbers[pos] > numbers[pos + 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos + 1];; - numbers[pos + 1] = temp; - lastSwap = pos; - } - if (pos >= max) { - pos = max; - max = (lastSwap < max) ? lastSwap : max - 1; - goingUp = !goingUp; - } else - pos++; - } else { - if (numbers[pos] < numbers[pos - 1]) { - temp = numbers[pos]; - numbers[pos] = numbers[pos - 1]; - numbers[pos - 1] = temp; - lastSwap = pos; - } - if (pos <= min) { - pos = min; - min = (lastSwap > min) ? lastSwap : min + 1; - goingUp = !goingUp; - } else - pos--; - } - } - ColorFloat color; - can.pauseDrawing(); //Tell the Canvas to stop updating the screen temporarily - for (int i = 0; i < SIZE; i++) { - color = (i == pos) ? YELLOW : RED; - rectangles[i]->setColor(color); - rectangles[i]->setHeight(numbers[i]); - } - can.resumeDrawing(); //Tell the Canvas it can resume drawing - } - - for (int i = 0; i < SIZE; i++) { - delete rectangles[i]; - } -} - -//Takes in command line arguments for the window width and height -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; - if (w <= 0 || h <= 0) { // Checked the passed width and height if they are valid - w = 1300; h = 900; // If not, set the width and height to a default value - } - Canvas c(-1, -1, w, h, "Shaker Sort"); - c.run(shakerSortFunction); -} diff --git a/src/tests/testSolarSystem.cpp b/src/tests/testSolarSystem.cpp deleted file mode 100644 index c35dc459f..000000000 --- a/src/tests/testSolarSystem.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * testSolarSystem.cpp - * - * Usage: ./testSolarSystem - */ - -#include -#include - -using namespace tsgl; - -void ssFunction(Canvas& can) { - Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); - Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); - Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); - Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); - Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); - Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); - Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); - Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); - Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); - Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); - - mercury->setRotationPoint(0,0,0); - venus->setRotationPoint(0,0,0); - earth->setRotationPoint(0,0,0); - mars->setRotationPoint(0,0,0); - jupiter->setRotationPoint(0,0,0); - saturn->setRotationPoint(0,0,0); - saturnRings->setRotationPoint(0,0,0); - uranus->setRotationPoint(0,0,0); - neptune->setRotationPoint(0,0,0); - - can.add(sun); - can.add(mercury); - can.add(venus); - can.add(earth); - can.add(mars); - can.add(jupiter); - can.add(saturn); - can.add(saturnRings); - can.add(uranus); - can.add(neptune); - float rotation = 0.0f; - while (can.isOpen()) { - can.sleep(); - sun->setPitch(rotation); - mercury->setPitch(rotation * 4); - venus->setPitch(rotation * 3 / 2); - earth->setPitch(rotation); - mars->setPitch(rotation/2); - jupiter->setPitch(rotation/12); - saturn->setPitch(rotation/30); - saturnRings->setPitch(rotation/30); - uranus->setPitch(rotation/90); - neptune->setPitch(rotation/180); - rotation += 1; - } - - delete sun; - delete mercury; - delete venus; - delete earth; - delete mars; - delete jupiter; - delete saturn; - delete saturnRings; - delete uranus; - delete neptune; -} - -int main(int argc, char* argv[]) { - Canvas c(0, -1, 1800, 620, "Solar System"); - c.setBackgroundColor(BLACK); - c.run(ssFunction); -} \ No newline at end of file diff --git a/src/tests/testSpectrogram.cpp b/src/tests/testSpectrogram.cpp deleted file mode 100644 index 99eb133ae..000000000 --- a/src/tests/testSpectrogram.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testSpectrogram.cpp - * - * Usage: ./testSpectrogram - */ - -#include - -#include -using namespace tsgl; - -/*! - * \brief Displays a spectrogram. - * \details Shows a spectrogram for the colors of a chosen photo. - * - The window width and height are stored for ease of use. - * - The image is drawn onto the Canvas. - * - A Spectrogram object is created which will display the spectrogram. - * - Sleep the Canvas for 1/10th of a second. - * - Have a counter that keeps track of the number of pixels that we have checked (for their color). - * - A parallel block is created and the process is forked. - * - The thread id and the actual number of threads spawned are stored. - * - Start and stopping points for the thread are calculated and stored. - * - For the starting point to the ending point of rendering: - * - If the Canvas is open: - * - Sleep the internal timer until the next draw cycle. - * - For 0 to the width of the Canvas: - * - Get a hue color based off of the current pixel. - * - Check for a weird case where we can end up with a NaN error (Not a Number). - * - Draw the point onto the Canvas. - * . - * - Update the number of pixels checked in an parallel atomic block (to avoid conflicts). - * - Draw the results on the Spectrogram object. - * . - * . - * - Have the Canvas sleep for: FRAME seconds. - * - Draw the chosen image onto the Canvas. - * - Close the Spectrogram object. - * . - * \param can Reference to the Canvas object to draw to. - * \param fname The name of the file to get the image from. - */ -void spectrogramFunction(Canvas& can, std::string fname) { - const int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - can.drawImage(fname, 0, 0, cww, cwh); - Spectrogram sp(VERTICAL,500); - can.sleepFor(0.1f); -// can.recordForNumFrames(FPS); - unsigned numChecked = 0; - #pragma omp parallel num_threads(omp_get_num_procs()) - { - int tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); - int blockSize = cwh / nthreads; - int start = tid * blockSize; - int end = (tid == (nthreads-1)) ? cwh : (tid+1) * blockSize; - for (int j = start; j < end; ++j) { - if (can.isOpen()) { - can.sleep(); - ColorHSV hsv; - for (int i = 0; i < cww; ++i) { - hsv = can.getPoint(i,j); - if (hsv.H == hsv.H) { //Check for NAN - sp.updateLocked(MAX_COLOR*hsv.H/6,1.0f,0.8f); - sp.updateCritical(MAX_COLOR*hsv.H/6,1.0f,0.8f); - } - can.drawPoint(i,j,ColorHSV(0.0f,0.0f,hsv.V)); - } - #pragma omp atomic - ++numChecked; - sp.draw((float)(1.0f*numChecked)/cwh); - } - } - } - // can.sleepFor(FRAME); - can.drawImage(fname, 0, 0, cww, cwh); - sp.finish(); -} - -//Takes command-line arguments for the file name of the picture to use in the spectrogram function -int main(int argc, char* argv[]) { - std::string fname = argc > 1 ? argv[1] : "../assets/pics/colorful_cars.jpg"; - int w, h; - TextureHandler::getDimensions(fname,w,h); - Canvas c(-1, Canvas::getDisplayHeight()-h, w, h ,"Spectrogram"); - c.run(spectrogramFunction, fname); -} diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile deleted file mode 100644 index dfaa0fba6..000000000 --- a/src/tests/testSpectrogram/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testSpectrogram - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testSpectrogram - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrogram/testSpectrogram.cpp b/src/tests/testSpectrogram/testSpectrogram.cpp deleted file mode 100644 index 99eb133ae..000000000 --- a/src/tests/testSpectrogram/testSpectrogram.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testSpectrogram.cpp - * - * Usage: ./testSpectrogram - */ - -#include - -#include -using namespace tsgl; - -/*! - * \brief Displays a spectrogram. - * \details Shows a spectrogram for the colors of a chosen photo. - * - The window width and height are stored for ease of use. - * - The image is drawn onto the Canvas. - * - A Spectrogram object is created which will display the spectrogram. - * - Sleep the Canvas for 1/10th of a second. - * - Have a counter that keeps track of the number of pixels that we have checked (for their color). - * - A parallel block is created and the process is forked. - * - The thread id and the actual number of threads spawned are stored. - * - Start and stopping points for the thread are calculated and stored. - * - For the starting point to the ending point of rendering: - * - If the Canvas is open: - * - Sleep the internal timer until the next draw cycle. - * - For 0 to the width of the Canvas: - * - Get a hue color based off of the current pixel. - * - Check for a weird case where we can end up with a NaN error (Not a Number). - * - Draw the point onto the Canvas. - * . - * - Update the number of pixels checked in an parallel atomic block (to avoid conflicts). - * - Draw the results on the Spectrogram object. - * . - * . - * - Have the Canvas sleep for: FRAME seconds. - * - Draw the chosen image onto the Canvas. - * - Close the Spectrogram object. - * . - * \param can Reference to the Canvas object to draw to. - * \param fname The name of the file to get the image from. - */ -void spectrogramFunction(Canvas& can, std::string fname) { - const int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - can.drawImage(fname, 0, 0, cww, cwh); - Spectrogram sp(VERTICAL,500); - can.sleepFor(0.1f); -// can.recordForNumFrames(FPS); - unsigned numChecked = 0; - #pragma omp parallel num_threads(omp_get_num_procs()) - { - int tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); - int blockSize = cwh / nthreads; - int start = tid * blockSize; - int end = (tid == (nthreads-1)) ? cwh : (tid+1) * blockSize; - for (int j = start; j < end; ++j) { - if (can.isOpen()) { - can.sleep(); - ColorHSV hsv; - for (int i = 0; i < cww; ++i) { - hsv = can.getPoint(i,j); - if (hsv.H == hsv.H) { //Check for NAN - sp.updateLocked(MAX_COLOR*hsv.H/6,1.0f,0.8f); - sp.updateCritical(MAX_COLOR*hsv.H/6,1.0f,0.8f); - } - can.drawPoint(i,j,ColorHSV(0.0f,0.0f,hsv.V)); - } - #pragma omp atomic - ++numChecked; - sp.draw((float)(1.0f*numChecked)/cwh); - } - } - } - // can.sleepFor(FRAME); - can.drawImage(fname, 0, 0, cww, cwh); - sp.finish(); -} - -//Takes command-line arguments for the file name of the picture to use in the spectrogram function -int main(int argc, char* argv[]) { - std::string fname = argc > 1 ? argv[1] : "../assets/pics/colorful_cars.jpg"; - int w, h; - TextureHandler::getDimensions(fname,w,h); - Canvas c(-1, Canvas::getDisplayHeight()-h, w, h ,"Spectrogram"); - c.run(spectrogramFunction, fname); -} diff --git a/src/tests/testSpectrum.cpp b/src/tests/testSpectrum.cpp deleted file mode 100644 index 63fb5f125..000000000 --- a/src/tests/testSpectrum.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * testSpectrum.cpp - * - * Usage: ./testSpectrum - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws the full spectrum across the x, y, and time dimensions at the given framerate - * and a static number of threads using OMP and takes in a command line argument for the number of threads to use. - * \details - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - A parallel block is set up with OMP, using one thread per processor. - * - The actual number of threads spawned is stored in: \b nthreads. - * - Check if the argument for the number of threads is valid: - * - If it is less than or equal to 0, use the number of threads that we can use with OMP. - * - If it is greater than the number of threads that we can use, use only the number of threads that we can use with OMP. - * - Else, its valid and use that many threads. - * . - * - While the canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - An outer for loop from 0 to 255 is set up in a per-thread striping pattern. - * - An inner for loop runs from 0 to the 255 normally. - * - Each point is drawn to the canvas, with x, y, and time representing red, green, and blue respectively. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void spectrumFunction(Canvas& can, int numberOfThreads) { - #pragma omp parallel num_threads(omp_get_num_procs()) - { - int holder = omp_get_num_threads(); //Temp variable - int nthreads = 0; //Actual number of threads - if (numberOfThreads <= 0) { //Check if the argument for the number of threads is valid - nthreads = holder; //If not, use the number of threads that we can use with OMP - } else if(numberOfThreads > holder) { - nthreads = holder; - } else { - nthreads = numberOfThreads; //Else, use the argument as the number of threads - } - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = omp_get_thread_num(); i < NUM_COLORS; i += nthreads) - for (int j = 0; j < NUM_COLORS; j++) - can.drawPoint(i, j, ColorInt(i, j, can.getReps() % NUM_COLORS)); - } - } -} - -//Takes command-line arguments for the number of threads to use -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); //Number of threads to use - Canvas c(-1,-1,255,255,"The Color Spectrum"); - c.run(spectrumFunction, t); -} - diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile deleted file mode 100644 index 760443e7b..000000000 --- a/src/tests/testSpectrum/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testSpectrum - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testSpectrum - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrum/testSpectrum.cpp b/src/tests/testSpectrum/testSpectrum.cpp deleted file mode 100644 index 63fb5f125..000000000 --- a/src/tests/testSpectrum/testSpectrum.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * testSpectrum.cpp - * - * Usage: ./testSpectrum - */ - -#include -#include - -using namespace tsgl; - -/*! - * \brief Draws the full spectrum across the x, y, and time dimensions at the given framerate - * and a static number of threads using OMP and takes in a command line argument for the number of threads to use. - * \details - * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). - * - A parallel block is set up with OMP, using one thread per processor. - * - The actual number of threads spawned is stored in: \b nthreads. - * - Check if the argument for the number of threads is valid: - * - If it is less than or equal to 0, use the number of threads that we can use with OMP. - * - If it is greater than the number of threads that we can use, use only the number of threads that we can use with OMP. - * - Else, its valid and use that many threads. - * . - * - While the canvas is open: - * - The internal timer sleeps until the next frame is ready to be drawn. - * - An outer for loop from 0 to 255 is set up in a per-thread striping pattern. - * - An inner for loop runs from 0 to the 255 normally. - * - Each point is drawn to the canvas, with x, y, and time representing red, green, and blue respectively. - * . - * . - * \param can Reference to the Canvas being drawn to. - * \param numberOfThreads Reference to the number of threads to use. - */ -void spectrumFunction(Canvas& can, int numberOfThreads) { - #pragma omp parallel num_threads(omp_get_num_procs()) - { - int holder = omp_get_num_threads(); //Temp variable - int nthreads = 0; //Actual number of threads - if (numberOfThreads <= 0) { //Check if the argument for the number of threads is valid - nthreads = holder; //If not, use the number of threads that we can use with OMP - } else if(numberOfThreads > holder) { - nthreads = holder; - } else { - nthreads = numberOfThreads; //Else, use the argument as the number of threads - } - while (can.isOpen()) { - can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (int i = omp_get_thread_num(); i < NUM_COLORS; i += nthreads) - for (int j = 0; j < NUM_COLORS; j++) - can.drawPoint(i, j, ColorInt(i, j, can.getReps() % NUM_COLORS)); - } - } -} - -//Takes command-line arguments for the number of threads to use -int main(int argc, char* argv[]) { - int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); //Number of threads to use - Canvas c(-1,-1,255,255,"The Color Spectrum"); - c.run(spectrumFunction, t); -} - diff --git a/src/tests/testSphere.cpp b/src/tests/testSphere.cpp deleted file mode 100644 index e2e9a8600..000000000 --- a/src/tests/testSphere.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * testSphere.cpp - * - * Usage: ./testSphere - */ - -#include -#include - -using namespace tsgl; - -void sphereFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); - Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); - testSphere->setIsOutlined(true); - testSphere2->setIsOutlined(true); - // printf("%f\n", testSphere->getAlpha()); - // testSphere->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testSphere->getAlpha()); - // testSphere->setColor(colors); - // printf("%f\n", testSphere->getAlpha()); - can.add(testSphere); - can.add(testSphere2); - float rotation = 0.0f; - // GLfloat delta = 5; - bool boolean = true; - while (can.isOpen()) { - can.sleep(); - // testSphere->setCenterX(sin(rotation) * 100); - // testSphere->setCenterY(cos(rotation) * 100); - // testSphere->setCenterZ(sin(rotation) * 100); - // testSphere->setYaw(rotation*45); - // testSphere->setPitch(rotation*45); - testSphere->setRoll(rotation*45); - // testSphere->setRadius(cos(rotation) * 100 +101); - // if(testSphere->getRadius() >= 200) { - // delta = -5; - // } - // if(testSphere->getRadius() <= 500) { - // delta = 5; - // } - // testSphere->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - // printf("%f\n", rotation*45); - if (rotation*45 >= 360) { - if (boolean) { - testSphere->setColor(RED); - } else { - testSphere->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - - rotation+=0.01; - } - - delete testSphere; - delete testSphere2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Sphere"); - c.setBackgroundColor(BLACK); - c.run(sphereFunction); -} \ No newline at end of file diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile deleted file mode 100644 index d7a7189d6..000000000 --- a/src/tests/testSphere/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testSphere - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testSphere - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testSphere/testSphere.cpp b/src/tests/testSphere/testSphere.cpp deleted file mode 100644 index 3d602168a..000000000 --- a/src/tests/testSphere/testSphere.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * testSphere.cpp - * - * Usage: ./testSphere - */ - -#include -#include - -using namespace tsgl; - -void sphereFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); - Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); - testSphere->setIsOutlined(true); - testSphere2->setIsOutlined(true); - // printf("%f\n", testSphere->getAlpha()); - // testSphere->setColor(ColorFloat(1,0,0,0.9)); - // printf("%f\n", testSphere->getAlpha()); - // testSphere->setColor(colors); - // printf("%f\n", testSphere->getAlpha()); - can.add(testSphere); - can.add(testSphere2); - float rotation = 0.0f; - // GLfloat delta = 5; - bool boolean = true; - while (can.isOpen()) { - can.sleep(); - // testSphere->setCenterX(sin(rotation) * 100); - // testSphere->setCenterY(cos(rotation) * 100); - // testSphere->setCenterZ(sin(rotation) * 100); - // testSphere->setYaw(rotation*45); - // testSphere->setPitch(rotation*45); - testSphere->setRoll(rotation*45); - // testSphere->setRadius(cos(rotation) * 100 +101); - // if(testSphere->getRadius() >= 200) { - // delta = -5; - // } - // if(testSphere->getRadius() <= 500) { - // delta = 5; - // } - // testSphere->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - // printf("%f\n", rotation*45); - if (rotation*45 >= 360) { - if (boolean) { - testSphere->setColor(RED); - } else { - testSphere->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - - rotation+=0.01; - } - - delete testSphere; - delete testSphere2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Sphere", BLACK); - c.run(sphereFunction); -} \ No newline at end of file diff --git a/src/tests/testSquare.cpp b/src/tests/testSquare.cpp deleted file mode 100644 index e58b677a7..000000000 --- a/src/tests/testSquare.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * testSquare.cpp - * - * Usage: ./testSquare - */ - -#include -#include - -using namespace tsgl; - -void squareFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,200,0,0,0,colors); - Square * square2 = new Square(-250,0,0,200,0,0,0,RED); - // square->setCenterX(200); - // square->setRotationPoint(0,0,0); - can.add(square); - can.add(square2); - float floatVal = 0.0f; - GLfloat delta = 0.05; - bool ss = false; - while (can.isOpen()) { - can.sleep(); - // square->setCenterX(sin(floatVal/90) * 100); - // square->setCenterY(sin(floatVal/90) * 100); - // square->setCenterZ(sin(floatVal/90) * 100); - // square->setYaw(floatVal); - // square->setPitch(floatVal); - // square->setRoll(floatVal); - // square->setSideLength(sin(floatVal/90) * 100 + 300); - // if (square->getSideLength() > 300 || square->getSideLength() < 100) { - // delta *= -1; - // } - // square->changeSideLengthBy(delta); - // if (delta > 0) { - // square->setColor(colors); - // } else { - // square->setColor(RED); - // } - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - floatVal += 1; - } - - delete square; - delete square2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Square"); - c.setBackgroundColor(BLACK); - c.run(squareFunction); -} \ No newline at end of file diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile deleted file mode 100644 index 339f7d968..000000000 --- a/src/tests/testSquare/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testSquare - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testSquare - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testSquare/testSquare.cpp b/src/tests/testSquare/testSquare.cpp deleted file mode 100644 index 56eaf740a..000000000 --- a/src/tests/testSquare/testSquare.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * testSquare.cpp - * - * Usage: ./testSquare - */ - -#include -#include - -using namespace tsgl; - -void squareFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Square * square = new Square(0,0,0,200,0,0,0,colors); - Square * square2 = new Square(-250,0,0,200,0,0,0,RED); - // square->setCenterX(200); - // square->setRotationPoint(0,0,0); - can.add(square); - can.add(square2); - float floatVal = 0.0f; - GLfloat delta = 0.05; - bool ss = false; - while (can.isOpen()) { - can.sleep(); - // square->setCenterX(sin(floatVal/90) * 100); - // square->setCenterY(sin(floatVal/90) * 100); - // square->setCenterZ(sin(floatVal/90) * 100); - // square->setYaw(floatVal); - // square->setPitch(floatVal); - // square->setRoll(floatVal); - // square->setSideLength(sin(floatVal/90) * 100 + 300); - // if (square->getSideLength() > 300 || square->getSideLength() < 100) { - // delta *= -1; - // } - // square->changeSideLengthBy(delta); - // if (delta > 0) { - // square->setColor(colors); - // } else { - // square->setColor(RED); - // } - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - floatVal += 1; - } - - delete square; - delete square2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Square", BLACK); - c.run(squareFunction); -} \ No newline at end of file diff --git a/src/tests/testStar.cpp b/src/tests/testStar.cpp deleted file mode 100644 index 14afe96c6..000000000 --- a/src/tests/testStar.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * testStar.cpp tests displaying the Star class - * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. - */ -#include -using namespace tsgl; - -void starFunction(Canvas& c) { - ColorFloat * colors = new ColorFloat[400]; - colors[0] = ColorFloat(1,0,0,1); - for(int i = 1; i < 10; i ++) { - // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); - colors[i] = ColorFloat(0,0,1,1); - } - - Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); - // s1->setColor(RED); - c.add(s1); - - float floatVal = 0.0f; - GLfloat delta = 5; - while (c.isOpen()) { - c.sleep(); - // s1->setCenterX(sin(floatVal/90) * 100); - // s1->setCenterY(sin(floatVal/90) * 100); - // s1->setCenterZ(sin(floatVal/90) * 100); - // s1->setYaw(floatVal); - // s1->setPitch(floatVal); - // s1->setRoll(floatVal); - // s1->setRadius(sin(floatVal/90) * 100 + 300); - if (s1->getRadius() > 300 || s1->getRadius() < 100) { - delta *= -1; - } - s1->changeRadiusBy(delta); - if (delta > 0) { - s1->setColor(colors); - } else { - s1->setColor(RED); - } - floatVal += 1; - } - - delete[] colors; - // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Stars"); - c.run(starFunction); -} \ No newline at end of file diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile deleted file mode 100644 index 90f33c627..000000000 --- a/src/tests/testStar/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testStar - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testStar - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testStar/testStar.cpp b/src/tests/testStar/testStar.cpp deleted file mode 100644 index 14afe96c6..000000000 --- a/src/tests/testStar/testStar.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * testStar.cpp tests displaying the Star class - * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. - */ -#include -using namespace tsgl; - -void starFunction(Canvas& c) { - ColorFloat * colors = new ColorFloat[400]; - colors[0] = ColorFloat(1,0,0,1); - for(int i = 1; i < 10; i ++) { - // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); - colors[i] = ColorFloat(0,0,1,1); - } - - Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); - // s1->setColor(RED); - c.add(s1); - - float floatVal = 0.0f; - GLfloat delta = 5; - while (c.isOpen()) { - c.sleep(); - // s1->setCenterX(sin(floatVal/90) * 100); - // s1->setCenterY(sin(floatVal/90) * 100); - // s1->setCenterZ(sin(floatVal/90) * 100); - // s1->setYaw(floatVal); - // s1->setPitch(floatVal); - // s1->setRoll(floatVal); - // s1->setRadius(sin(floatVal/90) * 100 + 300); - if (s1->getRadius() > 300 || s1->getRadius() < 100) { - delta *= -1; - } - s1->changeRadiusBy(delta); - if (delta > 0) { - s1->setColor(colors); - } else { - s1->setColor(RED); - } - floatVal += 1; - } - - delete[] colors; - // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. -} - -int main(int argc, char* argv[]) { - int w = 1000; - int h = 1000; - Canvas c(-1, -1, w, h, "Stars"); - c.run(starFunction); -} \ No newline at end of file diff --git a/src/tests/testText.cpp b/src/tests/testText.cpp deleted file mode 100644 index fc07072d1..000000000 --- a/src/tests/testText.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * testText.cpp - * - * Usage: ./testSpectrum - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a Canvas. - * \details - * - We changed it so that now a default text font is loaded if one is not specified. - * - We draw a few lines of text in various colors using drawText(). - * . - * \param can Reference to the Canvas being drawn to. - * \param font The font of the text. - */ -void textFunction(Canvas& can, std::string font) { - // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); - // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - // 32, BLUE); - // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); - can.add(lowercase); - Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); - can.add(uppercase); - Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); - // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); - can.add(random); - // can.add(rec); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { - random->setText(L"Glorgaborg"); - // random->setColor(RED); - // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); - // random->setFontSize(100); - }); - - bool ss = false; - float rotation = 0.0f; - while(can.isOpen()) { - can.sleep(); - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - // random->setCenterX(sin(rotation)*200); - // random->setCenterY(cos(rotation)*200); - // random->setCenterZ(sin(rotation)*100); - // random->setYaw(rotation*45); - random->setPitch(rotation*45); - // random->setRoll(rotation*45); - rotation+=0.01; - } - delete lowercase; - delete uppercase; - delete random; - -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; - std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "Text on a Canvas"); - c.run(textFunction, font); -} diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile deleted file mode 100644 index 41fa2cd44..000000000 --- a/src/tests/testText/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testText - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testText - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testText/testText.cpp b/src/tests/testText/testText.cpp deleted file mode 100644 index fc07072d1..000000000 --- a/src/tests/testText/testText.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * testText.cpp - * - * Usage: ./testSpectrum - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a Canvas. - * \details - * - We changed it so that now a default text font is loaded if one is not specified. - * - We draw a few lines of text in various colors using drawText(). - * . - * \param can Reference to the Canvas being drawn to. - * \param font The font of the text. - */ -void textFunction(Canvas& can, std::string font) { - // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); - // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - // 32, BLUE); - // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); - Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); - can.add(lowercase); - Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); - can.add(uppercase); - Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); - // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); - can.add(random); - // can.add(rec); - - can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { - random->setText(L"Glorgaborg"); - // random->setColor(RED); - // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); - // random->setFontSize(100); - }); - - bool ss = false; - float rotation = 0.0f; - while(can.isOpen()) { - can.sleep(); - // if (can.getFrameNumber() > 50 && !ss) { - // can.takeScreenShot(); - // ss = true; - // } - // random->setCenterX(sin(rotation)*200); - // random->setCenterY(cos(rotation)*200); - // random->setCenterZ(sin(rotation)*100); - // random->setYaw(rotation*45); - random->setPitch(rotation*45); - // random->setRoll(rotation*45); - rotation+=0.01; - } - delete lowercase; - delete uppercase; - delete random; - -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font -int main(int argc, char * argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; - std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "Text on a Canvas"); - c.run(textFunction, font); -} diff --git a/src/tests/testTextCart.cpp b/src/tests/testTextCart.cpp deleted file mode 100644 index 77f5956a7..000000000 --- a/src/tests/testTextCart.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextCart.cpp - * - * Usage: ./testTextCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a CartesianCanvas. - * \details Same as textFunction, but with a CartesianCanvas and black text. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - * \param font The font of the text. - */ -void textCartFunction(Cart& can, std::string font) { - can.setFont(font); - can.drawText(L"A long time ago, in a galaxy far, far away.", 1, 2, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 1, 1.9, 32, BLACK); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 1, 1.8, 32, BLACK); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 1, 1.7, - 32, BLACK); - can.drawText(L"Of *what* exactly that extraordinary event was.", 1, 1.6, 32, BLACK); - can.drawText(L"And to that I say...oh well.", 1, 1.5, 32, BLACK); -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font file for the text -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w - 200.0f; - std::string font = argv[3]; //Font - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.75 * w; - } - Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); - c.run(textCartFunction, font); -} diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile deleted file mode 100644 index 5963dd8bb..000000000 --- a/src/tests/testTextCart/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testTextCart - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testTextCart - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testTextCart/testTextCart.cpp b/src/tests/testTextCart/testTextCart.cpp deleted file mode 100644 index 77f5956a7..000000000 --- a/src/tests/testTextCart/testTextCart.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextCart.cpp - * - * Usage: ./testTextCart - */ - -#include - -using namespace tsgl; - -/*! - * \brief Draws some text on a CartesianCanvas. - * \details Same as textFunction, but with a CartesianCanvas and black text. - * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). - * \param font The font of the text. - */ -void textCartFunction(Cart& can, std::string font) { - can.setFont(font); - can.drawText(L"A long time ago, in a galaxy far, far away.", 1, 2, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 1, 1.9, 32, BLACK); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 1, 1.8, 32, BLACK); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 1, 1.7, - 32, BLACK); - can.drawText(L"Of *what* exactly that extraordinary event was.", 1, 1.6, 32, BLACK); - can.drawText(L"And to that I say...oh well.", 1, 1.5, 32, BLACK); -} - -//Takes command-line arguments for the width and height of the screen -//as well as for the font file for the text -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75*w - 200.0f; - std::string font = argv[3]; //Font - if(w <= 0 || h <= 0) { //Check validity of width and height - w = 1.2 * Canvas::getDisplayHeight(); - h = 0.75 * w; - } - Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); - c.run(textCartFunction, font); -} diff --git a/src/tests/testTextTwo.cpp b/src/tests/testTextTwo.cpp deleted file mode 100644 index b6ef8060e..000000000 --- a/src/tests/testTextTwo.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextTwo.cpp - * - * Usage: ./testTextTwo - */ - -#include - -using namespace tsgl; - -/** - * \brief Tests to see if text is still drawn if a font is not specified. - * \details Same as textFunction, but with the setFont line deleted. - * \param can Reference to the Canvas being drawn to. - */ -void textFunctionTwo(Canvas& can) { - ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); - ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); - ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); - - can.drawText(L"A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 16, 150, 32, RED); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - 32, BLUE); - can.drawText(L"Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - can.drawText(L"And to that I say...oh well.", 16, 550, 32, WHITE); -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 300.0f; - if(w <= 0 || h <= 0) { //Check the validity of the width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "More Text on a Canvas"); - c.run(textFunctionTwo); -} diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile deleted file mode 100644 index a230e8978..000000000 --- a/src/tests/testTextTwo/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testTextTwo - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testTextTwo - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testTextTwo/testTextTwo.cpp b/src/tests/testTextTwo/testTextTwo.cpp deleted file mode 100644 index b6ef8060e..000000000 --- a/src/tests/testTextTwo/testTextTwo.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * testTextTwo.cpp - * - * Usage: ./testTextTwo - */ - -#include - -using namespace tsgl; - -/** - * \brief Tests to see if text is still drawn if a font is not specified. - * \details Same as textFunction, but with the setFont line deleted. - * \param can Reference to the Canvas being drawn to. - */ -void textFunctionTwo(Canvas& can) { - ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); - ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); - ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); - - can.drawText(L"A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); - can.drawText(L"Something extraordinary happened.", 16, 150, 32, RED); - can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); - can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, - 32, BLUE); - can.drawText(L"Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); - can.drawText(L"And to that I say...oh well.", 16, 550, 32, WHITE); -} - -//Takes command-line arguments for the width and height of the screen -int main(int argc, char * argv[]) { - //Width and height - int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 300.0f; - if(w <= 0 || h <= 0) { //Check the validity of the width and height - w = 1.2f*Canvas::getDisplayHeight(); - h = 0.75f*w; - } - Canvas c(-1, -1, w, h, "More Text on a Canvas"); - c.run(textFunctionTwo); -} diff --git a/src/tests/testTransparency.cpp b/src/tests/testTransparency.cpp deleted file mode 100644 index c852b3e20..000000000 --- a/src/tests/testTransparency.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * testTransparency.cpp - * - * Usage: ./testTransparency - */ - -#include -#include - -using namespace tsgl; - -void transparencyFunction(Canvas& can) { - Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); - Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); - Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); - can.add(cube2); - can.add(cube); - can.add(rec); - - float rotation = 0.0f; - while (can.isOpen()) { - can.sleep(); - cube2->setCenterZ(150 * cos(rotation)); - rotation += 0.1; - } -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Transparency"); - c.setBackgroundColor(BLACK); - c.run(transparencyFunction); -} \ No newline at end of file diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile deleted file mode 100644 index 44792324d..000000000 --- a/src/tests/testTransparency/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testTransparency - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testTransparency - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testTransparency/testTransparency.cpp b/src/tests/testTransparency/testTransparency.cpp deleted file mode 100644 index efb7867d3..000000000 --- a/src/tests/testTransparency/testTransparency.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * testTransparency.cpp - * - * Usage: ./testTransparency - */ - -#include -#include - -using namespace tsgl; - -void transparencyFunction(Canvas& can) { - Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); - Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); - Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); - can.add(cube2); - can.add(cube); - can.add(rec); - - float rotation = 0.0f; - while (can.isOpen()) { - can.sleep(); - cube2->setCenterZ(150 * cos(rotation)); - rotation += 0.1; - } -} - -int main(int argc, char* argv[]) { - Canvas c(-1, -1, 1024, 620, "Transparency", BLACK); - c.run(transparencyFunction); -} \ No newline at end of file diff --git a/src/tests/testTriangle.cpp b/src/tests/testTriangle.cpp deleted file mode 100644 index af80c2314..000000000 --- a/src/tests/testTriangle.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * testTriangle.cpp - * - * Usage: ./testTriangle - */ - -#include -#include - -using namespace tsgl; - -void triangleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); - Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); - // triangle->setCenterX(200); - // triangle->setRotationPoint(0,0,0); - can.add(triangle); - can.add(triangle2); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // triangle->setCenterX(sin(floatVal/90) * 100); - // triangle->setCenterY(sin(floatVal/90) * 100); - // triangle->setCenterZ(sin(floatVal/90) * 100); - // triangle->setYaw(floatVal); - // triangle->setPitch(floatVal); - // triangle->setRoll(floatVal); - if (floatVal < 200) { - triangle->setColor(colors); - } else { - triangle->setColor(RED); - if (floatVal > 400) { - floatVal = 0; - } - } - floatVal += 1; - } - - delete triangle; - delete triangle2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Triangle"); - c.setBackgroundColor(BLACK); - c.run(triangleFunction); -} \ No newline at end of file diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile deleted file mode 100644 index 53cee6da5..000000000 --- a/src/tests/testTriangle/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testTriangle - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testTriangle - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testTriangle/testTriangle.cpp b/src/tests/testTriangle/testTriangle.cpp deleted file mode 100644 index f29e650cb..000000000 --- a/src/tests/testTriangle/testTriangle.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * testTriangle.cpp - * - * Usage: ./testTriangle - */ - -#include -#include - -using namespace tsgl; - -void triangleFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); - Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); - // triangle->setCenterX(200); - // triangle->setRotationPoint(0,0,0); - can.add(triangle); - can.add(triangle2); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // triangle->setCenterX(sin(floatVal/90) * 100); - // triangle->setCenterY(sin(floatVal/90) * 100); - // triangle->setCenterZ(sin(floatVal/90) * 100); - // triangle->setYaw(floatVal); - // triangle->setPitch(floatVal); - // triangle->setRoll(floatVal); - if (floatVal < 200) { - triangle->setColor(colors); - } else { - triangle->setColor(RED); - if (floatVal > 400) { - floatVal = 0; - } - } - floatVal += 1; - } - - delete triangle; - delete triangle2; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Triangle", BLACK); - c.run(triangleFunction); -} \ No newline at end of file diff --git a/src/tests/testTriangleStrip.cpp b/src/tests/testTriangleStrip.cpp deleted file mode 100644 index ab27b3838..000000000 --- a/src/tests/testTriangleStrip.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * testTriangleStrip.cpp - * - * Usage: ./testTriangleStrip - */ - -#include -#include - -using namespace tsgl; - -void triangleStripFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { 0,-50,50,-50,50,0 }; - float y[] = { -100,-50,-50,50,50,100 }; - float z[] = { 0,50,50,50,50,0 }; - TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); - // ts->setIsOutlined(true); - // ts->setCenterX(2); - ts->setRotationPoint(0,0,0); - can.add(ts); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // ts->setCenterX(sin(floatVal/90) * 100); - // ts->setCenterY(sin(floatVal/90) * 100); - // ts->setCenterZ(sin(floatVal/90) * 100); - // ts->setYaw(floatVal); - ts->setPitch(floatVal); - // ts->setRoll(floatVal); - // if (floatVal < 200) { - // ts->setColor(colors); - // } else { - // ts->setColor(RED); - // if (floatVal > 400) { - // floatVal = 0; - // } - // } - floatVal += 1; - } - - delete ts; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip"); - c.setBackgroundColor(BLACK); - c.run(triangleStripFunction); -} \ No newline at end of file diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile deleted file mode 100644 index e5f78015b..000000000 --- a/src/tests/testTriangleStrip/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testTriangleStrip - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testTriangleStrip - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testTriangleStrip/testTriangleStrip.cpp b/src/tests/testTriangleStrip/testTriangleStrip.cpp deleted file mode 100644 index dc281cd33..000000000 --- a/src/tests/testTriangleStrip/testTriangleStrip.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * testTriangleStrip.cpp - * - * Usage: ./testTriangleStrip - */ - -#include -#include - -using namespace tsgl; - -void triangleStripFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), - ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), - ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), - ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), - ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), - ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), - ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), - ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; - float x[] = { 0,-50,50,-50,50,0 }; - float y[] = { -100,-50,-50,50,50,100 }; - float z[] = { 0,50,50,50,50,0 }; - TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); - // ts->setIsOutlined(true); - // ts->setCenterX(2); - ts->setRotationPoint(0,0,0); - can.add(ts); - float floatVal = 0.0f; - GLfloat delta = 0.05; - while (can.isOpen()) { - can.sleep(); - // ts->setCenterX(sin(floatVal/90) * 100); - // ts->setCenterY(sin(floatVal/90) * 100); - // ts->setCenterZ(sin(floatVal/90) * 100); - // ts->setYaw(floatVal); - ts->setPitch(floatVal); - // ts->setRoll(floatVal); - // if (floatVal < 200) { - // ts->setColor(colors); - // } else { - // ts->setColor(RED); - // if (floatVal > 400) { - // floatVal = 0; - // } - // } - floatVal += 1; - } - - delete ts; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip", BLACK); - c.run(triangleStripFunction); -} \ No newline at end of file diff --git a/src/tests/testUnits.cpp b/src/tests/testUnits.cpp deleted file mode 100644 index f62a3271a..000000000 --- a/src/tests/testUnits.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * testUnits.cpp - * - * Usage: ./testUnits - */ - -/* testUnits.cpp runs the unit tests for the TSGL library. */ - -#include "tsgl.h" - -using namespace tsgl; - -int main() { - //Quick note about the tests... - std::cout << "NOTE: " << std::endl; - TsglDebug("This color means either a set of tests is being initiated or tests have passed."); - TsglErr("This color means tests have failed."); - //Begin Unit testing - std::cout << "Begin unit testing...." << std::endl << std::endl; - Canvas::runTests(); // Canvas (Image test included) - TextureHandler::runTests(); // TextureHandler - ConcavePolygon::runTests(); // ConcavePolygon - ConvexPolygon::runTests(); // ConvexPolygon - CartesianCanvas::runTests(); // CartesianCanvas - std::cout << std::endl; - TsglDebug("All Unit Tests have completed!"); -} diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile deleted file mode 100644 index c0ec4da0b..000000000 --- a/src/tests/testUnits/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for testUnits - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testUnits - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testUnits/testUnits.cpp b/src/tests/testUnits/testUnits.cpp deleted file mode 100644 index f62a3271a..000000000 --- a/src/tests/testUnits/testUnits.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * testUnits.cpp - * - * Usage: ./testUnits - */ - -/* testUnits.cpp runs the unit tests for the TSGL library. */ - -#include "tsgl.h" - -using namespace tsgl; - -int main() { - //Quick note about the tests... - std::cout << "NOTE: " << std::endl; - TsglDebug("This color means either a set of tests is being initiated or tests have passed."); - TsglErr("This color means tests have failed."); - //Begin Unit testing - std::cout << "Begin unit testing...." << std::endl << std::endl; - Canvas::runTests(); // Canvas (Image test included) - TextureHandler::runTests(); // TextureHandler - ConcavePolygon::runTests(); // ConcavePolygon - ConvexPolygon::runTests(); // ConvexPolygon - CartesianCanvas::runTests(); // CartesianCanvas - std::cout << std::endl; - TsglDebug("All Unit Tests have completed!"); -} diff --git a/src/tests/testVoronoi.cpp b/src/tests/testVoronoi.cpp deleted file mode 100644 index d0a05d6e9..000000000 --- a/src/tests/testVoronoi.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * testVoronoi.cpp - * - * Usage: ./testVoronoi - */ - -/* testVoronoi.cpp contains multiple functions that display a Voronoi diagram in similar fashions. */ - -#include "Voronoi/Voronoi.h" -#include "Voronoi/ShadedVoronoi.h" - -using namespace tsgl; - -/*! - * \brief Draws a randomly generated Voronoi diagram, using OMP and private variables - * ( see http://en.wikipedia.org/wiki/Voronoi_diagram ). - * \details - * - The data and methods for drawing are stored in a class. - * - When you create an instance of the class: - * - The Canvas's dimensions are stored in local constants. - * - The number of control points are predetermined and stored a protected class instance variable. - * - We seed the random number generator with the time. - * - We allocate arrays for x and y coordinates for each of the points. - * - We allocate an array of k-values for each pixel on the Canvas. - * - For each control point: - * - Fill the x-coordinate and y-coordinate arrays with random values (thereby randomizing the locations - * of the control points). - * . - * - Seed the random number generator again with the time. - * - We initialize variables for the top, right, left, and bottom corner colors. - * - For each control point: - * - We get its x coordinate and y coordinate. - * - We determine its x-color based on a linear interpolation on the x-axis. - * - We determine its y-color based on a linear interpolation on the y-axis. - * - We determine its color based on an even mixture of its x-color and y-color. - * . - * . - * - When you draw: - * - The best k-value is initially set to 0. - * - We initialize variables keeping track of the best and current distances. - * - We start a parallel OMP block, allowing the system to determine the best means of parallelization. - * - For each column, we set the best k to 0. Then: - * - For each row: - * - Reset the best distance to a large value. - * - For each control point: - * - We calculate the distance from row,col to the control point. - * - If this distance is less than the best distance, we update the best distance and best-k - * (best point). - * - We set the k-value for row,col to the best-k. - * - We draw a pixel at row,col with the best-k's point color. - * - If we closed the Canvas, break. - * . - * . - * . - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void voronoiFunction(Canvas& can) { - Voronoi v1(can); //Make the Voronoi object - v1.draw(can); //Draw it on the Canvas -} - -/*! - * \brief Draws a randomly generated Voronoi diagram with fancy shading. - * \details Same principle as voronoiFunction(). Also has a class. - * - Key differences: - * - We keep track of the second best distance to each point in \b nbdist. - * - We keep track of the kvalues of each 2nd best point in the array \b kvalue2. - * - In a second post-processing loop through the screen: - * - Find the closest and 2nd closest control points to each pixel. - * - Find the distance from the pixel to the closest control point and store it in: \b d1. - * - Find the distance from the closest to the 2nd closest control point and store it in: \b kd. - * - Set \b shading to ( \b d1 / \b kd ). - * - Bind \b shading between 0 and 1, and shade the pixel with \b shading. - * - Break if the Canvas is closed. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void shadedVoronoiFunction(Canvas& can) { - ShadedVoronoi s1(can); - s1.draw(can); -} - -//Takes command line arguments for the width and height of the window -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - //Normal Voronoi - std::cout << "Regular Voronoi" << std::endl; - Canvas c1(-1, -1, w, h, "Voronoi"); - c1.run(voronoiFunction); - - //Shaded Voronoi - std::cout << "Special Voronoi" << std::endl; - Canvas c2(-1, -1, w, h, "Shaded Voronoi"); - c2.run(shadedVoronoiFunction); -} diff --git a/src/tests/test_specs.cpp b/src/tests/test_specs.cpp deleted file mode 100644 index 367badcb1..000000000 --- a/src/tests/test_specs.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "tsgl.h" - -int main(int argc, char* argv[]) { - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL); - if (!window) { - fprintf(stderr, "GLFW window creation failed."); - exit(100); - } - glfwMakeContextCurrent(window); - const GLubyte* gfxVendor = glGetString(GL_VENDOR); - std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); - - FT_Library flib = NULL; - FT_Init_FreeType(&flib); - FT_Int fmaj = 0, fmin = 0, fpatch = 0; - FT_Library_Version(flib,&fmaj,&fmin,&fpatch); - - printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - printf("GLFW version: %s\n", glfwGetVersionString()); - printf("GLEW version: %s\n", glewGetString(GLEW_VERSION)); - printf("Freetype version: %d.%d.%d\n", (int)fmaj,(int)fmin,(int)fpatch); - - glfwTerminate(); -} diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile deleted file mode 100644 index d5cb2797a..000000000 --- a/src/tests/test_specs/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for test_specs - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = test_specs - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/test_specs/test_specs.cpp b/src/tests/test_specs/test_specs.cpp deleted file mode 100644 index 367badcb1..000000000 --- a/src/tests/test_specs/test_specs.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "tsgl.h" - -int main(int argc, char* argv[]) { - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL); - if (!window) { - fprintf(stderr, "GLFW window creation failed."); - exit(100); - } - glfwMakeContextCurrent(window); - const GLubyte* gfxVendor = glGetString(GL_VENDOR); - std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); - - FT_Library flib = NULL; - FT_Init_FreeType(&flib); - FT_Int fmaj = 0, fmin = 0, fpatch = 0; - FT_Library_Version(flib,&fmaj,&fmin,&fpatch); - - printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - printf("GLFW version: %s\n", glfwGetVersionString()); - printf("GLEW version: %s\n", glewGetString(GLEW_VERSION)); - printf("Freetype version: %d.%d.%d\n", (int)fmaj,(int)fmin,(int)fpatch); - - glfwTerminate(); -} From 73e7f3d9ff195472783d2854a9b779c5e638d849 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:56:02 -0400 Subject: [PATCH 071/105] Add files via upload --- src/examples/Ballroom/testBallroom.cpp | 3 +- src/examples/Clock/testClock.cpp | 3 +- src/examples/Conway/LifeFarm.cpp | 359 ++++++++++++++++++ src/examples/Conway/LifeFarm.h | 100 +++++ src/examples/Conway/Makefile | 63 +++ src/examples/Conway/testConway.cpp | 89 +++++ src/examples/CubeRun/Makefile | 63 +++ src/examples/CubeRun/testCubeRun.cpp | 174 +++++++++ src/examples/DiningPhilosophers/Table.cpp | 3 +- src/examples/Fireworks/Arc.cpp | 108 ++++++ src/examples/Fireworks/Arc.h | 43 +++ src/examples/Fireworks/Dot.cpp | 45 +++ src/examples/Fireworks/Dot.h | 25 ++ src/examples/Fireworks/Firework.cpp | 57 +++ src/examples/Fireworks/Firework.h | 29 ++ src/examples/Fireworks/Makefile | 63 +++ src/examples/Fireworks/testFireworks.cpp | 59 +++ src/examples/ForestFire/Makefile | 63 +++ src/examples/ForestFire/testForestFire.cpp | 144 +++++++ src/examples/Langton/AntFarm.cpp | 72 ++++ src/examples/Langton/AntFarm.h | 86 +++++ src/examples/Langton/LangtonAnt.cpp | 47 +++ src/examples/Langton/LangtonAnt.h | 84 ++++ src/examples/Langton/Makefile | 63 +++ src/examples/Langton/testLangton.cpp | 183 +++++++++ src/examples/Mandelbrot/Buddhabrot.cpp | 109 ++++++ src/examples/Mandelbrot/Buddhabrot.h | 55 +++ .../Mandelbrot/GradientMandelbrot.cpp | 43 +++ src/examples/Mandelbrot/GradientMandelbrot.h | 43 +++ src/examples/Mandelbrot/Julia.cpp | 59 +++ src/examples/Mandelbrot/Julia.h | 41 ++ src/examples/Mandelbrot/Makefile | 63 +++ src/examples/Mandelbrot/Mandelbrot.cpp | 161 ++++++++ src/examples/Mandelbrot/Mandelbrot.h | 85 +++++ src/examples/Mandelbrot/Nova.cpp | 53 +++ src/examples/Mandelbrot/Nova.h | 42 ++ src/examples/Mandelbrot/testMandelbrot.cpp | 223 +++++++++++ src/examples/MergeSort/testMergeSort.cpp | 3 +- .../NewtonPendulum/testNewtonPendulum.cpp | 3 +- src/examples/Pandemic/Pandemic.cpp | 293 +++++++------- src/examples/Pandemic/Pandemic.h | 123 +++--- src/examples/Pandemic/Person.cpp | 253 ++++++------ src/examples/Pandemic/Person.h | 50 +-- src/examples/Pandemic/testPandemic.cpp | 144 ++++--- src/examples/ParallelPandemic/Makefile | 63 +++ src/examples/ParallelPandemic/Person.cpp | 212 +++++++++++ src/examples/ParallelPandemic/Person.h | 88 +++++ src/examples/ParallelPandemic/obj/Person.o | Bin 0 -> 318592 bytes src/examples/ParallelPandemic/statusEnums.h | 11 + .../ParallelPandemic/testPandemic.cpp | 326 ++++++++++++++++ src/examples/ParallelPandemic/testPerson.cpp | 33 ++ src/examples/ProducerConsumer/Consumer.cpp | 81 ++++ src/examples/ProducerConsumer/Consumer.h | 28 ++ src/examples/ProducerConsumer/Makefile | 63 +++ src/examples/ProducerConsumer/PCThread.cpp | 88 +++++ src/examples/ProducerConsumer/PCThread.h | 42 ++ src/examples/ProducerConsumer/Producer.cpp | 102 +++++ src/examples/ProducerConsumer/Producer.h | 33 ++ src/examples/ProducerConsumer/Queue.h | 289 ++++++++++++++ src/examples/ProducerConsumer/Thread.cpp | 53 +++ src/examples/ProducerConsumer/Thread.h | 35 ++ .../ProducerConsumer/testProducerConsumer.cpp | 171 +++++++++ 62 files changed, 5135 insertions(+), 457 deletions(-) create mode 100644 src/examples/Conway/LifeFarm.cpp create mode 100644 src/examples/Conway/LifeFarm.h create mode 100644 src/examples/Conway/Makefile create mode 100644 src/examples/Conway/testConway.cpp create mode 100644 src/examples/CubeRun/Makefile create mode 100644 src/examples/CubeRun/testCubeRun.cpp create mode 100644 src/examples/Fireworks/Arc.cpp create mode 100644 src/examples/Fireworks/Arc.h create mode 100644 src/examples/Fireworks/Dot.cpp create mode 100644 src/examples/Fireworks/Dot.h create mode 100644 src/examples/Fireworks/Firework.cpp create mode 100644 src/examples/Fireworks/Firework.h create mode 100644 src/examples/Fireworks/Makefile create mode 100644 src/examples/Fireworks/testFireworks.cpp create mode 100644 src/examples/ForestFire/Makefile create mode 100644 src/examples/ForestFire/testForestFire.cpp create mode 100644 src/examples/Langton/AntFarm.cpp create mode 100644 src/examples/Langton/AntFarm.h create mode 100644 src/examples/Langton/LangtonAnt.cpp create mode 100644 src/examples/Langton/LangtonAnt.h create mode 100644 src/examples/Langton/Makefile create mode 100644 src/examples/Langton/testLangton.cpp create mode 100644 src/examples/Mandelbrot/Buddhabrot.cpp create mode 100644 src/examples/Mandelbrot/Buddhabrot.h create mode 100644 src/examples/Mandelbrot/GradientMandelbrot.cpp create mode 100644 src/examples/Mandelbrot/GradientMandelbrot.h create mode 100644 src/examples/Mandelbrot/Julia.cpp create mode 100644 src/examples/Mandelbrot/Julia.h create mode 100644 src/examples/Mandelbrot/Makefile create mode 100644 src/examples/Mandelbrot/Mandelbrot.cpp create mode 100644 src/examples/Mandelbrot/Mandelbrot.h create mode 100644 src/examples/Mandelbrot/Nova.cpp create mode 100644 src/examples/Mandelbrot/Nova.h create mode 100644 src/examples/Mandelbrot/testMandelbrot.cpp create mode 100644 src/examples/ParallelPandemic/Makefile create mode 100644 src/examples/ParallelPandemic/Person.cpp create mode 100644 src/examples/ParallelPandemic/Person.h create mode 100644 src/examples/ParallelPandemic/obj/Person.o create mode 100644 src/examples/ParallelPandemic/statusEnums.h create mode 100644 src/examples/ParallelPandemic/testPandemic.cpp create mode 100644 src/examples/ParallelPandemic/testPerson.cpp create mode 100644 src/examples/ProducerConsumer/Consumer.cpp create mode 100644 src/examples/ProducerConsumer/Consumer.h create mode 100644 src/examples/ProducerConsumer/Makefile create mode 100644 src/examples/ProducerConsumer/PCThread.cpp create mode 100644 src/examples/ProducerConsumer/PCThread.h create mode 100644 src/examples/ProducerConsumer/Producer.cpp create mode 100644 src/examples/ProducerConsumer/Producer.h create mode 100644 src/examples/ProducerConsumer/Queue.h create mode 100644 src/examples/ProducerConsumer/Thread.cpp create mode 100644 src/examples/ProducerConsumer/Thread.h create mode 100644 src/examples/ProducerConsumer/testProducerConsumer.cpp diff --git a/src/examples/Ballroom/testBallroom.cpp b/src/examples/Ballroom/testBallroom.cpp index 722639ca3..faa9bbcc7 100644 --- a/src/examples/Ballroom/testBallroom.cpp +++ b/src/examples/Ballroom/testBallroom.cpp @@ -313,7 +313,6 @@ int main(int argc, char* argv[]) { int h = (argc > 2) ? atoi(argv[2]) : w; if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, w, h, "The Ballroom"); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, w, h, "The Ballroom", BLACK); c.run(ballroomFunction); } diff --git a/src/examples/Clock/testClock.cpp b/src/examples/Clock/testClock.cpp index d2fccf8b6..4435ddccd 100644 --- a/src/examples/Clock/testClock.cpp +++ b/src/examples/Clock/testClock.cpp @@ -102,7 +102,6 @@ int main(int argc, char* argv[]) { // int h = (argc > 2) ? atoi(argv[2]) : w; // if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid // w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 500, 700, "Grandfather Clock"); - c.setBackgroundColor(WHITE); + Canvas c(-1, -1, 500, 700, "Grandfather Clock", WHITE); c.run(clockFunction); } \ No newline at end of file diff --git a/src/examples/Conway/LifeFarm.cpp b/src/examples/Conway/LifeFarm.cpp new file mode 100644 index 000000000..bd6bb9ff5 --- /dev/null +++ b/src/examples/Conway/LifeFarm.cpp @@ -0,0 +1,359 @@ +/* + * LifeFarm.cpp + */ + +#include "LifeFarm.h" + +LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { + framecount = 0; + listend = 0; + width = w; + height = h; + size = w * h; + livelist = new int[size]; + int maxsize = 1+h*(1+w); + currentstate = new int[maxsize]; + for (int i = 0; i < maxsize; ++i) + currentstate[i] = 0; + nextstate = new int[maxsize]; + for (int i = 0; i < maxsize; ++i) + nextstate[i] = 0; + for (int i = 0; i < size; ++i) + livelist[i] = 0; + + currentstart = currentstate; //Pointers to the beginning of the arrays + nextstart = nextstate; + + alive = new bool*[h](); + for (int i = 0; i < h; ++i) { + alive[i] = new bool[w]; + for (int j = 0; j < w; ++j) + alive[i][j] = false; + } + if (randomize) { + for (int i = 9*h/10; i > h/10; --i) { + bool newrow = true; + for (int j = 9*w/10; j > w/10; --j) { + if ((rand() % 2) > 0) { + if (newrow) { + *currentstate = (i + 1); + ++currentstate; + newrow = false; + } + *currentstate = -(j + 1); + ++currentstate; + addAnt(j,i); + } + } + } + *currentstate = 0; + currentstate = currentstart; + } + else + initGun(); + can = c; + neighbors = new int*[h](); + for (int i = 0; i < h; ++i) + neighbors[i] = new int[w]; + bgcolor = c->getBackgroundColor(); + drawdead = false; +} + +void LifeFarm::initGun() { + int w = width/2, h = height/2; + currentstart = currentstate; + *currentstate++ = h+1; + *currentstate++ = -(w+25); + addAnt(w+25,h+1); + *currentstate++ = h+2; + *currentstate++ = -(w+25); + *currentstate++ = -(w+23); + addAnt(w+25,h+2); + addAnt(w+23,h+2); + *currentstate++ = h+3; + *currentstate++ = -(w+36); + *currentstate++ = -(w+35); + *currentstate++ = -(w+22); + *currentstate++ = -(w+21); + *currentstate++ = -(w+14); + *currentstate++ = -(w+13); + addAnt(w+36,h+3); + addAnt(w+35,h+3); + addAnt(w+22,h+3); + addAnt(w+21,h+3); + addAnt(w+14,h+3); + addAnt(w+13,h+3); + *currentstate++ = h+4; + *currentstate++ = -(w+36); + *currentstate++ = -(w+35); + *currentstate++ = -(w+22); + *currentstate++ = -(w+21); + *currentstate++ = -(w+16); + *currentstate++ = -(w+12); + addAnt(w+36,h+4); + addAnt(w+35,h+4); + addAnt(w+22,h+4); + addAnt(w+21,h+4); + addAnt(w+16,h+4); + addAnt(w+12,h+4); + *currentstate++ = h+5; + *currentstate++ = -(w+22); + *currentstate++ = -(w+21); + *currentstate++ = -(w+17); + *currentstate++ = -(w+11); + *currentstate++ = -(w+2); + *currentstate++ = -(w+1); + addAnt(w+22,h+5); + addAnt(w+21,h+5); + addAnt(w+17,h+5); + addAnt(w+11,h+5); + addAnt(w+2,h+5); + addAnt(w+1,h+5); + *currentstate++ = h+6; + *currentstate++ = -(w+25); + *currentstate++ = -(w+23); + *currentstate++ = -(w+18); + *currentstate++ = -(w+17); + *currentstate++ = -(w+15); + *currentstate++ = -(w+11); + *currentstate++ = -(w+2); + *currentstate++ = -(w+1); + addAnt(w+25,h+6); + addAnt(w+23,h+6); + addAnt(w+18,h+6); + addAnt(w+17,h+6); + addAnt(w+15,h+6); + addAnt(w+11,h+6); + addAnt(w+2,h+6); + addAnt(w+1,h+6); + *currentstate++ = h+7; + *currentstate++ = -(w+25); + *currentstate++ = -(w+17); + *currentstate++ = -(w+11); + addAnt(w+25,h+7); + addAnt(w+17,h+7); + addAnt(w+11,h+7); + *currentstate++ = h+8; + *currentstate++ = -(w+16); + *currentstate++ = -(w+12); + addAnt(w+16,h+8); + addAnt(w+12,h+8); + *currentstate++ = h+9; + *currentstate++ = -(w+14); + *currentstate++ = -(w+13); + addAnt(w+14,h+9); + addAnt(w+13,h+9); + *currentstate = 0; + currentstate = currentstart; +} + +LifeFarm::~LifeFarm() { + for (int i = 0; i < height; ++i) { + delete[] alive[i]; + delete[] neighbors[i]; + } + delete[] alive; + delete[] neighbors; + delete[] livelist; + delete[] currentstate; + delete[] nextstate; +} + +void LifeFarm::addAnt(int x, int y) { + livelist[listend++] = y*width+x; + alive[y][x] = true; +} + +void LifeFarm::moveAnts() { + moveAntsOld(); +// moveAntsNew(); +} + +void LifeFarm::moveAntsOld() { + //Compute this frame's color + const int P1 = 7, P2 = 11, P3 = 17; + // std::cout << ++framecount << std::endl; + int r = (framecount*P1/50 % 255); + if (r < 128) r = 255 - r; + int g = (framecount*P2/50 % 255); + if (g < 128) g = 255 - g; + int b = (framecount*P3/50 % 255); + if (b < 128) b = 255 - b; + ColorFloat fcolor = ColorInt(r,g,b,255); + + //Clear the each cell's neighbor list + for (int i = 0; i < height; ++i) + for (int j = 0; j < width; ++j) + neighbors[i][j] = 0; + + //Populate the neighbor list of each living cell + int tid = 0, nthreads = 1; + for (int i = tid; i < listend ; i += nthreads) { + int n = livelist[i]; + int row = n / width, col = n % width; + int xm = col - 1; + if (xm < 0) xm = width - 1; + int xp = col+1; + if (xp > width-1) xp = 0; + int ym = row-1; + if (ym < 0) ym = height - 1; + int yp = row+1; + if (yp > height-1) yp = 0; + ++neighbors[ym][xm]; + ++neighbors[row][xm]; + ++neighbors[yp][xm]; + ++neighbors[ym][col]; + ++neighbors[yp][col]; + ++neighbors[ym][xp]; + ++neighbors[row][xp]; + ++neighbors[yp][xp]; + } + + //Reset the end of the list for the next iteration + listend = 0; + + //Redraw any cell whose living status has changed, and repopulate the living list + bool lives, lived; + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++ col) { + lived = alive[row][col]; + lives = ( (neighbors[row][col] == 3) || ( lived && (neighbors[row][col] == 2) )); + if (lives != lived) { + if (lives) { + can->drawPoint(col, row, fcolor); + addAnt(col,row); + } + else if (drawdead) + can->drawPoint(col, row, bgcolor); + alive[row][col] = lives; + } else if (lives) + addAnt(col,row); + } + } +} + + +void LifeFarm::moveAntsNew() { + life(currentstate,nextstate); + //Swap pointers to the begnning of the current and next state arrays + int* temp = nextstart; + nextstart = currentstart; + currentstart = temp; + //Move the pointers to the beginning of the newly-swapped arrays + currentstate = currentstart; + nextstate = nextstart; + return; +} + +void LifeFarm::setDrawdead(bool b) { + drawdead = b; +} + + +void LifeFarm::life(int *current, int *fresh) { + //Compute this frame's color + const int P1 = 7, P2 = 11, P3 = 17; + std::cout << ++framecount << std::endl; + int r = (framecount*P1/50 % 255); + if (r < 128) r = 255 - r; + int g = (framecount*P2/50 % 255); + if (g < 128) g = 255 - g; + int b = (framecount*P3/50 % 255); + if (b < 128) b = 255 - b; + ColorFloat fcolor = ColorInt(r,g,b,255); + + unsigned bitmap; + int *next, *prev, *start; + start = fresh; + int x, y; + static bool state[1 << 9]; //Array of dead / alive states + static bool init = false; + + //Check for init [007 (octal) == 00000111 (binary) -> 3 neighbors] + if(!init) { + init = true; + //Populate a state bitmap + for(bitmap = 0; bitmap < (1<<9); bitmap++) { + for(x = y = 0; y < 9; y++) //For each cell in the 3x3 neighbor grid + if(bitmap & (1< center cell is alive] + if(x == 2 || x == 3) //If two neighbors or three neighbors, alive; else, dead + state[bitmap] = true; + else + state[bitmap] = false; + } else { //Else, bitmap is dead + if(x == 3) //If three neighbors, alive; else, dead + state[bitmap] = true; + else + state[bitmap] = false; + } + } + } + + x = y = 0; //ADDED + + prev = next = current; //Set the previous / next cell to the first cell of "this" (the old state) + bitmap = 0; //Set bitmap to 0 (empty) + *fresh = 0; //Set the first position of the new state to 0 (empty) + for(;;) { //For each row + /* did we write an X co-ordinate? */ + if(*fresh < 0) //If the next element in the new state is an x coordinate + fresh++; //Change new's pointer to the next element + if(prev == next) { //If the address of our previous and next cell are the same... + /* start a new group of rows */ + if(*next == 0) { //If out next cell is the terminator + *fresh = 0; //Set the next state of the new board to the terminator state as well + fresh = start; + return; //We're done! + } + y = *next++ + 1; //Set out y coordinate to 1 plus next's current value, and increment next (which is sorted desc.) + } else { //If our previous and next cells are different + /* move to next row and work out which ones to scan */ + if(*prev == y--) //Increment prev's pointer if it's the same as our y (after decrementing it) plus 1 + prev++; + if(*current == y) //Increment this's pointer if it's the same as our y + current++; + if(*next == y-1) //Increment next's pointer if it's the same as our y minus 1 + next++; + } + /* write new row co-ordinate */ + *fresh = y; //Write the new row coordinate + for(;;) { //For each column (cell) + /* skip to the leftmost cell */ + x = *prev; //Set our (negative) x coordinate to the max of the current values of prev, this, and next + if(x > *current) + x = *current; + if(x > *next) + x = *next; + /* end of line? */ + if(x >= 0) //If x is non-negative, this is a y coordinate; we're at the end of the line; move on! + break; + for(;;) { //For each consecutive cell + /* add a column to the bitmap */ + if(*prev == x) { //If the previous row's cell (the one directly above us) is alive + bitmap |= 0100; //OR the bitmap with 001000000 (topright) + prev++; //Increment the previous row's pointer + } + if(*current == x) { //If the current row's cell is alive + bitmap |= 0200; //OR the bitmap with 010000000 (midright) + current++; //Increment the current row's pointer + } + if(*next == x) { //If the next row's cell (the one directly below us) is alive + bitmap |= 0400; //OR the bitmap with 100000000 (bottomright) + next++; //Increment the next row's pointer + } + /* what does this bitmap indicate? */ + if(state[bitmap] && !(y > height-3 || y < 3) && !((-x) > width-3 || (-x) < 3)) { //If our bitmap is now alive + *(++fresh) = x - 1; //Increment the cell pointer of our new board, and set the next value to the current x-coordinate minus 1 + can->drawPoint(-(x), y, fcolor); //Draw it + } + else if(bitmap == 000) //If our bitmap is now empty... + break; //No more consecutive living cells; move on to the next explicitly stored pointer + /* move right */ + bitmap >>= 3; //Shave off the the leftmost three bits to move our bitmap to the right + x += 1; //Increment our x coordinate + } + } + } +} diff --git a/src/examples/Conway/LifeFarm.h b/src/examples/Conway/LifeFarm.h new file mode 100644 index 000000000..5ba61d841 --- /dev/null +++ b/src/examples/Conway/LifeFarm.h @@ -0,0 +1,100 @@ +/* + * LifeFarm.h + */ + +#ifndef ANTFARM_H_ +#define ANTFARM_H_ + +#include +#include + +using namespace tsgl; + +/*! + * \class LifeFarm + * \brief Simulate Conway's Game of Life! + * \details Contains the data and methods needed in order to simulate Conway's Game of Life. + * \details see https://en.wikipedia.org/wiki/Conway's_Game_of_Life for more details on what Conway's Game of Life is. + */ +class LifeFarm { +private: + void initGun(); + + unsigned framecount; + bool **alive; + int **neighbors; + int *livelist; + int liststart, listend; + bool drawdead; + ColorFloat bgcolor; + + int *currentstate, *nextstate; + int *currentstart, *nextstart; +public: + int width, height, size; + Canvas* can; + + /*! + * \brief Explicitly constructs a LifeFarm object. + * \details Explicit constructor for the LifeFarm class. + * \param w The width of the LifeFarm object. + * \param h The height of the LifeFarm object. + * \param can Pointer to the Canvas to draw to. + * \param randomize Determines if we should randomize the motion of the ants that are currently in the LifeFarm object. + */ + LifeFarm(int w, int h, Canvas* can, bool randomize); + + /*! + * \brief Destroy a LifeFarm object. + * \details Destructor for the LifeFarm class. + * \return Frees up any allocated memory to a LifeFarm object. + */ + ~LifeFarm(); + + /*! + * \brief Add an ant. + * \details Adds an ant to the LifeFarm object. + * \param x The x coordinate of the ant in the LifeFarm object. + * \param y The y coordinate of the ant in the LifeFarm object. + */ + void addAnt(int x, int y); + + /*! + * \brief Move the ants. + * \details Move the ants that are currently in the LifeFarm object. + * \note This method class moveAntsOld(). + * \see moveAntsOld() + */ + void moveAnts(); + + /*! + * \brief Move the ants. + * \details This method is called first in order to move the ants around in the LifeFarm object. + * \see moveAntsNew() + */ + void moveAntsOld(); + + /*! + * \brief Move the ants. + * \details This method moves the ants around to new positions. + * \see moveAntsOld() + */ + void moveAntsNew(); + + /*! + * \brief Draw "dead" ants. + * \details Determines if we should draw ants that have "died" in the game. + * \param b A boolean that determines if we should draw the dead ants or not. + */ + void setDrawdead(bool b); + + /*! + * \brief Give life to the ants! + * \details Makes the ants come alive by keeping track of their current positions and next state positions. + * \param *current A pointer to an array of current states that the ants are in during the game. + * \param *fresh A pointer to an array of next states that the ants are going to be in during the game. + */ + void life(int *current, int *fresh); +}; + +#endif /* ANTFARM_H_ */ diff --git a/src/examples/Conway/Makefile b/src/examples/Conway/Makefile new file mode 100644 index 000000000..beadf029b --- /dev/null +++ b/src/examples/Conway/Makefile @@ -0,0 +1,63 @@ +# Makefile for Conway + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConway + +# Object files +ODIR = obj +_OBJ = LifeFarm.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Conway/testConway.cpp b/src/examples/Conway/testConway.cpp new file mode 100644 index 000000000..5770c07f4 --- /dev/null +++ b/src/examples/Conway/testConway.cpp @@ -0,0 +1,89 @@ +/* + * testConway.cpp + * + * Usage: ./testConway + */ + +#include +#include "Conway/LifeFarm.h" + +using namespace tsgl; + +/*! + * \brief Simulates Conway's Game of Life! (Now interactive!) + * \note See https://en.wikipedia.org/wiki/Conway's_Game_of_Life + * \details It is drawn in this way: + * - Get the iterations per frame, window width and window height and store them. + * - Create a LifeFarm object to hold the objects (ants) that move around on the screen. + * - Set the ability to draw ants that have "died" in the game to true. + * - Set boolean flags that determine when the animation has been paused and when the left mouse button + * has been clicked. + * - Bind the spacebar so that when it is pressed a screenshot is taken of the current frame. + * Also, set the paused boolean flag to true. + * - Bind the left mouse button so that when it is clicked the boolean flag for keeping track of the mouse's + * state is set to true. When it is released, set that flag to false. + * - While the Canvas has not been closed: + * - Sleep the internal timer until the next draw cycle. + * - If the paused boolean flag is not set: + * - Clear the Canvas. + * - For 0 to the number of iterations: + * - If the mouse has been clicked: + * - Add an ant to the LifeFarm object. + * - Draw it on the Canvas. + * . + * - Move the ants in the LifeFarm object. + * . + * . + * - If the mouse has been clicked while the Canvas has been paused, + * add an ant to the LifeFarm object and draw it to the Canvas. + * . + * . + * \param can Reference to the Canvas to draw to. + */ +void conwayFunction(Canvas& can) { + const int IPF = 100, // Iterations per frame + WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(); // Window height + LifeFarm farm(WW,WH,&can,false); //Change the false to true for something awesome! + farm.setDrawdead(true); + bool paused = false; + bool mouseDown = false; + // can.drawRectangle(1,1,can.getWindowWidth()-2,can.getWindowHeight()-2,GREEN,false,PI/4); + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can, &paused]() { + paused = !paused; + can.recordForNumFrames(1); //Screenshot + }); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown]() { + mouseDown = true; + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown]() { + mouseDown = false; + }); + + while (can.isOpen()) { + can.sleep(); + if(!paused) { + for (int i = 0; i < IPF; i++) { + if(mouseDown) { + farm.addAnt(can.getMouseX(), can.getMouseY()); + can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + } + farm.moveAnts(); + } + } + if(mouseDown) { + farm.addAnt(can.getMouseX(), can.getMouseY()); + can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + } + } +} + +//Take command-line arguments for the width and height of the Canvas +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + Canvas c(-1, -1, w, h, "Conway's Game of Life", BLACK); + c.run(conwayFunction); +} diff --git a/src/examples/CubeRun/Makefile b/src/examples/CubeRun/Makefile new file mode 100644 index 000000000..31dcc4ea6 --- /dev/null +++ b/src/examples/CubeRun/Makefile @@ -0,0 +1,63 @@ +# Makefile for CubeRun + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCubeRun + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/CubeRun/testCubeRun.cpp b/src/examples/CubeRun/testCubeRun.cpp new file mode 100644 index 000000000..bd48a32ca --- /dev/null +++ b/src/examples/CubeRun/testCubeRun.cpp @@ -0,0 +1,174 @@ +/* + * testCubeRun.cpp + * + * Usage: ./testCubeRun + */ + +#include +#include +#include +#define FONT "./assets/freefont/FreeSansBold.ttf" +#define zDelta 10 +#define obRoll 45.0 +#define OBJECT_Y -53.0 +#define PLAYER_MOVE_DIST 15.0 +#define numObstacles 20 +#define SIDE_LENGTH 25 +#define interObstacleDistance 600.0 + +using namespace tsgl; + +class ThreadData{ +private: + unsigned threadID; + Cube * myObstacle; + float myXDelta; + float myYDelta; + float myInitialZ; + +public: + ThreadData(unsigned tid, Cube* obstacle, float x, float z){ + threadID = tid; + myObstacle = obstacle; + myXDelta = x; + myInitialZ = z; + } + void moveObCloser(){ + myObstacle->changeXBy(myXDelta); + myObstacle->changeZBy(zDelta); + } + + void resetLocation(){ + myObstacle->setCenterX(0.0); + myObstacle->setCenterY(OBJECT_Y); + myObstacle->setCenterZ(myInitialZ); + } + + Cube * getObstacle(){ return myObstacle; } + + float getInitialZ(){ return myInitialZ; } +}; + +// Player cube +ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; +Cube * playerCube = new Cube(0.0, OBJECT_Y, 300, SIDE_LENGTH, 0.0, 0.0, 0.0, colors); + + +void increaseX() { + playerCube->changeXBy(PLAYER_MOVE_DIST); + // printf("X: %f\n", playerCube->getCenterX()); + if(playerCube->getCenterX() - SIDE_LENGTH/2.0 >= 135){ + playerCube->setCenterX(-135); + } +} + +void decreaseX() { + playerCube->changeXBy(-PLAYER_MOVE_DIST); + if(playerCube->getCenterX() + 12.5 <= -135){ + playerCube->setCenterX(135); + } +} + +float genXDelta(Cube * obstacle){ + float num; + if(obstacle->getCenterZ() > -4000.0){ + num = (rand() % 101) / 100.0 - 0.5; // generate random number between -0.5 and 0.5 + } + else if(obstacle->getCenterZ() <= -4000.0){ + num = (rand() % 31) / 100.0 - 0.15; // generate random number between -0.15 and 0.15 + } + return num; +} + +// Main function to run animation and gameplay +void environmentFunction(Canvas& can) { + srand( time(0) ); // initialize random seed + + ColorFloat colorArray[] = {RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, GRAY, WHITE}; + + // Initialize arrays to contain all obstacles and some obstacle data + Cube * obstacleArray[numObstacles]; + float initialZArray[numObstacles]; + float xDeltaArray[numObstacles]; + + // Fill arrays + for(unsigned i = 0; i < numObstacles; i++){ + obstacleArray[i] = new Cube(0.0, OBJECT_Y, (i+1.0)*(-interObstacleDistance), + SIDE_LENGTH, 0.0, 0.0, 0.0, colorArray[i%8]); + xDeltaArray[i] = genXDelta(obstacleArray[i]); + initialZArray[i] = obstacleArray[i]->getCenterZ(); + } + + // Create text object + unsigned scoreNum = 0; + Text * scoreText = new Text(265, 265, 0.0, std::to_wstring(scoreNum), FONT, 25, 0.0, 0.0, 0.0, WHITE); + + // Add objects to canvas + can.add(playerCube); + for(unsigned i = 0; i < numObstacles; i++){ + can.add(obstacleArray[i]); + } + can.add(scoreText); + + + // Initial key bindings + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, increaseX); + can.bindToButton(TSGL_LEFT, TSGL_PRESS, decreaseX); + + while (can.isOpen()){ + can.sleep(); + #pragma omp parallel + { + unsigned tid = omp_get_thread_num(); + unsigned numThreads = omp_get_num_threads(); + + #pragma omp for schedule(static) + for(unsigned i = 0; i < numObstacles; i ++){ + ThreadData * td = new ThreadData(tid, obstacleArray[i], xDeltaArray[i], initialZArray[i]); + + td->moveObCloser(); + + // Respawns obstacle at original starting point with a new xDelta + if(td->getObstacle()->getCenterZ() >= td->getInitialZ() + (numObstacles * interObstacleDistance) + 500.0){ + td->resetLocation(); + xDeltaArray[i] = genXDelta(td->getObstacle()); + // scoreArray[0] = scoreArray[0]->setText(std::to_string(can.getFrameNumber())); + // printf(to_string(can.getFrameNumber()) + "\n"); + + } + // Lose conditions (if player cube collides with obstacle) + if(playerCube->getCenterZ() <= td->getObstacle()->getCenterZ() + SIDE_LENGTH and + playerCube->getCenterZ() >= td->getObstacle()->getCenterZ() - SIDE_LENGTH and + playerCube->getCenterX() <= td->getObstacle()->getCenterX() + SIDE_LENGTH and + playerCube->getCenterX() >= td->getObstacle()->getCenterX() - SIDE_LENGTH){ + can.close(); + } + } + } + + // Update score + scoreNum++; + scoreText->setText(std::to_wstring(scoreNum)); + } + + // Display final score + printf("\n*********************** \ + \nFinal score: %d \ + \n***********************\n", scoreNum); + + // Delete all objects + for(unsigned i = 0; i < numObstacles; i++){ + delete obstacleArray[i]; + } + delete scoreText; + + // printf("All objects deleted!\n"); +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 620, 620, "Cube Run"); + c.setBackgroundColor(BLACK); + c.run(environmentFunction); +} \ No newline at end of file diff --git a/src/examples/DiningPhilosophers/Table.cpp b/src/examples/DiningPhilosophers/Table.cpp index 9bd781750..1eb27f3df 100644 --- a/src/examples/DiningPhilosophers/Table.cpp +++ b/src/examples/DiningPhilosophers/Table.cpp @@ -48,9 +48,8 @@ Table::Table(Canvas& can, int p, PhilMethod m) { break; } - myCan2 = new Canvas(0,0,300,300,"Legend"); + myCan2 = new Canvas(0,0,300,300,"Legend", GRAY); myCan2->start(); - myCan2->setBackgroundColor(GRAY); legendTexts = new Text*[9](); legendTexts[0] = new Text(-134,128,0,L"Method:","./assets/freefont/FreeSerif.ttf",32,0,0,0,BLACK); diff --git a/src/examples/Fireworks/Arc.cpp b/src/examples/Fireworks/Arc.cpp new file mode 100644 index 000000000..0c154288a --- /dev/null +++ b/src/examples/Fireworks/Arc.cpp @@ -0,0 +1,108 @@ +/* + * Arc.cpp + */ + +#include "Arc.h" + +const float HFLOAT = 6.0f/255.0f; + +/*! + * \brief Explicit constructor for an Arc. + * \details Explicitly constructs an Arc. + * \param can The Canvas to which the Arc is to be drawn. + */ +Arc::Arc(Canvas& can) { + f = NULL; + myLife = 0; + myCan = &can; + myX = rand() % myCan->getWindowWidth(); + myY = rand() % myCan->getWindowHeight(); + myAngle = ((rand() % 32000) / 32000.0f) * 2.0f*PI; + myRad = 20 + rand() % 180; + computeStepSize(); + myColor = ColorHSV(0.0f,1.0f,1.0f,1.0f); +} + +/*! + * \brief Explicit constructor for an Arc. + * \details Explicitly constructs an Arc. + * \param can The Canvas to which the dot is to be drawn. + * \param x The x coordinate of the dot emission point. + * \param y The y coordinate of the dot emission point. + * \param rad The radians of the Arc. + * \param angle The starting angle of the Arc. + */ +Arc::Arc(Canvas* can, int x, int y, int rad, float angle) { + myCan = can; + myX = x; myY = y; + myAngle = angle; myRad = rad; + computeStepSize(); +} + +/*! + * \brief Accessor for if the Arc is out of the Canvas window. + * \details Returns if myX and myY are between 0 and the Canvas' width and height respectively. + */ +bool Arc::outOfBounds() { + return (myX < 0 || myY < 0 || myX > myCan->getWindowWidth() || myY > myCan->getWindowHeight()); +} + +/*! + * \brief Accesssor if the Canvas is black at the Arc's pixel. + */ +bool Arc::onBlackPixel() { + const int LET = 14; + ColorInt col = myCan->getPoint(myX,myY); + return !(col.RgetWindowWidth(); + myY = rand() % myCan->getWindowHeight(); + } + computeStepSize(); +} + +/*! + * \brief Makes the Arc take a step. + */ +void Arc::step() { + if (f != NULL) + f->step(); + if (rand() % 100 < 2) { + ++myRad; + myStepSize = 1.0f/(myRad); + } + myAngle += myStepSize; + myX += cos(myAngle); + myY += sin(myAngle); + if (outOfBounds() || onBlackPixel()) { + if (f != NULL) + delete f; + f = new Firework(*myCan,myX,myY); + relocate(); + } + myCan->drawPoint(myX,myY,myColor); +} + +Arc::~Arc() { + delete f; +} \ No newline at end of file diff --git a/src/examples/Fireworks/Arc.h b/src/examples/Fireworks/Arc.h new file mode 100644 index 000000000..a7cd14718 --- /dev/null +++ b/src/examples/Fireworks/Arc.h @@ -0,0 +1,43 @@ +/* + * Firework.h + */ + +#ifndef ARC_H_ +#define ARC_H_ + +#include +#include "Firework.h" + +using namespace tsgl; + +class Arc { +private: + Canvas* myCan; + int myLife; + float myX, myY, myRad; + float myAngle, myStepSize; + ColorHSV myColor; + Firework* f; +public: + Arc(Canvas& can); + + Arc(Canvas* can, int x, int y, int rad, float angle); + + ~Arc(); + + bool outOfBounds(); + + bool onBlackPixel(); + + void computeStepSize(); + + void relocate(); + + void step(); +}; + +#endif /* ARC_H_ */ + +/* #ifdef _WIN32 + #define Arc tsgl::Arc +#endif */ \ No newline at end of file diff --git a/src/examples/Fireworks/Dot.cpp b/src/examples/Fireworks/Dot.cpp new file mode 100644 index 000000000..ccd6c5b37 --- /dev/null +++ b/src/examples/Fireworks/Dot.cpp @@ -0,0 +1,45 @@ +/* + * Dot.cpp + */ + +#include "Dot.h" + +/*! + * \brief Explicit constructor for a Dot. + * \details Draws a Dot to a Canvas parameter + * \param can Canvas to which the Dot will be drawn. + * \param x The x-coordinate of the Dot. + * \param y The y-coordinate of the Dot. + * \param s The Dot's movement speed. + * \param f The Dot's friction. + * + */ +Dot::Dot(Canvas& can, float x, float y, float s, float d, float f) { + myCan = &can; + dead = false; + myX = x; myY = y; mySpeed = s; + myDir = d; myFric = f; +} + +/*! + * \brief Makes the Dot take a step.\ + * \details Updates the Dot's x and y based on its speed and friction + */ +void Dot::step() { + myX += mySpeed*cos(myDir); + myY += mySpeed*sin(myDir); + mySpeed *= myFric; + if (!dead) + myCan->drawPoint(myX,myY,WHITE); + if (mySpeed < 0.5f) + dead = true; +} + +/*! + * \brief Accessor for the Dot's death status + * \details Returns the Dot's dead variable. + * \return dead The Dot's variable that says whether it's dead. + */ +bool Dot::isDead() { + return dead; +} \ No newline at end of file diff --git a/src/examples/Fireworks/Dot.h b/src/examples/Fireworks/Dot.h new file mode 100644 index 000000000..12052a7bf --- /dev/null +++ b/src/examples/Fireworks/Dot.h @@ -0,0 +1,25 @@ +/* + * Dot.h + */ + +#ifndef DOT_H_ +#define DOT_H_ + +#include + +using namespace tsgl; + +class Dot { +private: + bool dead; + Canvas* myCan; + float myX, myY, mySpeed, myDir, myFric; +public: + Dot(Canvas& can, float x, float y, float s, float d, float f); + + void step(); + + bool isDead(); +}; + +#endif /* DOT_H_ */ \ No newline at end of file diff --git a/src/examples/Fireworks/Firework.cpp b/src/examples/Fireworks/Firework.cpp new file mode 100644 index 000000000..d222832a2 --- /dev/null +++ b/src/examples/Fireworks/Firework.cpp @@ -0,0 +1,57 @@ +/* + * Firework.cpp + */ + +#include "Firework.h" + +/*! + * \brief Explicit constructor for a Firework. + * \details Shoots white dots out in random directions from a point. + * \param can The Canvas to which the dot is to be drawn. + * \param x The x coordinate of the dot emission point. + * \param y The y coordinate of the dot emission point. + */ +Firework::Firework(Canvas& can, int x, int y) { + dead = false; + myCan = &can; + myX = x; + myY = y; + for (int i = 0; i < 10; ++i) { + myDots[i] = new Dot(can, myX,myY,(rand() % 10000)/10000.0f,(rand() % 10000)/10000.0f * 2 * PI, 0.99f); + } +} + +/*! + * \brief Destructor for Firework. + * \details Deallocates the myDots array. + */ +Firework::~Firework() { + for (int i = 0; i < 10; i++) { + delete myDots[i]; + } +} + +/*! + * \brief Makes the firework take a step. + * \details Makes each dot in myDots take a step. + */ +void Firework::step() { + if (!dead) { + bool allDead = true; + for (int i = 0; i < 10; ++i) { + myDots[i]->step(); + if (!myDots[i]->isDead()) + allDead = false; + } + dead = allDead; + } +} + +/*! + * \brief Accessor for if the Firework is dead. + * \details Returns the dead variable. + * \return dead A bool stating whether the Firework is dead. + */ +bool Firework::isDead() { + return dead; +} \ No newline at end of file diff --git a/src/examples/Fireworks/Firework.h b/src/examples/Fireworks/Firework.h new file mode 100644 index 000000000..5eb86af65 --- /dev/null +++ b/src/examples/Fireworks/Firework.h @@ -0,0 +1,29 @@ +/* + * Firework.h + */ + +#ifndef FIREWORK_H_ +#define FIREWORK_H_ + +#include +#include "Dot.h" + +using namespace tsgl; + +class Firework { +private: + bool dead; + int myX, myY; + Canvas* myCan; + Dot* myDots[10]; +public: + Firework(Canvas& can, int x, int y); + + ~Firework(); + + void step(); + + bool isDead(); +}; + +#endif /* FIREWORK_H_ */ \ No newline at end of file diff --git a/src/examples/Fireworks/Makefile b/src/examples/Fireworks/Makefile new file mode 100644 index 000000000..8f8a3918f --- /dev/null +++ b/src/examples/Fireworks/Makefile @@ -0,0 +1,63 @@ +# Makefile for Fireworks + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testFireworks + +# Object files +ODIR = obj +_OBJ = Arc.o Dot.o Firework.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Fireworks/testFireworks.cpp b/src/examples/Fireworks/testFireworks.cpp new file mode 100644 index 000000000..11711fb4e --- /dev/null +++ b/src/examples/Fireworks/testFireworks.cpp @@ -0,0 +1,59 @@ +/* + * testFireworks.cpp + * + * Usage: ./testFireworks + */ + +#include +#include "Fireworks/Arc.h" + +using namespace tsgl; + +/*! + * \brief Creates a bunch of fireworks. + * \details Creates a bunch of Arcs, which explode into new arcs + * \param can Canvas reference to which the fireworks will be drawn. + * \param threads Number of threads to use to draw the fireworks. + * \param numFireworks Number of fireworks to draw. + * \param speed How fast the fireworks move. + */ +void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { + Arc** arcs = new Arc*[numFireworks]; + for (int i = 0; i < numFireworks; i++) { + arcs[i] = new Arc(can); + } + ColorFloat col = can.getBackgroundColor(); + col.A = 0.04f; + const int CWW = can.getWindowWidth(), CWH = can.getWindowHeight(); + #pragma omp parallel num_threads(threads) + { + while(can.isOpen()) { + can.sleep(); + int tid = omp_get_thread_num(); + int nthreads = omp_get_num_threads(); + for (int n = 0; n < speed; ++n) { + for (int i = tid; i < numFireworks; i += nthreads) + arcs[i]->step(); + if (tid == 0) + can.drawRectangle(0,0,CWW,CWH,col); + #pragma omp barrier + } + } + } + for (int i = 0; i < numFireworks; i++) { + delete arcs[i]; + } + delete [] arcs; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + int f = (argc > 4) ? atoi(argv[4]) : 50; + int s = (argc > 5) ? atoi(argv[5]) : 10; + Canvas c(-1, -1, w, h, "Fireworks!", BLACK); + c.run(fireworkFunction,t,f,s); +} diff --git a/src/examples/ForestFire/Makefile b/src/examples/ForestFire/Makefile new file mode 100644 index 000000000..1d7b13c41 --- /dev/null +++ b/src/examples/ForestFire/Makefile @@ -0,0 +1,63 @@ +# Makefile for ForestFire + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testForestFire + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ForestFire/testForestFire.cpp b/src/examples/ForestFire/testForestFire.cpp new file mode 100644 index 000000000..60a43ae24 --- /dev/null +++ b/src/examples/ForestFire/testForestFire.cpp @@ -0,0 +1,144 @@ +/* + * testForestFire.cpp + * + * Usage: ./testForestFire + */ + +#include + +using namespace tsgl; + +float randfloat(int divisor = 10000) { + return (rand() % divisor) / (float) divisor; +} + +/*! + * \brief Pseudo-simulates a forest fire using a lot of probability and randomness. + * \details + * - Store the Canvas's dimensions for ease of use. + * - Set the fire's life, strength, and maximum spread distance to some predetermined numbers. + * - Seed the random number generator. + * - Allocate arrays for storing each pixel's onFire status and flammability. + * - For each pixel: + * - Get its distance from the center of the Canvas. + * - Set its flammability and color based upon a semi-arbitrary single-line function. + * . + * - Draw 32 random square "lakes" with very low flammabilities onto the Canvas. + * - Declare a mini-firePoint struct with coordinates, life, and strength. + * - Make a 3x3 square of fire in the middle of the Canvas, and color the pixels accordingly. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - For each fire point: + * - Pop it from the queue, pushing it back on only if its life > 0. + * - For each cell adjacent to the fire, if it is not on the edge of the screen, not already + * on fire, and the random number generator rolls a number lower than the cell's flammability, + * set that cell on fire. + * . + * . + * - Deallocate the onFire and flammability arrays. + * . + * \param can Reference to the Canvas being drawn to. + */ +void forestFireFunction(Canvas& can) { + const int WINDOW_W = can.getWindowWidth(), // Set the screen sizes + WINDOW_H = can.getWindowHeight(); + const float LIFE = 10, + STRENGTH = 0.03, + MAXDIST = sqrt(WINDOW_W * WINDOW_W + WINDOW_H * WINDOW_H) / 2; + srand(time(NULL)); // Seed the random number generator + bool* onFire = new bool[WINDOW_W * WINDOW_H](); + float* flammability = new float[WINDOW_W * WINDOW_H](); + //Setting each pixel's flammablity + for (int i = 0; i < WINDOW_W; i++) { // For each individual point + for (int j = 0; j < WINDOW_H; j++) { + float xi = std::abs(WINDOW_W / 2 - i); + float yi = std::abs(WINDOW_H / 2 - j); + float tdist = (MAXDIST - sqrt(xi * xi + yi * yi)) / MAXDIST; + float f = 0.01 + (i * j % 100) / 100.0 * randfloat(100) / 2 * tdist; + flammability[i * WINDOW_H + j] = f; + can.drawPoint(i, j, ColorFloat(0.0f, f, 0.0f, 1.0f)); + } + } + //"Lakes" + for (int reps = 0; reps < 32; reps++) { + int x = rand() % WINDOW_W; + int y = rand() % WINDOW_H; + int w = rand() % (WINDOW_W - x); + int h = rand() % (WINDOW_H - y); + if (w > 32) w = 32; + if (h > 32) h = 32; + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + flammability[(x + i) * WINDOW_H + (y + j)] = 0.01; + can.drawPoint(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); + } + } + } + struct firePoint { + int x; + int y; + float life; + float strength; + }; + std::queue fires; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + firePoint fire = { WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, LIFE, STRENGTH }; + fires.push(fire); + can.drawPoint(WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); + } + } + Rectangle *rec = new Rectangle(10,10,10,10,BLUE); + can.add(rec); + while (can.isOpen()) { + can.sleep(); + int l = fires.size(); + for (int i = 0; i < l; i++) { + firePoint f = fires.front(); + fires.pop(); + if (--f.life > 0) fires.push(f); + int myCell = f.x * WINDOW_H + f.y; + if (f.x > 0 && !onFire[myCell - WINDOW_H] && randfloat() < flammability[myCell - WINDOW_H]) { + firePoint fire = { f.x - 1, f.y, LIFE, f.strength }; + fires.push(fire); + onFire[myCell - WINDOW_H] = true; + can.drawPoint(f.x - 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + } + if (f.x < WINDOW_W - 1 && !onFire[myCell + WINDOW_H] + && randfloat() < flammability[myCell + WINDOW_H]) { + firePoint fire = { f.x + 1, f.y, LIFE, f.strength }; + fires.push(fire); + onFire[myCell + WINDOW_H] = true; + can.drawPoint(f.x + 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + } + if (f.y > 0 && !onFire[myCell - 1] && randfloat() < flammability[myCell - 1]) { + firePoint fire = { f.x, f.y - 1, LIFE, f.strength }; + fires.push(fire); + onFire[myCell - 1] = true; + can.drawPoint(f.x, f.y - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + } + if (f.y < WINDOW_H && !onFire[myCell + 1] && randfloat() < flammability[myCell + 1]) { + firePoint fire = { f.x, f.y + 1, LIFE, f.strength }; + fires.push(fire); + onFire[myCell + 1] = true; + can.drawPoint(f.x, f.y + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + } + } + } + delete rec; + delete[] onFire; + delete[] flammability; +} + +//Takes width and height as command line arguments +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid + w = 1200; + h = 900; //If not, set the width and height to a default value + } + Canvas c(-1, -1, w, h, "Forest Fire"); + c.run(forestFireFunction); +} diff --git a/src/examples/Langton/AntFarm.cpp b/src/examples/Langton/AntFarm.cpp new file mode 100644 index 000000000..4d687c184 --- /dev/null +++ b/src/examples/Langton/AntFarm.cpp @@ -0,0 +1,72 @@ +/* + * AntFarm.cpp + */ + +#include "AntFarm.h" + +AntFarm::AntFarm(int w, int h, int s, Canvas* c) { + width = w; + height = h; + cap = s; + size = 0; + ants = new LangtonAnt*[cap]; + filled = new bool[w * h](); // Create an empty bitmap for the window + can = c; + shading = false; + inParallel = true; +} + +AntFarm::~AntFarm() { + for (int i = 0; i < size; i++) { + delete ants[i]; + } + delete[] ants; + delete[] filled; +} + +void AntFarm::addAnt(int x, int y, int r, int g, int b, int d) { + if (size < cap) { + ants[size] = new LangtonAnt(x, y, r, g, b, d, this); + size++; + } +} + +inline void AntFarm::moveAnt(int j) { + if (filled[ants[j]->myX + width * ants[j]->myY]) { + ants[j]->myDir = (ants[j]->myDir + 1) % 4; + if (shading) + can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); + else + can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); + } else { + ants[j]->myDir = (ants[j]->myDir + 3) % 4; + can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); + } +} + +void AntFarm::moveAnts() { + if (inParallel) { + #pragma omp parallel num_threads(omp_get_num_procs()) + { + int nthreads = omp_get_num_threads(); + int tid = omp_get_thread_num(); + for (int j = tid; j < size; j+= nthreads) + moveAnt(j); + } + } else { + for (int j = 0; j < size; j++) + moveAnt(j); + } + for (int j = 0; j < size; j++) { + filled[ants[j]->myX + width * ants[j]->myY] ^= true; + ants[j]->move(); + } +} + +void AntFarm::setShading(bool b) { + shading = b; +} + +void AntFarm::setParallel(bool b) { + inParallel = b; +} diff --git a/src/examples/Langton/AntFarm.h b/src/examples/Langton/AntFarm.h new file mode 100644 index 000000000..2f85d75ab --- /dev/null +++ b/src/examples/Langton/AntFarm.h @@ -0,0 +1,86 @@ +/* + * AntFarm.h + */ + +#ifndef ANTFARM_H_ +#define ANTFARM_H_ + +#include + +#include +#include "LangtonAnt.h" + +using namespace tsgl; + +class LangtonAnt; //Forward Declaration + +/*! + * \class AntFarm + * \brief Display one or more of Langton's Ant! + * \details Contains the data and method needed in order to hold and move around one or more LangtonAnt objects. + * \details You can have one LangtonAnt, or multiple. + * \details You can move them in parallel, or in sequence. + * \details You can also shade the colors of each LangtonAnt. + */ +class AntFarm { +private: + bool* filled; + bool shading; + bool inParallel; + void moveAnt(int j); +public: + LangtonAnt** ants; + int width, height, size, cap; + Canvas* can; + + /*! + * \brief Explicitly constructs an AntFarm object. + * \details Explicit constructor for the AntFarm class. + * \param w The width of the AntFarm object. + * \param h The height of the AntFarm object. + * \param s The size of the AntFarm object (how many ants are going to be in the AntFarm object). + * \param can Pointer to the Canvas to draw to. + */ + AntFarm(int w, int h, int s, Canvas* can); + + /*! + * \brief Destroy an AntFarm object. + * \details Destructor for the AntFarm class. + * \return Frees up any allocated memory to an AntFarm object. + */ + ~AntFarm(); + + /*! + * \brief Add an ant. + * \details Adds a LangtonAnt to the AntFarm with the specified arguments. + * \param x The x coordinate of the LangtonAnt. + * \param y The y coordinate of the LangtonAnt. + * \param r Red component of the color of the LangtonAnt. + * \param g Green component of the color of the LangtonAnt. + * \param b Blue component of the color of the LangtonAnt. + * \param d The direction of the LangtonAnt. + */ + void addAnt(int x, int y, int r, int g, int b, int d); + + /*! + * \brief Move the ants. + * \details Move the LangtonAnts that are currently in the AntFarm object. + */ + void moveAnts(); + + /*! + * \brief Shade the ants. + * \details Determines if we should shade the LangtonAnt(s) so that they have a darker color or not. + * \param b A boolean determining if we should shade the LangtonAnt(s) or not. + */ + void setShading(bool b); + + /*! + * \brief Moves the ants in parallel. + * \details Determines if we should move the LangtonAnt(s) in parallel or not. + * \param b A boolean determining if we should move the LangtonAnt(s) in parallel or not. + */ + void setParallel(bool b); +}; + +#endif /* ANTFARM_H_ */ diff --git a/src/examples/Langton/LangtonAnt.cpp b/src/examples/Langton/LangtonAnt.cpp new file mode 100644 index 000000000..0d1621cf9 --- /dev/null +++ b/src/examples/Langton/LangtonAnt.cpp @@ -0,0 +1,47 @@ +/* + * LangtonAnt.cpp + */ + +#include "LangtonAnt.h" + +LangtonAnt::LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p) { + myX = x; + myY = y; + myRed = r; + myGreen = g; + myBlue = b; + myDir = d; + myFarm = p; + myAlpha = 16; +} + +void LangtonAnt::move() { + switch (myDir) { + case UP: + myY = (myY > 0) ? myY - 1 : myFarm->height - 1; + break; + case RIGHT: + myX = (myX < myFarm->width - 1) ? myX + 1 : 0; + break; + case DOWN: + myY = (myY < myFarm->height - 1) ? myY + 1 : 0; + break; + case LEFT: + myX = (myX > 0) ? myX - 1 : myFarm->width - 1; + break; + default: + break; + } +} + +void LangtonAnt::changeColor(int r, int g, int b) { + myRed = r; myGreen = g; myBlue = b; +} + +void LangtonAnt::changeColor(ColorFloat c) { + changeColor(c.R*255,c.G*255,c.B*255); +} + +void LangtonAnt::setAlpha(int a) { + myAlpha = a; +} diff --git a/src/examples/Langton/LangtonAnt.h b/src/examples/Langton/LangtonAnt.h new file mode 100644 index 000000000..3baac9c6c --- /dev/null +++ b/src/examples/Langton/LangtonAnt.h @@ -0,0 +1,84 @@ +/* + * LangtonAnt.h + */ + +#ifndef LANGTONANT_H_ +#define LANGTONANT_H_ + +#include "AntFarm.h" + +using namespace tsgl; + +class AntFarm; //Forward Declaration + +// Shared values between langton functions +enum direction { + UP = 0, + RIGHT = 1, + DOWN = 2, + LEFT = 3 +}; + +/*! + * \class LangtonAnt + * \brief Create one of Langton's Ant! + * \details Contains all of the data and method needed in order to simulate a LangtonAnt. + * \details You can change the color either by manually setting the red, green, and blue components + * or by passing a ColorFloat struct that contains those values. + * \details The movement of each LangtonAnt is determined by its direction; UP, DOWN, LEFT, or RIGHT. + * \details You can also set each LangtonAnt object to have an alpha value in order to make them transparent. + */ +class LangtonAnt { +public: + int myX, myY, myRed, myGreen, myBlue, myAlpha, myDir; + AntFarm* myFarm; +public: + + /*! + * \brief Explicitly constructs a LangtonAnt object. + * \details Explicit constructor for the LangtonAnt class. + * \param x The x coordinate of the LangtonAnt object. + * \param y The y coordinate of the LangtonAnt object. + * \param r Red component for the color of the LangtonAnt object. + * \param g Green component for the color of the LangtonAnt object. + * \param b Blue component for the color of the LangtonAnt object. + * \param d The direction of the LangtonAnt object. + * \param p Pointer to the AntFarm object that the LangtonAnt object belongs to. + * \return The constructed LangtonAnt object. + */ + LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p); + + /*! + * \brief Move the LangtonAnt object. + * \details Set to movement of the LangtonAnt object based off of its current direction (UP, DOWN, LEFT, or RIGHT). + */ + void move(); + + /*! + * \brief Change the color of a LangtonAnt object. + * \details Specifying a new red, green, and blue component allows you to change the + * color of the LangtonAnt object. + * \param r Red component of the new color for the LangtonAnt object. + * \param g Green component of the new color for the LangtonAnt object. + * \param b Blue component of the new color for the LantonAnt object. + */ + void changeColor(int r, int g, int b); + + /*! + * \brief Change the color of a LangtonAnt object. + * \details Same as changeColor(r, g, b) but instead of passing the red, green, and + * blue components seperately you are passing a ColorFloat struct that contains all three. + * \param c A ColorFloat struct containing the new red, green, and blue components for the new + * color of the LangtonAnt object. + */ + void changeColor(ColorFloat c); + + /*! + * \brief Set the alpha component of the color. + * \details Set the alpha component of the color for a LangtonAnt object. + * \param a Alpha component to give to the LangtonAnt object. + */ + void setAlpha(int a); +}; + +#endif /* LANGTONANT_H_ */ diff --git a/src/examples/Langton/Makefile b/src/examples/Langton/Makefile new file mode 100644 index 000000000..c0bfe9b4d --- /dev/null +++ b/src/examples/Langton/Makefile @@ -0,0 +1,63 @@ +# Makefile for Langton + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLangton + +# Object files +ODIR = obj +_OBJ = AntFarm.o LangtonAnt.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Langton/testLangton.cpp b/src/examples/Langton/testLangton.cpp new file mode 100644 index 000000000..60c0c1324 --- /dev/null +++ b/src/examples/Langton/testLangton.cpp @@ -0,0 +1,183 @@ +/* + * testLangton.cpp + * + * Usage: ./testLangton + */ + +#include +#include + +#include "Langton/AntFarm.h" + +using namespace tsgl; + +/*! + * \brief Simulates 4 Langton's Ants with alpha transparency used for drawing and a couple + * other neat features. + * \details Mostly the same as langtonColonyFunction(), but with a couple key differences: + * - Each ant is drawn with an alpha (transparency) value of 16 (~0.06). + * - There are four LangtonAnts in the AntFarm object (same as langtonColonyFunction() ) *BUT* they have alpha transparency. + * - We set up an additional timer \b pulse to keep track of intervals between clearing the screen. + * - We set up a function \b tempo, which resets the \b pulse timer, sets its interval to the + * time since the last reset, and makes the Canvas clear itself at that interval. + * - We bind the left mouse button and the enter button to the described \b tempo function. + * - We bind the enter key to pause the animation. + * - We bind the space key to clearing the Canvas. + * - After all the ants are moved on a given frame, if the \b pulse timer is expired, we clear the screen. + * . + * \param can Reference to the Canvas being drawn to. + */ +void alphaLangtonFunction(Canvas& can) { + const int IPF = 5000, // Iterations per frame + WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(), // Window height + R = WH / 6; // How far apart to space the ants + bool paused = false; + + AntFarm farm(WW,WH,4,&can); + farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); + farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); + farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); + farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + + Timer pulse(28.72 / 60); + double time = pulse.getTime(); + + auto tempo = [&can, &pulse, &time]() { + std::cout << (pulse.getTime() - time) << std::endl; + pulse.reset(pulse.getTime() - time); + time = pulse.getTime(); + }; + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, tempo); + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&paused]() { + paused = !paused; + }); + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { + can.clearProcedural(); + }); + + while (can.isOpen()) { + if (!paused) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = 0; i < IPF; i++) + farm.moveAnts(); + if (pulse.pastPeriod()) + can.clearProcedural(); + } + } +} + +/*! + * \brief Simulates Langton's Ant at speeds faster than the Canvas' framerate. + * \details + * - The Canvas' width and height are stored. + * - An AntFarm object is created that will display the LangtonAnt. + * - The number of iterations per frame is set to a large number. + * - While the Canvas is still open: + * - Sleep the internal timer until the next draw cycle. + * - For 0 to the iterations per frame: + * - Move the LangtonAnt inside of the AntFarm object. + * . + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void langtonFunction(Canvas& can) { + const int IPF = 1000, // Iterations per frame + WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(); // Window height + AntFarm farm(WW,WH,4,&can); + farm.setParallel(false); + farm.addAnt(WW / 2,WH / 2,MAX_COLOR,0,0,0); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = 0; i < IPF; i++) { + farm.moveAnts(); + } + } +} + +/*! + * \brief Simulates 4 LangtonAnts at speeds faster than the Canvas' framerate. + * \details Same principle as langtonFunction(). Key differences: + * - A variable \b R holds the distance from the center for each ant. + * - There are four LangtonAnts inside of the AntFarm object. + * - Each ant is tracked separately, with arrays holding each type of variable. + * - The LangtonAnts are shaded this time. + * . + * \param can Reference to the Canvas being drawn to. + */ +void langtonColonyFunction(Canvas& can) { + const int IPF = 5000, // Iterations per frame + WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(), // Window height + R = WH / 6; // How far apart to space the ants + + AntFarm farm(WW,WH,4,&can); + farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); + farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); + farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); + farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.setShading(true); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = 0; i < IPF; i++) + farm.moveAnts(); + } +} + +/*! + * \brief Simulates 4 LangtonAnts at speeds faster than the Canvas' framerate, with nicer colors! + * \details Same as langtonColonyFunction(), but with dynamically-colored LangtonAnts. + * \param can Reference to the Canvas being drawn to. + */ +void langtonRainbowFunction(Canvas& can) { + const int IPF = 5000, // Iterations per frame + WW = can.getWindowWidth(), // Window width + WH = can.getWindowHeight(), // Window height + R = WH / 6; // How far apart to space the ants + + AntFarm farm(WW,WH,4,&can); + farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); + farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); + farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); + farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.setShading(true); + for (int j = 0; j < 4; j++) + farm.ants[j]->setAlpha(64); + + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int j = 0; j < 4; j++) + farm.ants[j]->changeColor(ColorHSV((can.getFrameNumber() + 3 * j) % 12 / 2.0f, 1.0f, 1.0f, .25f)); + for (int i = 0; i < IPF; i++) + farm.moveAnts(); + } +} + +//Take command-line arguments for the width and height of the Canvas +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + //Alpha Langton + std::cout << "Alpha Langton's Ant" << std::endl; + Canvas c1(-1, -1, w, h, "Langton's Ant w/Alpha (enter to pause)", BLACK); + c1.run(alphaLangtonFunction); + + //Regular Langton + std::cout << "Regular Langton's Ant" << std::endl; + Canvas c2(-1, -1, w, h, "Langton's Ant"); + c2.run(langtonFunction); + + //Colony Langton + std::cout << "Multiple Langton's Ants" << std::endl; + Canvas c3(-1, -1, w, h, "4x Langton's Ants"); + c3.run(langtonColonyFunction); + + //Colorful Langton + std::cout << "Dynamically Colored Langton's Ants" << std::endl; + Canvas c4(-1, -1, w, h, "Colorful Langton's Ants", BLACK); + c4.run(langtonRainbowFunction); +} diff --git a/src/examples/Mandelbrot/Buddhabrot.cpp b/src/examples/Mandelbrot/Buddhabrot.cpp new file mode 100644 index 000000000..f3d2ab888 --- /dev/null +++ b/src/examples/Mandelbrot/Buddhabrot.cpp @@ -0,0 +1,109 @@ +/* + * Buddhabrot.cpp + */ + +#include "Buddhabrot.h" + +#ifdef _WIN32 //Windows doesn't like numbers higher than RAND_MAX (32767) + #define rand() (rand() | rand() << 16) +#endif + +Buddhabrot::Buddhabrot(unsigned threads, unsigned depth = 1000) : Mandelbrot(threads, depth) { + counter = nullptr; + cww = cwh = 0; +} + +Buddhabrot::~Buddhabrot() { + for (int i = 0; i < cwh; ++i) + delete [] counter[i]; + delete[] counter; + counter = nullptr; +} + +void Buddhabrot::draw(Cart& can) { + cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + const unsigned long MAXITS = cww*cwh*10; + ColorFloat tcolor(1.0f,1.0f,1.0f,0.1f); + const int RPREC = 100000; + counter = new int*[cwh]; + for (int i = 0; i < cwh; ++i) + counter[i] = new int[cww]; + while (myRedraw) { + myRedraw = false; + can.clearProcedural(); + for (int i = 0; i < cwh; ++i) + for (int j = 0; j < cww; ++j) + counter[i][j] = 0; + const Decimal cph = can.getPixelHeight(), cpw = can.getPixelWidth(), + cMinx = can.getMinX(), cMiny = can.getMinY(), + cMaxx = cMinx+cpw*(cww-1), cMaxy = cMiny+cph*(cwh-1); + unsigned long cycles = 0; + #pragma omp parallel num_threads(myThreads) + { + unsigned tid = omp_get_thread_num(), threads = omp_get_num_threads(); + Decimal offset = cMiny+(cph*cwh*tid)/(Decimal)threads; + const Decimal wscale = (cpw*cww)/(Decimal)RPREC; + const Decimal hscale = (cph*cwh/threads)/(Decimal)RPREC; + ColorFloat tc = Colors::highContrastColor(tid); + ColorFloat tcolor(tc.R,tc.G,tc.B,0.1f); + complex* znums = new complex[myDepth]; + Decimal col, row; + for (unsigned long i = tid; i < MAXITS; i+= threads) { + if (myRedraw) break; + col = cMinx+wscale*(rand() % RPREC); //Between cMinx and cMaxx + row = offset+hscale*(rand() % RPREC); //Between cMiny and cMaxy + complex c(col,row); + complex z = c; + unsigned its = 0; + while (std::abs(z) < 2.0l && its != myDepth) { + z = z * z + c; + znums[its] = z; + ++its; + } + if (its < myDepth) { //If we're not in the Mandelbrot set + z = c; + while (its > 0) { + --its; + if (znums[its].imag() < cMiny || znums[its].imag() > cMaxy || + znums[its].real() < cMinx || znums[its].real() > cMaxx) + continue; + int boxY = (znums[its].imag()-cMiny)/cph; + int boxX = (znums[its].real()-cMinx)/cpw; + #pragma omp atomic + ++(counter[boxY][boxX]); + can.Canvas::drawPixel(boxY, boxX, tcolor); + } + } + #pragma omp atomic + ++cycles; + if (cycles % (MAXITS/100) == 0) { + std::cout << (100*cycles)/MAXITS << "%" << std::endl; + can.handleIO(); + } + if (myRedraw || !can.isOpen()) + break; + } + delete [] znums; + znums = NULL; + } + if (!can.isOpen()) + return; + int maxIts = 0; + for (int i = 0; i < cwh; ++i) + for (int j = 0; j < cww; ++j) + if (counter[i][j] > maxIts) + maxIts = counter[i][j]; + std::cout << maxIts << " max iterations" << std::endl; + #pragma omp parallel num_threads(myThreads) + { + for (int i = omp_get_thread_num(); i < cwh; i += omp_get_num_threads()) + for (int j = 0; j < cww; ++j) { + float normalize = sqrt((float)counter[i][j]/maxIts); + can.Canvas::drawPixel(i, j, (ColorFloat)can.getPixel(i,j) * normalize); + } + } + while (can.isOpen() && !myRedraw) + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + } +} + diff --git a/src/examples/Mandelbrot/Buddhabrot.h b/src/examples/Mandelbrot/Buddhabrot.h new file mode 100644 index 000000000..ea4de8320 --- /dev/null +++ b/src/examples/Mandelbrot/Buddhabrot.h @@ -0,0 +1,55 @@ +/* + * Buddhabrot.h + */ + +#ifndef BUDDHABROT_H_ +#define BUDDHABROT_H_ + +#include + +#include "Mandelbrot.h" + +using namespace tsgl; + +/*! + * \class Buddhabrot + * \brief Draw a Buddhabrot. + * \details Contains all of the information necessary in order to draw a Buddhabrot. + * \details Child class of the Mandelbrot class. + * \see https://en.wikipedia.org/wiki/Buddhabrot for details on what a Buddhabrot is. + * \see Mandelbrot class + */ +class Buddhabrot : public Mandelbrot { +private: + int **counter; + int cww, cwh; +public: + + /*! + * \brief Explicitly construct a Buddhabrot object. + * \details Explicit constructor for the Buddhabrot class. + * \param threads The number of threads to use when drawing the Buddhabrot object to the CartesianCanvas. + * \param depth The number of iterations to go to in order to draw the Buddhabrot object. + * \return The constructed Buddhabrot object. + */ + Buddhabrot(unsigned threads, unsigned depth); + + /*! + * \brief Destroys a Buddhabrot object. + * \details Destructor for the Buddhabrot class. + * \return Frees up memory allocated to a Buddhabrot object. + */ + ~Buddhabrot(); + + /*! + * \brief Draw the Buddhabrot. + * \details Actually draws the Buddhabrot object to the CartesianCanvas. + * \param can Reference to the CartesianCanvas to draw on. + * \note This method overrides the draw() method from Mandelbrot. + * \note Cart is a typedef for CartesianCanvas. + */ + void draw(Cart& can); +}; + +#endif /* BUDDHABROT_H_ */ + diff --git a/src/examples/Mandelbrot/GradientMandelbrot.cpp b/src/examples/Mandelbrot/GradientMandelbrot.cpp new file mode 100644 index 000000000..c2cba1c51 --- /dev/null +++ b/src/examples/Mandelbrot/GradientMandelbrot.cpp @@ -0,0 +1,43 @@ +/* + * GradientMandelbrot.cpp + */ + +#include "GradientMandelbrot.h" + +GradientMandelbrot::GradientMandelbrot(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} + +void GradientMandelbrot::draw(Cart& can) { + while (myRedraw) { + myRedraw = false; + #pragma omp parallel num_threads(myThreads) + { + unsigned int nthreads = omp_get_num_threads(); + double blockstart = can.getCartHeight() / nthreads; + unsigned int iterations; + double smooth; + for (unsigned int k = 0; k <= (can.getWindowHeight() / nthreads) && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... + long double row = blockstart * omp_get_thread_num() + can.getMinY() + can.getPixelHeight() * k; + for (long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { + complex c(col, row); + complex z(col, row); + smooth = exp(-std::abs(z)); + iterations = 0; + while (std::abs(z) < 2.0l && iterations != myDepth) { + iterations++; + z = z * z + c; + smooth += exp(-std::abs(z)); + } + smooth /= (myDepth + 1); + float value = (float)iterations/myDepth; + can.drawPoint(col, row, ColorHSV((float)smooth * 6.0f, 1.0f, value, 1.0f)); + if (myRedraw) break; + } + can.handleIO(); + if (myRedraw) break; + } + } + while (can.isOpen() && !myRedraw) + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + } +} + diff --git a/src/examples/Mandelbrot/GradientMandelbrot.h b/src/examples/Mandelbrot/GradientMandelbrot.h new file mode 100644 index 000000000..4f219ebf5 --- /dev/null +++ b/src/examples/Mandelbrot/GradientMandelbrot.h @@ -0,0 +1,43 @@ +/* + * GradientMandelbrot.h + */ + +#ifndef GRADIENTMANDELBROT_H_ +#define GRADIENTMANDELBROT_H_ + +#include "Mandelbrot.h" + +using namespace tsgl; + +/*! + * \class GradientMandelbrot + * \brief Draws a GradientMandelbrot set on a CartesianCanvas. + * \details Similar to a normal Mandelbrot set but with a smoother shading. + * \details Extends the Mandelbrot class and overrides its draw() function and setRedraw() function. + * \details Can zoom in and out of the Mandelbrot set by scrolling up and down on the mouse wheel (respectively). + * \see Mandelbrot class + */ +class GradientMandelbrot : public Mandelbrot { +public: + + /*! + * \brief Explicitly constructs a GradientMandelbrot set. + * \details Explicit constructor for the GradienMandelbrot class. + * \param threads The number of threads to use in the drawing of the GradientMandelbrot object. + * \param depth The number of iterations to go to in order to draw the GradientMandelbrot object. + * \return The GradientMandelbrot object ready to be drawn onto the CartesianCanvas. + */ + GradientMandelbrot(unsigned threads, unsigned depth); + + /*! + * \brief Draw the GradientMandelbrot set. + * \details Actually draws the GradientMandelbrot set onto the CartesianCanvas. + * \param can Reference to the CartesianCanvas to draw to. + * \note This method overrides the Mandelbrot class' draw() method. + * \note Cart is a typedef for a CartesianCanvas object. + */ + void draw(Cart& can); +}; + +#endif /* GRADIENTMANDELBROT_H_ */ + diff --git a/src/examples/Mandelbrot/Julia.cpp b/src/examples/Mandelbrot/Julia.cpp new file mode 100644 index 000000000..1e84b90f2 --- /dev/null +++ b/src/examples/Mandelbrot/Julia.cpp @@ -0,0 +1,59 @@ +/* + * Julia.cpp + */ + +#include "Julia.h" + +Julia::Julia(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} + +void Julia::draw(Cart& can) { + const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas + VisualTaskQueue vq(CH); + while(myRedraw) { + myRedraw = false; + can.reset(); + unsigned next = 0; + vq.reset(); + #pragma omp parallel num_threads(myThreads) + { + vq.showLegend(); + int myNext; + while(true) { // As long as we aren't trying to render off of the screen... + #pragma omp critical + { + myNext = next++; + } + if (myNext >= can.getWindowHeight()) + break; + vq.update(myNext,RUNNING); + long double row = can.getMinY() + can.getPixelHeight() * myNext; + for(long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { + complex z(-0.8f, 0.156f); + complex c(col, row); + unsigned iterations = 0; + while (std::abs(c) < 2.0 && iterations != myDepth) { // Compute it until it escapes or we give up + iterations++; + c = c * c + z; + } + if(iterations == myDepth) { // If the point never escaped, draw it black + can.drawPoint(col, row, BLACK); + } else { // Otherwise, draw it with color based on how long it took + float mult = iterations/(float)myDepth; + can.drawPoint(col, row, Colors::blend(BLACK,WHITE,0.25f+0.5f*mult)*mult); + } + if (!can.isOpen() || myRedraw) break; + } + vq.update(myNext,FINISHED); + can.handleIO(); + if (myRedraw) break; + } + } +// manhattanShading(can); + std::cout << can.getTime() << std::endl; + while (can.isOpen() && !myRedraw) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + vq.sleep(); + } + } + vq.close(); +} diff --git a/src/examples/Mandelbrot/Julia.h b/src/examples/Mandelbrot/Julia.h new file mode 100644 index 000000000..081b5b0e2 --- /dev/null +++ b/src/examples/Mandelbrot/Julia.h @@ -0,0 +1,41 @@ +/* + * Julia.h + */ + +#ifndef JULIA_H_ +#define JULIA_H_ + +#include "Mandelbrot.h" + +using namespace tsgl; + +/*! + * \class Julia + * \brief Draw a Julia set. + * \details Contains all of the information necessary in order to draw a Julia set onto a CartesianCanvas. + * \details Can zoom in and out of the Julia set by scrolling the mouse wheel up and down (respectively). + * \details Same is true when clicking the left mouse button (zooming in) and the right mouse button (zooming out). + * \details Can also clear the screen by pressing the spacebar. + */ +class Julia : public Mandelbrot { +public: + + /*! + * \brief Explicitly constructs a Julia object. + * \details Explicit constructor for the Julia class. + * \param threads The number of threads to use in drawing the Julia object onto the CartesianCanvas. + * \param depth The number of iterations to go to in order to draw the Julia object. + *\return The constructed Julia object. + */ + Julia(unsigned threads, unsigned depth); + + /*! + * \brief Draw the Julia object. + * \details Actually draws the Julia object to a CartesianCanvas. + * \param can Reference to the CartesianCanvas to draw on. + * \note Cart is a typedef for a CartesianCanvas object. + */ + void draw(Cart& can); +}; + +#endif /* JULIA_H_ */ diff --git a/src/examples/Mandelbrot/Makefile b/src/examples/Mandelbrot/Makefile new file mode 100644 index 000000000..f002ec241 --- /dev/null +++ b/src/examples/Mandelbrot/Makefile @@ -0,0 +1,63 @@ +# Makefile for Mandelbrot + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMandelbrot + +# Object files +ODIR = obj +_OBJ = Buddhabrot.o GradientMandelbrot.o Julia.o Mandelbrot.o Nova.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Mandelbrot/Mandelbrot.cpp b/src/examples/Mandelbrot/Mandelbrot.cpp new file mode 100644 index 000000000..5e3986600 --- /dev/null +++ b/src/examples/Mandelbrot/Mandelbrot.cpp @@ -0,0 +1,161 @@ +/* + * Mandelbrot.cpp + */ + +#include "Mandelbrot.h" + +Mandelbrot::Mandelbrot(unsigned threads, unsigned depth) { + myThreads = threads; + myDepth = depth; + myFirstX = myFirstY = mySecondX = mySecondY = 0.0; + myRedraw = true; +} + +void Mandelbrot::manhattanShading(CartesianCanvas& can) { + int** canPoints = new int*[can.getWindowHeight()]; + for (int i = 0; i < can.getWindowHeight(); ++i) { + canPoints[i] = new int[can.getWindowWidth()]; + for (int j = 0; j < can.getWindowWidth(); ++j) { + ColorInt c = can.getPoint(j,i); + canPoints[i][j] = ((c.R == c.G) && (c.G == c.B) && (c.B == 0)) ? 0 : -1; + } + } + bool done = false; + int loop, cwh = can.getWindowHeight(), cww = can.getWindowWidth(); + for (loop = 0; !done; ++loop) { + done = true; + #pragma omp parallel for + for (int i = 0; i < cwh; ++i) { + for (int j = 0; j < cww; ++j) { + if (canPoints[i][j] != loop) + continue; + if (i > 0 && canPoints[i-1][j] == -1) + canPoints[i-1][j] = loop+1, done = false; + if (j > 0 && canPoints[i][j-1] == -1) + canPoints[i][j-1] = loop+1, done = false; + if (i < cwh-1 && canPoints[i+1][j] == -1) + canPoints[i+1][j] = loop+1, done = false; + if (j < cww-1 && canPoints[i][j+1] == -1) + canPoints[i][j+1] = loop+1, done = false; + } + } + } + + int sum = 0; + for (int i = 0; i < cwh; ++i) + for (int j = 0; j < cww; ++j) + sum += canPoints[i][j]; + float avg = (((float)sum)/cww)/cwh; + + #pragma omp parallel for + for (int i = 0; i < cwh; ++i) { + for (int j = 0; j < cww; ++j) { + float mult = sqrt(avg*((float)canPoints[i][j])/loop); + ColorFloat c = can.getPoint(j,i); + can.Canvas::drawPoint(j,i,c*mult); + } + } + + for (int i = 0; i < can.getWindowHeight(); ++i) + delete [] canPoints[i]; + delete [] canPoints; + canPoints = NULL; +} + +void Mandelbrot::bindings(Cart& can) { + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can, this]() { + can.clearProcedural(); + this->myRedraw = true; + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&can, this]() { + can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->myFirstX, this->myFirstY); + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&can, this]() { + can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), this->mySecondX, this->mySecondY); + if (!(this->myFirstX == this->mySecondX || this->myFirstY == this->mySecondY)) { + can.zoom(this->myFirstX, this->myFirstY, this->mySecondX, this->mySecondY); + this->myRedraw = true; + } + }); + can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&can, this]() { + Decimal x, y; + can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); + can.zoom(x, y, 1.5); + this->myRedraw = true; + }); + can.bindToScroll([&can, this](double dx, double dy) { + Decimal x, y; + can.getCartesianCoordinates(can.getMouseX(), can.getMouseY(), x, y); + Decimal scale; + if (dy == 1) scale = .5; + else scale = 1.5; + can.zoom(x, y, scale); + this->myRedraw = true; + }); + } + +void Mandelbrot::draw(Cart& can) { + const int CH = can.getWindowHeight(); //Height of our Mandelbrot canvas + const int XBRD = 10; //Border for out progress bar + const int YBRD = 40; //Border for out progress bar + const int PBWIDTH = 800; + Canvas pCan(0, 0, PBWIDTH, 100, "Thread Workloads"); //Canvas for our progress bar + pCan.start(); + ProgressBar pb( + XBRD,YBRD,pCan.getWindowWidth()-XBRD*2,pCan.getWindowHeight()-YBRD*2, + 0,CH - (CH % myThreads),myThreads //Make the max PB value a multiple of myThreads + ); + for (int i = 0; i < myThreads; ++i) { + pCan.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); + } + while(myRedraw) { + myRedraw = false; + can.reset(); + #pragma omp parallel num_threads(myThreads) + { + unsigned tid = omp_get_thread_num(); + unsigned nthreads = omp_get_num_threads(); + ColorFloat tcolor = Colors::highContrastColor(tid); + double blocksize = can.getCartHeight() / nthreads; + double blockheight = CH / nthreads; + pb.update(blockheight*tid); + pCan.drawProgress(&pb); + long double startrow = blocksize * tid + can.getMinY(); + for(unsigned int k = 0; k <= blockheight && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... + pb.update(k+(CH*tid)/nthreads); + //Messy, but effective +// pCan.drawRectangle(XBRD,YBRD,pCan.getWindowWidth()-XBRD,pCan.getWindowHeight()-YBRD,pCan.getBackgroundColor(),true); + //Elegant, but flickery + pCan.drawProgress(&pb); + long double row = startrow + can.getPixelHeight() * k; + for(long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { + complex originalComplex(col, row); + complex c(col, row); + unsigned iterations = 0; + while (std::abs(c) < 2.0 && iterations != myDepth) { // Compute it until it escapes or we give up + iterations++; + c = c * c + originalComplex; + } + if(iterations == myDepth) { // If the point never escaped, draw it black + can.drawPoint(col, row, BLACK); + } else { // Otherwise, draw it with color based on how long it took + float mult = iterations/(float)myDepth; + can.drawPoint(col, row, Colors::blend(tcolor,WHITE,0.25f+0.5f*mult)*mult); + } + if (myRedraw) break; + } + can.handleIO(); + if (myRedraw) break; + } + } +// shadeCanvas(can); Optional shading + std::cout << can.getTime() << std::endl; + while (can.isOpen() && !myRedraw) { + pCan.sleep(); + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + } + } + if (pCan.isOpen()) + pCan.close(); + pCan.wait(); //Close our progress bar if we're done +} diff --git a/src/examples/Mandelbrot/Mandelbrot.h b/src/examples/Mandelbrot/Mandelbrot.h new file mode 100644 index 000000000..4c61cdf11 --- /dev/null +++ b/src/examples/Mandelbrot/Mandelbrot.h @@ -0,0 +1,85 @@ +/* + * Mandelbrot.h + */ + +#ifndef MANDELBROT_H_ +#define MANDELBROT_H_ + +//Imports, constants.... +#include +#include +#include +#include +#include +#include + +using namespace tsgl; + +/*! + * \var complex + * \brief Typedef for std::complex. + */ +typedef std::complex complex; + +/*! + * \class Mandelbrot + * \brief Draw a Mandelbrot set. + * \details Contains the information necessary in order to draw a Mandelbrot set onto a CartesianCanvas. + * \details Can zoom in and out of the screen by scrolling up and down on the mouse wheel (respectively). + * \details Same is true if you click on the left mouse button (zoom in) and right mouse button (zoom out). + */ +class Mandelbrot { +private: + Decimal myFirstX, myFirstY, mySecondX, mySecondY; + +protected: + int myThreads; + unsigned int myDepth; + bool myRedraw; + + /*! + * \brief Shades the fractal using Manhattan distances + * \details This function may be called after the Mandelbrot has finished rendering to do some + * post-procecssing using the distances from non-escaped pixels to their nearest escaped pixels, + * using the average of their Manhattan distances. + */ + void manhattanShading(CartesianCanvas& can); + +public: + + /*! + * \brief Explicitly construct a Mandelbrot object. + * \details Explicit constructor for the Mandelbrot class. + * \param threads The number of threads to use in drawing the Mandelbrot object onto the CartesianCanvas. + * \param depth The number of iterations to go to in order to draw the Mandelbrot object. + * \return The constructed Mandelbrot object. + */ + Mandelbrot(unsigned threads, unsigned depth); + + /*! + * \brief Destroys a Mandelbrot object and any children of the Mandelbrot class. + * \details Destructor for the Mandelbrot class and its children. + * \note Does absolutely nothing. + */ + virtual ~Mandelbrot() {}; + + /*! + * \brief Binds buttons and/or mouse clicks. + * \details Binds buttons and/or mouse clicks needed for I/O capabilities. + * \details In this case: the mouse wheel, left and right mouse buttons. + * \param can Reference to the CartesianCanvas to have the buttons bound to. + * \note Cart is a typedef for CartesianCanvas. + */ + void bindings(Cart& can); + + /*! + * \brief Draw the Mandelbrot object. + * \details Actually draws the Mandelbrot object onto the CartesianCanvas. + * \param can Reference to the CartesianCanvas to draw on. + * \note Can be inherited by children classes who extend the Mandelbrot class. + * \note Cart is a typedef for CartesianCanvas. + */ + virtual void draw(Cart& can); +}; + +#endif /* MANDELBROT_H_ */ diff --git a/src/examples/Mandelbrot/Nova.cpp b/src/examples/Mandelbrot/Nova.cpp new file mode 100644 index 000000000..983438694 --- /dev/null +++ b/src/examples/Mandelbrot/Nova.cpp @@ -0,0 +1,53 @@ +/* + * Nova.cpp + */ + +#include "Nova.h" + +Nova::Nova(unsigned threads, unsigned depth) : Mandelbrot(threads, depth) {} + +void Nova::draw(Cart& can) { + const long double R = 1.0l; + while (myRedraw) { + myRedraw= false; + #pragma omp parallel num_threads(myThreads) + { + unsigned int nthreads = omp_get_num_threads(); + double blockstart = can.getCartHeight() / nthreads; + unsigned int iterations; + double smooth; + for (unsigned int k = 0; k <= (can.getWindowHeight() / nthreads) && can.isOpen(); k++) { // As long as we aren't trying to render off of the screen... + long double row = blockstart * omp_get_thread_num() + can.getMinY() + can.getPixelHeight() * k; + for (long double col = can.getMinX(); col <= can.getMaxX(); col += can.getPixelWidth()) { + complex c(col, row); + complex z(1, 0); + smooth = exp(-std::abs(z)); + complex n, d, c1; + complex r(1, 0); + iterations = 0; + while (std::abs(z) < 2.0l && iterations != myDepth) { + iterations++; + n = z * z * z - 1.0l; + d = z * z * 3.0l; + z = z + c - (R * n / d); + smooth += exp(-std::abs(z)); + } + smooth /= myDepth; + if (smooth != smooth || smooth < 0) // Check to see if smooth is NAN + smooth = 0; + smooth = smooth - (int)smooth; + //float mult = iterations/(float)myDepth; + if (iterations == myDepth) + can.drawPoint(col, row, BLACK); + else + can.drawPoint(col, row, ColorHSV((float) smooth * 6.0f, 1.0f, (float) smooth, 1.0f)); + } + can.handleIO(); + if (myRedraw) break; + } + } + manhattanShading(can); + while (can.isOpen() && !myRedraw) + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + } +} diff --git a/src/examples/Mandelbrot/Nova.h b/src/examples/Mandelbrot/Nova.h new file mode 100644 index 000000000..a750258e2 --- /dev/null +++ b/src/examples/Mandelbrot/Nova.h @@ -0,0 +1,42 @@ +/* + * Nova.h + */ + +#ifndef NOVA_H_ +#define NOVA_H_ + +#include "Mandelbrot.h" + +using namespace tsgl; + +/*! + * \class Nova + * \brief Draws a Nova (Newton Fractal) set on a CartesianCanvas. + * \details Extends the Mandelbrot class and overrides its draw() function and setRedraw() function. + * \details Can zoom in and out of the Nova set by scrolling up and down on the mouse wheel (respectively). + * \see Mandelbrot class + */ +class Nova : public Mandelbrot { +public: + + /*! + * \brief Explicitly constructs a Nova set. + * \details Explicit constructor for the Nova class. + * \param threads The number of threads to use in the drawing of the Nova object. + * \param depth The number of iterations to go to in order to draw the Nova object. + * \return The Nova object ready to be drawn onto the CartesianCanvas. + */ + Nova(unsigned threads, unsigned depth); + + /*! + * \brief Draw the Nova set. + * \details Actually draws the Nova set onto the CartesianCanvas. + * \param can Reference to the CartesianCanvas to draw to. + * \note This method overrides the Mandelbrot class' draw() method. + * \note Cart is a typedef for a CartesianCanvas object. + */ + void draw(Cart& can); +}; + +#endif /* NOVA_H_ */ + diff --git a/src/examples/Mandelbrot/testMandelbrot.cpp b/src/examples/Mandelbrot/testMandelbrot.cpp new file mode 100644 index 000000000..f36ac871c --- /dev/null +++ b/src/examples/Mandelbrot/testMandelbrot.cpp @@ -0,0 +1,223 @@ +/* + * testMandelbrot.cpp + * + * Usage: ./testMandelbrot + */ + +/*testMandelbrot.cpp contains multiple functions that display a Mandelbrot set in similar fashions (and one that displays a Julia set). */ + +#include "Mandelbrot/Buddhabrot.h" +#include "Mandelbrot/Mandelbrot.h" +#include "Mandelbrot/GradientMandelbrot.h" +#include "Mandelbrot/Julia.h" +#include "Mandelbrot/Nova.h" + +using namespace tsgl; + +/*! + * \brief Draws the Mandelbrot set on a CartesianCanvas with custom controls, a specified target update rate, + * and a dynamic number of threads and uses command-line arguments to specify the number of threads to use. + * There is also a ProgressBar that shows the progress made by each thread as the Mandelbrot set is drawn onto the CartesianCanvas. + * \details + * - A class containing all of the data and methods to draw a Mandelbrot set has been made. + * - When you create a Mandelbrot object: + * - The number of threads to use is predetermined (passed as the \b threads parameter) and stored in: \b myThreads. + * - The number of iterations to check is predetermined (passed as the \b depth parameter) and stored in: \b myDepth. + * - The internal timer of the Canvas is set up to go off every ( \b FRAME / 2 ) seconds. + * - A flag telling us to redraw is set to true. + * . + * - When you bind the buttons: + * - The spacebar on-press event is set to tell the Canvas to clear and re-render. + * - The left mouse on-press event is set to grab the mouse's current coordinates. + * - The left mouse on-release event is set to grab the mouse's current coordinates, and tell the Canvas to zoom into the + * bounding rectangle between the current coordinates and those from the left mouse's on press event and to redraw the Mandelbrot + * at that point. + * - The right mouse on-press event is set to grab the mouse's current coordinates, and tell the Canvas to zoom out + * from that area and redraw the Mandlebrot at that point. + * - The mouse's scroll wheel is set to tell the Canvas to zoom in / out by a predetermined amount at the mouse's + * current coordinates and redraw the Mandelbrot at that point. + * . + * - When you actually draw the Mandelbrot object onto the CartesianCanvas: + * - Store the height of the Canvas, the x and y-coordinates for the ProgressBar, and the width of the ProgressBar Canvas. + * - Create the Canvas that will draw the ProgressBar object. + * - Create the ProgressBar object. + * - While the redraw flag is set: + * - Set the redraw flag to false. + * - Reset the internal timer to 0. + * - Fork off the predetermined number of parallel threads using OMP. + * - Store the actual number of threads spawned in: \b nthreads. + * - Assign a color to each thread. + * - Figure the cartesian size of the area each thread is to calculate and store it in: \b blocksize. + * - Figure out the actual number of rows each thread is to calculate and store it in: \b blockheight. + * - Clear the Canvas that holds the ProgressBar. + * - Update the ProgressBar. + * - Draw the ProgressBar onto the Canvas. + * - For 0 to \b blockheight and as long as we aren't trying to render off of the screen: + * - Update the ProgressBar. + * - Redraw the ProgressBar with labels for the ID of each thread above each segment of the ProgressBar. + * - Make an inner loop which determines whether to color the pixels black or a different color based off of whether they've escaped or not. + * - (Basic Mandelbrot calculations; see http://en.wikipedia.org/wiki/Mandelbrot_set#Computer_drawings ). + * - Break if the Canvas is to redraw. + * . + * - Handle any IO events (OS X version only). + * - Break if the Canvas is to redraw. + * . + * - Output the time it took to compute the screen. + * - While the Canvas has not been closed and it isn't time to redraw yet: + * - Sleep the thread for one frame until the Canvas is closed by the user or told to redraw. + * . + * . + * - If the ProgressBar Canvas is still open, close it up. + * . + * \param can Reference to the CartesianCanvas being drawn to. + * \param threads Reference to the number of threads passed via command-line arguments. + * \param depth The number of iterations to go to in order to draw the Mandelbrot set. + */ +void mandelbrotFunction(Cart& can, unsigned threads, unsigned depth) { + Mandelbrot m(threads,depth); //Make the object + m.bindings(can); //Bind the buttons + m.draw(can); //Draw the Mandelbrot object onto the Canvas +} + +/*! + * \brief Draws a Gradient Mandelbrot set on a CartesianCanvas. + * \details Same as mandelbrotFunction(), but with smoother shading and no ProgressBar. + * ( see http://linas.org/art-gallery/escape/smooth.html ). + * \param can Reference to the CartesianCanvas being drawn to. + * \param threads Reference to the number of threads to use. + * \param depth The number of iterations to go to in order to draw the Gradient Mandelbrot set. + * \see mandelbrotFunction(), GradientMandelbrot class. + */ +void gradientMandelbrotFunction(Cart& can, unsigned threads, unsigned depth) { + GradientMandelbrot m(threads,depth); //Create the GradientMandelbrot + m.bindings(can); //Bind the buttons + m.draw(can); //Draw it +} + +/*! + * \brief Draws a Buddhabrot set on a CartesianCanvas. + * \details Same as mandelbrotFunction(), but with a different shading algorithm and no + * ProgressBar. + * ( see https://en.wikipedia.org/wiki/Buddhabrot ). + * \param can Reference to the CartesianCanvas being drawn to. + * \param threads Reference to the number of threads to use. + * \param depth The number of iterations to go to in order to draw the Buddhabrot set. + */ +void buddhabrotFunction(Cart& can, unsigned threads, unsigned depth) { + Buddhabrot b(threads, depth); //Create the Buddhabrot object + b.draw(can); //Draw it +} + +/*! + * \brief Draws a Julia set. + * \details It is drawn in this way: + * - It is drawn in a similar way as the Mandelbrots are. + * - A class contains all of the necessary information to draw the Julia set. + * - When the Julia class object is made: + * - Set class instance variables for keeping track of the number of threads to use, + * the number of iterations, point coordinates for zooming in and out, and a redraw flag + * that determines when we should redraw the Julia object. + * . + * - When you bind buttons to the CartesianCanvas: + * - Bind the spacebar to clear the screen and redraw the Julia object. + * - Bind the left mouse button to zoom in and redraw the Julia object at the + * focused point. + * - Bind the right mouse button to zoom out and redraw the Julia object. + * - Bind the mouse wheel to zoom in and out when scrolled up and down (respectively) + * and redraw the Julia object. + * . + * - When you actually draw the Julia object onto the CartesianCanvas: + * - Store the window width of the Canvas. + * - Create a VisualTaskQueue object that displays how much work each thread did in drawing + * the Julia object. + * - While its time to redraw: + * - Set the redraw flag to false. + * - Reset the Canvas' internal timer to 0. + * - Reset the VisualTaskQueue object. + * - A parallel block is made using: \b myThreads threads. + * - Store the thread id number and the number of threads. + * - Store the thread color. + * - An infinite loop is made where the necessary calculations needed to draw the Julia + * object are made and the Julia object is drawn. Once the Julia object has been drawn, the + * loop is broken out of. Also, if the Canvas is not open or the redraw flag is set, the loop + * is also broken out of. Also, if one of the threads tries to render off of the screen, the loop + * is broken out of. The VisualTaskQueue is also updated in this loop, and if you are a Mac user, + * I/O events are handled here as well. + * . + * - Output the time it took for each iteration. + * - While the Canvas is open and the redraw flag is NOT set: + * - Sleep the internal timer until the next draw cycle. + * . + * . + * - Close the VisualTaskQueue. + * . + * . + * \param can Reference to the CartesianCanvas to draw to. + * \param threads Reference to the number of threads to use when drawing the Julia object. + * \param depth The number of iterations to go to in order to draw the Julia object. + */ +void juliaFunction(Cart& can, unsigned threads, unsigned depth) { + Julia j(threads,depth); //Create the Julia object + j.bindings(can); //Bind the buttons + j.draw(can); //Draw it +} + +/*! + * \brief Draws a Nova fractal (Newton fractal) on a CartesianCanvas. + * \param can Reference to the CartesianCanvas being drawn to. + * \param threads Reference to the number of threads to use. + * \param depth The number of iterations to go to in order to draw the Gradient Mandelbrot set. + * \see mandelbrotFunction(), Nova class. + */ +void novaFunction(Cart& can, unsigned threads, unsigned depth) { + Nova n(threads,depth); //Create the Nova object + n.bindings(can); //Bind the buttons + n.draw(can); //Draw it +} + +//Takes command line arguments for the width and height of the screen +//as well as the number of threads to use and the number of iterations to draw the Mandelbrot set +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + int w2 = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); //Julia + int h2 = (argc > 2) ? atoi(argv[2]) : 0.75*w; //Julia + int x = Canvas::getDisplayWidth() - w - 64; + if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid + w = 1200; + w2 = 1.2 * Canvas::getDisplayHeight(); + h = 900; //If not, set the width and height to a default value + h2 = 0.75 * w2; + } + unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use + if (t == 0) + t = omp_get_num_procs(); + unsigned d = (argc > 4) ? atoi(argv[4]) : MAX_COLOR; //Normal Mandelbrot + unsigned d2 = (argc > 4) ? atoi(argv[4]) : 32; //Gradient Mandelbrot & Nova + unsigned d3 = (argc > 4) ? atoi(argv[4]) : 1000; //Buddhabrot & Julia + //Normal Mandelbrot + std::cout << "Normal Mandelbrot" << std::endl; + Cart c1(-1, -1, w, h, -2, -1.125, 1, 1.125, "Mandelbrot", GRAY, FRAME / 2); + c1.run(mandelbrotFunction,t,d); + + //Gradient Mandelbrot + std::cout << "Gradient Mandelbrot" << std::endl; + Cart c2(-1, -1, w, h, -2, -1.125, 1, 1.125, "Gradient Mandelbrot", GRAY, FRAME / 2); + c2.run(gradientMandelbrotFunction,t,d2); + std::cout << "Buddhabrot" << std::endl; + + //Buddhabrot + Cart c3(-1, -1, w, h, -2, -1.125, 1, 1.125, "Buddhabrot", BLACK, FRAME / 2); + c3.run(buddhabrotFunction,t,d3); + + //Julia #FIXME requires a different library path + std::cout << "Julia set" << std::endl; + Cart c4(x, -1, w2, h2, -2, -1.125, 1, 1.125, "Julia Set", GRAY, FRAME / 2); + c4.run(juliaFunction,t,d3); + + //Nova + std::cout << "Nova" << std::endl; + Cart c5(x, -1, w, h, -1.0, -0.5, 0, 0.5, "Nova (Newton Fractal)", GRAY, FRAME / 2); + c5.zoom(-0.361883,-0.217078,0.1f); + c5.run(novaFunction,t,32); +} diff --git a/src/examples/MergeSort/testMergeSort.cpp b/src/examples/MergeSort/testMergeSort.cpp index 04e95382f..07f430c44 100644 --- a/src/examples/MergeSort/testMergeSort.cpp +++ b/src/examples/MergeSort/testMergeSort.cpp @@ -198,7 +198,6 @@ int main(int argc, char* argv[]) { int threads, t = (argc > 2) ? atoi(argv[2]) : omp_get_num_procs(); for (threads = 1; threads < t; threads *=2); //Force threads to be a power of 2 - Canvas c(0, 0, w, h, "Bottom-up Merge Sort"); - c.setBackgroundColor(BLACK); + Canvas c(0, 0, w, h, "Bottom-up Merge Sort", BLACK); c.run(mergeSortFunction, threads, s); } diff --git a/src/examples/NewtonPendulum/testNewtonPendulum.cpp b/src/examples/NewtonPendulum/testNewtonPendulum.cpp index 180361c3c..2ed14fbe5 100644 --- a/src/examples/NewtonPendulum/testNewtonPendulum.cpp +++ b/src/examples/NewtonPendulum/testNewtonPendulum.cpp @@ -128,7 +128,6 @@ int main(int argc, char * argv[]) { } else if(numberOfBalls % 2 == 0) { //If even, add 1 numberOfBalls++; } - Canvas c(-1, -1, w, h, "Newton's Pendulum"); - c.setBackgroundColor(WHITE); + Canvas c(-1, -1, w, h, "Newton's Pendulum", WHITE); c.run(newtonPendulumFunction,numberOfBalls); } diff --git a/src/examples/Pandemic/Pandemic.cpp b/src/examples/Pandemic/Pandemic.cpp index 18148d2f2..6902da864 100644 --- a/src/examples/Pandemic/Pandemic.cpp +++ b/src/examples/Pandemic/Pandemic.cpp @@ -1,156 +1,187 @@ #include "Pandemic.h" -#define RADIUS 5 // radius for the Person circles -#define infection_radius 30 +// person constants +#define PERSON_RADIUS 5 // the size of each person on screen +// text constants +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 20 // font size for all text +#define TEXT_COLOR ColorFloat(0.2,1,1,1) // color for all text (light blue) using namespace tsgl; -// Initializes the pandemic -Pandemic::Pandemic(Canvas& can, unsigned numPeople, unsigned numToInfect, unsigned infectionRate){ - // current day - current_day = 0; - // people counters - number_of_people = numPeople; - num_initially_infected = numToInfect; - // states counters - num_infected = numToInfect; - num_susceptible = numPeople - numToInfect; - num_immune = 0; - num_dead = 0; - - // stats - contagiousness_factor = infectionRate; - num_infections = numToInfect; - num_infection_attempts = 0; - num_deaths = 0; - num_recoveries = 0; - - // window dimensions - max_x = can.getWindowWidth()/2; - max_y = can.getWindowHeight()/2; - - // Generate random seed - srand( time(0) ); - // Fill vectors with infected - for(unsigned i = 0; i < num_infected; ++i){ - myPersons.push_back(new Person(rand()%(can.getWindowWidth())-max_x, - rand()%(can.getWindowHeight())-max_y, - RADIUS, infected)); // myPersons - x_locations.push_back(myPersons[i]->getX()); // x_locations - y_locations.push_back(myPersons[i]->getY()); // y_locations - infected_x_locations.push_back(myPersons[i]->getX()); // infected_x_locations - infected_y_locations.push_back(myPersons[i]->getY()); // infected_y_locations - // states.push_back(infected); // states - // num_days_infected.push_back(0); // num_days_infected - } - // Fill vectors with susceptible - for(unsigned i = num_infected; i < number_of_people; ++i){ - myPersons.push_back(new Person(rand()%(can.getWindowWidth())-max_x, - rand()%(can.getWindowHeight())-max_y, - RADIUS, susceptible)); // myPersons - x_locations.push_back(myPersons[i]->getX()); // x_locations - y_locations.push_back(myPersons[i]->getY()); // y_locations - infected_x_locations.push_back(0); // infected_x_locations - infected_y_locations.push_back(0); // infected_y_locations - // states.push_back(susceptible); // states - // num_days_infected.push_back(0); // num_days_infected +// To parse command line for custom program options +cxxopts::ParseResult parse(int argc, char* argv[]) { + try { + cxxopts::Options options("Pandemic Simulation", "- command line options"); + + options.positional_help("[optional args]").show_positional_help(); + + options.allow_unrecognised_options().add_options()("help", "Print help")( + "n, num", "the number of people in the model", cxxopts::value()->default_value("50"))( + "i, initial", "the number of initially infected people", cxxopts::value()->default_value("5"))( + "D, days", "the number of time days in the model", cxxopts::value()->default_value("60"))( + "T, sicktime", "the duration of the disease (in days)", cxxopts::value()->default_value("5"))( + "c, contagiousness" , "the contagiousness factor of the disease (0-100)", cxxopts::value()->default_value("50"))( + "r, radius", "the infection radius of the disease", cxxopts::value()->default_value("35"))( + "d, deadliness", "the deadliness factor of the disease (0-100)", cxxopts::value()->default_value("2"))( + "h, canvas-height", "TSGL canvas height", cxxopts::value()->default_value("600"))( + "w, canvas-width", "TSGL canvas width", cxxopts::value()->default_value("600")); + + auto results = options.parse(argc, argv); + + if (results.count("help")) { + std::cout << options.help({"", "Group"}) << std::endl; + exit(0); } + return results; + + } catch (const cxxopts::OptionSpecException& e) { + std::cout << "error parsing options: " << e.what() << std::endl; + exit(1); + } } -void Pandemic::draw(Canvas& can){ - for(unsigned i = 0; i < number_of_people; ++i){ - myPersons[i]->draw(can); + +Pandemic::Pandemic(Canvas& can, int argc, char* argv[]){ + // Parse command line + auto result = parse(argc, argv); + + // Set options TODO: add upper bounds on options, check options for validity + if (result["num"].as() > 0) { + myNumPersons = result["num"].as(); + } + if (result["initial"].as() > 0) { + my_num_initially_infected = result["initial"].as(); + } + if (result["days"].as() > 0) { + myNumDays = result["days"].as(); + } + if (result["sicktime"].as() > 0) { + mySickDuration = result["sicktime"].as(); + } + if (result["contagiousness"].as() >= 0) { + myContagiousFactor = result["contagiousness"].as(); + } + if (result["radius"].as() > 0) { + myInfectionRadius = result["radius"].as(); + } + if (result["deadliness"].as() >= 0) { + myDeadlinessFactor = result["deadliness"].as(); + } + if (result["canvas-width"].as() > 0) { + myWidth = result["canvas-width"].as(); + } + if (result["canvas-height"].as() > 0) { + myHeight = result["canvas-height"].as(); } -} -void Pandemic::updateStatuses(){ - for(unsigned i = 0; i < number_of_people; ++i){ - myPersons[i]->updateColor(); + my_num_currently_infected = my_num_initially_infected; + my_num_susceptible = myNumPersons - my_num_initially_infected; + my_total_num_infections = my_num_initially_infected; + my_total_num_infection_attempts = my_num_initially_infected; + + my_max_x = myWidth - PERSON_RADIUS; + my_max_y = myHeight - PERSON_RADIUS - FONT_SIZE; + + + // random number generator + std::uniform_int_distribution init_x_distr(-my_max_x, my_max_x); + std::uniform_int_distribution init_y_distr(-my_max_y, my_max_y); + std::uniform_int_distribution move_distr(-20, 20); + std::uniform_int_distribution chance_distr(1, 100); + + // Insert infected into array + for(int i = 0; i < my_num_initially_infected; ++i){ + myPeople.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + PERSON_RADIUS, infected, true)); + myPeople[i]->draw(can); } + // Insert susceptible into array + for(int i = my_num_initially_infected; i < myNumPersons; ++i){ + myPeople.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + PERSON_RADIUS, susceptible, true)); + myPeople[i]->draw(can); + } + + // Create text to display the current day + Text * myDayText = new Text(0, 300, 0, L"Day 1", FONT, FONT_SIZE, 0, 0, 0, TEXT_COLOR); + + myCan = &can; + // Create canvas for real-time data + myCan2 = new Canvas(0, 0, myWidth, myHeight,"Pandemic Data"); + myCan2->start(); + myCan2->setBackgroundColor(BLACK); + } -// void Pandemic::findInfected(){ -// for(unsigned i = 0; i < number_of_people; ++i){ -// if(myPersons[i]->getStatus() == infected){ -// infected_x_locations[i] = myPersons[i]->getX(); -// infected_y_locations[i] = myPersons[i]->getY(); -// } -// } -// } - -void Pandemic::movePersons(Canvas& can){ - float x_move_direction, y_move_direction; - for(unsigned i = 0; i < number_of_people; ++i){ - if(myPersons[i]->getStatus() != dead){ - // x_move_direction = ((rand()%3) - 1) * 10; - // y_move_direction = ((rand()%3) - 1) * 10; - x_move_direction = ((rand()%301)-150)/10; - y_move_direction = ((rand()%301)-150)/10; - - // Check if move is valid (within the window) - if((x_locations[i] + x_move_direction > -max_x) && - (x_locations[i] + x_move_direction < max_x) && - (y_locations[i] + y_move_direction > -max_y) && - (y_locations[i] + y_move_direction < max_y)) - { - // Move Person - myPersons[i]->changeXYBy(x_move_direction, y_move_direction); - // Update locations - x_locations[i] += x_move_direction; - y_locations[i] += y_move_direction; - // findInfected(); - } - } + +/** + * \brief Adds the Pandemic to the canvas. + * \param can The Canvas on which the Pandemic is to be drawn. + */ +void Pandemic::draw(){ + myCan->add(myDayText); + for(unsigned i = 0; i < myNumPersons; ++i){ + myPeople[i]->draw(*myCan); } } -void Pandemic::checkForInfection(){ - // For all people - for(unsigned i = 0; i < number_of_people; ++i){ - if(myPersons[i]->getStatus() == susceptible){ - // For those that are susceptible, check if there are any infected nearby - for(unsigned j = 0; j < number_of_people; ++j){ - if(myPersons[j]->getStatus() == infected){ - // Check if susceptible person is in infection radius - // printf("X: %f %f Y: %f %f\n", myPersons[i]->getX(), myPersons[j]->getX(), myPersons[i]->getY(), myPersons[j]->getY()); - if((myPersons[i]->getX() > myPersons[j]->getX() - infection_radius) && - (myPersons[i]->getX() < myPersons[j]->getX() + infection_radius) && - (myPersons[i]->getY() > myPersons[j]->getY() - infection_radius) && - (myPersons[i]->getY() < myPersons[j]->getY() + infection_radius)) - { // ISSUE IS WITH THE FOR LOOPS: SOMEHOW NOT EVERYTHING IS GETTING CHECKED, OR AT LEAST NOT GETTING CHECKED CORRECTLY - printf("AT RISK: PERSON %d\n", i); - ++num_infection_attempts; - // // Determine if person gets infected - // printf("RandNum: %d\n", randNum); - if(rand()%101 <= contagiousness_factor){ - printf("PERSON %d INFECTED\n", i); - myPersons[i]->setStatus(infected); - myPersons[i]->updateColor(); - ++num_infected; - // printf("num_infected increased to %d\n", num_infected); - --num_susceptible; - break; // to break out of the j for loop - } - } - } - } - } +void Pandemic::printInitialInfo(){ + printf("\n***********************\ + \n* Initial information *\ + \n***********************\ + \n\ + \nChance of infection: %d%%\ + \nDaily chance of death: %d%%\ + \n\ + \nStarting number of people infected: %d\ + \nTotal number of people: %d\ + \n\n", myContagiousFactor, myDeadlinessFactor, my_num_initially_infected, myNumPersons); +} + +void Pandemic::printFinalInfo(){ + // To avoid a divide-by-zero error (in case there were no infection attempts) + if(my_total_num_infection_attempts != 0){ + my_true_contagiousness = (my_total_num_infections/static_cast(my_total_num_infection_attempts)) * 100.0; } + my_true_mortality = (my_total_num_deaths/static_cast(my_total_num_death_attempts)) * 100.0; + + printf("\n***********************\ + \n* Statistics and data *\ + \n***********************\ + \n\ + \n*** Population after %d days ***\ + \nSusceptible: %d\ + \nInfected: %d\ + \nImmune: %d\ + \nDead: %d\ + \n", myNumDays, my_num_susceptible, my_num_currently_infected, + my_total_num_recoveries, my_total_num_deaths); + printf("\n*** Statistics ***\ + \nTotal number of infections: %d\ + \nTotal number of deaths: %d\ + \nTotal number of recoveries: %d\ + \nTrue contagiousness: %.2f%%\ + \nTrue mortality rate: %.2f%%\ + \n", my_total_num_infections, my_total_num_deaths, my_total_num_recoveries, + my_true_contagiousness, my_true_mortality); } /*! * \brief Destructor for Pandemic. */ Pandemic::~Pandemic(){ - for(unsigned i = 0; i < number_of_people; ++i){ - delete myPersons[i]; - } - myPersons.clear(); - x_locations.clear(); - y_locations.clear(); - infected_x_locations.clear(); - infected_y_locations.clear(); - // states.clear(); - // num_days_infected.clear(); + for(unsigned i = 0; i < myPeople.size(); ++i){ + delete myPeople[i]; + } + for(unsigned i = 0; i < myDataText.size(); ++i){ + delete myDataText[i]; + } + delete myDayText; + if (myCan2->isOpen()) + myCan2->stop(); + delete myCan2; + myPeople.clear(); + myDataText.clear(); } \ No newline at end of file diff --git a/src/examples/Pandemic/Pandemic.h b/src/examples/Pandemic/Pandemic.h index aee4f70de..33c5595b9 100644 --- a/src/examples/Pandemic/Pandemic.h +++ b/src/examples/Pandemic/Pandemic.h @@ -1,99 +1,62 @@ #ifndef PANDEMIC_H_ #define PANDEMIC_H_ -#include +#include +#include #include +#include +#include +#include #include "Person.h" -#include "statusEnums.h" using namespace tsgl; class Pandemic { -private: - char* myName; protected: - // persons - std::vector myPersons; - // current day - unsigned current_day; - // people counters - unsigned number_of_people; - unsigned num_initially_infected; - // states counters - unsigned num_infected; - unsigned num_susceptible; - unsigned num_immune; - unsigned num_dead; - // locations - std::vector x_locations; - std::vector y_locations; - //infected people's locations - std::vector infected_x_locations; - std::vector infected_y_locations; - // state - // std::vector states; - // infected time - // std::vector num_days_infected; - - // window dimensions - float max_x; - float max_y; - + int myNumPersons; + int myInfectionRadius; + // time + int myNumDays; + int mySickDuration; + // counters + int my_num_initially_infected; + int my_num_currently_infected; + int my_num_susceptible; + // pandemic factors + int myContagiousFactor; + int myDeadlinessFactor; // stats - unsigned contagiousness_factor; - unsigned num_infections; - unsigned num_infection_attempts; - unsigned num_deaths; - unsigned num_recoveries; + int my_total_num_infections; + int my_total_num_infection_attempts; + int my_total_num_deaths; + int my_total_num_death_attempts; + int my_total_num_recoveries; + float my_true_contagiousness; + float my_true_mortality; + // window dimensions + int myWidth, myHeight; + float my_max_x, my_max_y; + + // People + std::vector myPeople; + // Text + Text * myDayText; + std::vector myDataText; + // Random generator + std::default_random_engine generator; + + // Canvas + Canvas *myCan, *myCan2; public: - Pandemic(Canvas& can, unsigned numPeople, unsigned numToInfect, unsigned infectionRate); - - void draw(Canvas& can); - - // Accessors - Person * getPerson(unsigned i) { return myPersons[i]; } - - unsigned getCurrentDay() { return current_day; } - - unsigned getNumPeople() { return number_of_people; } - - unsigned getNumInitiallyInfected() { return num_initially_infected; } - - unsigned getNumInfected() { return num_infected; } - - unsigned getNumSusceptible() { return num_susceptible; } - - unsigned getNumImmune() { return num_immune; } - - unsigned getNumDead() { return num_dead; } - - int getXLocation(unsigned i) { return x_locations[i]; } - - int getYLocation(unsigned i) { return y_locations[i]; } - - int getInfectedXLocation(unsigned i) { return infected_x_locations[i]; } - - int getInfectedYLocation(unsigned i) { return infected_y_locations[i]; } - - unsigned getNumInfections() { return num_infections; } - - unsigned getNumInfectionAttempts() { return num_infection_attempts; } - - unsigned getNumDeaths() { return num_deaths; } - - unsigned getNumRecoveries() { return num_recoveries; } - - - // Utility - void updateStatuses(); + Pandemic(Canvas& can, int argc, char* argv[]); - // void findInfected(); + void draw(); - void movePersons(Canvas& can); + void printInitialInfo(); - void checkForInfection(); + void printFinalInfo(); virtual ~Pandemic(); }; -#endif /* PANDEMIC_H_ */ \ No newline at end of file +#endif /* Pandemic_H_ */ \ No newline at end of file diff --git a/src/examples/Pandemic/Person.cpp b/src/examples/Pandemic/Person.cpp index 628525d56..beecf1769 100644 --- a/src/examples/Pandemic/Person.cpp +++ b/src/examples/Pandemic/Person.cpp @@ -2,34 +2,61 @@ using namespace tsgl; -Person::Person(float x, float y, GLfloat radius, char status){ +Person::Person(){ + // Initialize random seed and random + srand( time(0) ); + myX = rand()%1016; + myY = rand()%286; + myCircleRadius = 5; + myStatus = susceptible; + numInfectedNearby = 0; + numDaysInfected = 0; + myColor = ColorFloat(1,1,0,1); // yellow + + // Create visual representation + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); + // myInfectionCircle = new Circle(myX, myY, 0.0, 50, 0.0, 0.0, 0.0, ColorFloat(1,0.5,0,0)); + myInfectionCircle = new Square(myX, myY, 0.0, 70, 0.0, 0.0, 0.0, ColorFloat(1,0.5,0,0)); +} + +Person::Person(float x, float y, GLfloat radius, char status, bool showInfectedRadius){ + // myID = id; myX = x; myY = y; myCircleRadius = radius; myStatus = status; numInfectedNearby = 0; + numDaysInfected = 0; + hasInfectedRadius = showInfectedRadius; // Determine color switch(myStatus){ case susceptible : - myColor = ColorFloat(1,1,0,1); + myColor = ColorFloat(1,1,0,1); // yellow break; case infected : - myColor = ColorFloat(1,0,0,1); + myColor = ColorFloat(1,0,0,1); // red break; case immune : - myColor = ColorFloat(0,1,0,1); + myColor = ColorFloat(0,1,0,1); // green break; case dead : - myColor = ColorFloat(0.5,0.5,0.5,1); + myColor = ColorFloat(0.5,0.5,0.5,1); // grey break; default: - myColor = ColorFloat(0,0,0,1); + myColor = ColorFloat(0,0,0,1); // black } // Create visual representation myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); - + if(showInfectedRadius){ + ColorFloat infectedRadiusColor = ColorFloat(0,0,0,0); + if(myStatus == infected){ + infectedRadiusColor = ColorFloat(1,0.5,0,0.5); + } + myInfectionCircle = new Square(myX, myY, 0.0, 70, 0.0, 0.0, 0.0, infectedRadiusColor); + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + } } /** @@ -37,6 +64,9 @@ Person::Person(float x, float y, GLfloat radius, char status){ * \param can The Canvas on which the Person is to be drawn. */ void Person::draw(Canvas& can){ + if(myStatus == infected){ + can.add(myInfectionCircle); + } can.add(myCircle); } @@ -49,144 +79,109 @@ void Person::setStatus(char status){ * \brief Sets the radius of the Person's Circle to a new radius. * \param radius The new radius. */ -void Person::setCircleRadius(GLfloat radius){ - myCircle->setRadius(radius); -} +// void Person::setCircleRadius(GLfloat radius){ +// myCircle->setRadius(radius); +// } -void Person::changeXYBy(float x, float y){ - myCircle->changeXBy(x); myCircle->changeYBy(y); +void Person::moveBy(float x, float y, float max_x, float max_y){ + // Check if move is valid (within the window) + if((myX + x > -max_x) && (myX + x < max_x) && + (myY + y > -max_y) && (myY + y < max_y)) { + // Move Person + myCircle->changeXBy(x); myCircle->changeYBy(y); + myInfectionCircle->changeXBy(x); myInfectionCircle->changeYBy(y); + // Update info + myX += x; myY += y; + } } /** * \brief Sets the Person's Cubes to a new color. */ -void Person::updateColor(){ - switch(myStatus){ - case susceptible : - myColor = ColorFloat(1,1,0,1); - break; - case infected : - myColor = ColorFloat(1,0,0,1); - break; - case immune : - myColor = ColorFloat(0,1,0,1); - break; - case dead : - myColor = ColorFloat(0.5,0.5,0.5,1); - break; - default: - myColor = ColorFloat(0,0,0,1); - } - myCircle->setColor(myColor); -} - -// /** -// * \brief Sets the Person's Cubes to new colors. -// * \param c The new array of ColorFloats. -// * \param size The size of the array of ColorFloats -// */ -// void Person::setColor(ColorFloat c[], unsigned size){ -// for(unsigned i = 0; i < mySize; ++i){ -// myCubes[i]->setColor(c[i%size]); +// void Person::updateColor(){ +// ColorFloat infectedRadiusColor = ColorFloat(0,0,0,0); +// switch(myStatus){ +// case susceptible : +// myColor = ColorFloat(1,1,0,1); // yellow +// break; +// case infected : +// myColor = ColorFloat(1,0,0,1); // red +// infectedRadiusColor = ColorFloat(1,0.5,0,0.5); // orange +// break; +// case immune : +// myColor = ColorFloat(0,1,0,1); // green +// break; +// case dead : +// myColor = ColorFloat(0.5,0.5,0.5,1); // gray +// break; +// default: +// myColor = ColorFloat(0,0,0,1); // black // } -// } - -// /** -// * \brief Sets the Person's Text/numbers to a new color. -// * \param color The new ColorFloat. -// */ -// void Person::setTextColor(ColorFloat color){ -// for(Text * t : myText){ -// t->setColor(color); +// myCircle->setColor(myColor); +// if(hasInfectedRadius){ +// myInfectionCircle->setColor(infectedRadiusColor); // } // } -// /** -// * \brief Sets the font of the Person's Text/numbers to a new font. -// * \param filename The path and file name of the font. -// */ -// void Person::setFont(std::string filename){ -// for(Text * t : myText){ -// t->setFont(filename); -// } -// } - -// /** -// * \brief Sets the font size of the Person's Text/numbers to a new size. -// * \param fontsize The new font size. -// */ -// void Person::setFontSize(unsigned int fontsize){ -// for(Text * t : myText){ -// t->setFontSize(fontsize); -// } -// } - - -// void Person::changeYawBy(GLfloat yaw){ -// for(unsigned i = 0; i < mySize; ++i){ -// myCubes[i]->changeYawBy(yaw); -// myText[i]->changeYawBy(yaw); -// } -// } - -// void Person::changePitchBy(GLfloat pitch){ -// for(unsigned i = 0; i < mySize; ++i){ -// myCubes[i]->changePitchBy(pitch); -// myText[i]->changePitchBy(pitch); -// } -// } - -// void Person::changeRollBy(GLfloat roll){ -// for(unsigned i = 0; i < mySize; ++i){ -// myCubes[i]->changeRollBy(roll); -// myText[i]->changeRollBy(roll); -// } -// } - -// void Person::visualSplit(unsigned index){ -// for(unsigned i = 0; i < index; ++i){ -// myCubes[i]->changeXBy(-myCubeSideLength/2.0); -// myText[i]->changeXBy(-myCubeSideLength/2.0); -// } -// for(unsigned i = index; i < mySize; ++i){ -// myCubes[i]->changeXBy(myCubeSideLength/2.0); -// myText[i]->changeXBy(myCubeSideLength/2.0); -// } -// } - -// // void Person::visualRegroup(unsigned index){ - -// // } +bool Person::checkIfInfectedNearby(std::vector personVec, float infectedRadius){ + for(unsigned i = 0; i < personVec.size(); ++i){ + // Search for all people who are infected + if(personVec[i]->getStatus() == infected){ + // Check if susceptible person is in infection radius + if((myX > personVec[i]->getX() - infectedRadius) && + (myX < personVec[i]->getX() + infectedRadius) && + (myY > personVec[i]->getY() - infectedRadius) && + (myY < personVec[i]->getY() + infectedRadius)) + { + ++numInfectedNearby; + return true; + } + } + } + return false; +} -// void Person::visualRegroupAll(float x){ -// for(unsigned i = 0; i < mySize; i++){ -// myCubes[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); -// myText[i]->setCenterX((x-(int)(mySize-1)*(myCubeSideLength/2.0)) + (i * myCubeSideLength)); -// } -// } +bool Person::determineIfInfected(Canvas& can, int contagiousFactor, int randNum){ + if(numInfectedNearby >= 1 && randNum <= contagiousFactor){ + myStatus = infected; + myCircle->setColor(ColorFloat(1,0,0,1)); // red + if(hasInfectedRadius){ + myInfectionCircle->setColor(ColorFloat(1,0.5,0,0.5)); // orange + can.add(myInfectionCircle); + } + numInfectedNearby = 0; + return true; + } + return false; +} +bool Person::determineIfDead(Canvas& can, int deadlinessFactor, int randNum){ + if(randNum <= deadlinessFactor){ + myStatus = dead; + myCircle->setColor(ColorFloat(0.5,0.5,0.5,1)); // grey + if(hasInfectedRadius){ + can.remove(myInfectionCircle); + } + numInfectedNearby = 0; + return true; + } + return false; +} -// /** -// * \brief If the sizes are equal, adds the values of two Persons and returns -// * the sums in a new Person. -// * If the sizes are not equal, returns a default-constructed Person. -// * \param c2 The Person to be added with the current one. -// */ -// Person Person::operator+(Person& c2){ -// if(mySize == c2.getSize()){ -// int summedArray[mySize]; -// for(unsigned i = 0; i < mySize; i++){ -// summedArray[i] = myData[i] + c2[i]; -// printf("%.2d\n", summedArray[i]); -// } -// return Person(0, 0, 0, myCubeSideLength, mySize, summedArray, mySize, myYaw, myPitch, myRoll, RED, WHITE); -// } -// return Person(); -// } +void Person::recover(Canvas& can){ + myStatus = immune; + myCircle->setColor(ColorFloat(0,1,0,1)); + if(hasInfectedRadius){ + can.remove(myInfectionCircle); + } +} /*! - * \brief Destructor for Table. + * \brief Destructor for Person. */ Person::~Person(){ delete myCircle; + if(hasInfectedRadius){ + delete myInfectionCircle; + } } \ No newline at end of file diff --git a/src/examples/Pandemic/Person.h b/src/examples/Pandemic/Person.h index e95f79cdd..86e053c4e 100644 --- a/src/examples/Pandemic/Person.h +++ b/src/examples/Pandemic/Person.h @@ -1,7 +1,7 @@ #ifndef PERSON_H_ #define PERSON_H_ -#include +#include #include "Circle.h" #include "statusEnums.h" @@ -9,20 +9,22 @@ using namespace tsgl; class Person { protected: + // int myID; float myX, myY; GLfloat myCircleRadius; Circle* myCircle; - // Circle* myCircle[1]; + Square* myInfectionCircle; ColorFloat myColor; + bool hasInfectedRadius; // Pandemic data char myStatus; - unsigned numInfectedNearby; - unsigned numDaysInfected; + int numInfectedNearby; + int numDaysInfected; public: - // Person(); + Person(); - Person(float x, float y, GLfloat radius, char status); + Person(float x, float y, GLfloat radius, char status, bool hasInfectedRadius); void draw(Canvas& can); @@ -38,44 +40,28 @@ class Person { char getStatus() { return myStatus; } - unsigned getNumDaysInfected() { return numDaysInfected; } + int getNumDaysInfected() { return numDaysInfected; } // // Mutators void setStatus(char status); - void setCircleRadius(GLfloat radius); + // void setCircleRadius(GLfloat radius); - void changeXYBy(float x, float y); + void moveBy(float x, float y, float max_x, float max_y); - void updateColor(); - - // void setColor(ColorFloat c); - - // void setColor(ColorFloat c[], unsigned size); - - // void setTextColor(ColorFloat c); - - // void setFont(std::string filename); - - // void setFontSize(unsigned int fontsize); + // void updateColor(); + bool checkIfInfectedNearby(std::vector personVec, float infectionRadius); - // void changeYawBy(GLfloat yaw); + void increaseNumDaysInfected() { numDaysInfected += 1; } - // void changePitchBy(GLfloat pitch); - - // void changeRollBy(GLfloat roll); - - // void visualSplit(unsigned index); - - // void visualRegroupAll(float x); + bool determineIfInfected(Canvas& can, int contagiousFactor, int randNum); + + bool determineIfDead(Canvas& can, int deadlinessFactor, int randNum); - // // Operations - // CubeArray operator+ (CubeArray& c2); + void recover(Canvas& can); - // bool operator==(CubeArray& a2); - virtual ~Person(); }; diff --git a/src/examples/Pandemic/testPandemic.cpp b/src/examples/Pandemic/testPandemic.cpp index eeb2237dc..5f3a1ecc6 100644 --- a/src/examples/Pandemic/testPandemic.cpp +++ b/src/examples/Pandemic/testPandemic.cpp @@ -1,100 +1,94 @@ /* * testPandemic.cpp * - * Usage: ./testPandemic [numPersons] [infectionRate] + * Usage: ./testPandemic [numPersons] [contagiousFactor] 1 <= numPersons <= 200, defaults to 50 - 0 <= infectionRate <= 100, defaults to 20 + 0 <= contagiousFactor <= 100, defaults to 50 */ -#include -#include -#include "Person.h" #include "Pandemic.h" -// disease constants -#define INFECTION_RADIUS 10 -#define NUM_TO_INFECT 10 -// #define DURATION_OF_DISEASE -// #define contagiousness_factor; -// #define deadliness_factor; // -// time constants -#define NUM_DAYS 365 // total number of days for pandemic -#define MS_PER_DAY 200000; // microseconds per day - using namespace tsgl; -void pandemicFunction(Canvas& can, unsigned numPersons, unsigned infectionRate) { - // Generate random seed - srand( time(0) ); +void pandemicFunction(Canvas& can, int argc, char* argv[]) { + + Pandemic p(can, argc, argv); - // Create Pandemic - Pandemic * p = new Pandemic(can, numPersons, NUM_TO_INFECT, infectionRate); + p.draw(); - float sleepTime = 0.03125; // initial number of seconds to sleep 0.03125 + float sleepTime = 1; // initial number of seconds to sleep 0.03125 // Key bindings to speed up/slow down animation - can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ - sleepTime /= 2; - }); - can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ - if(sleepTime < 1){ - sleepTime *= 2; - } - }); - - p->draw(can); + // can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + // sleepTime /= 2; + // }); + // can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + // if(sleepTime < 1){ + // sleepTime *= 2; + // } + // }); - unsigned complete = 0; // ensures simulation only runs once - printf("%d\n", infectionRate); + int complete = 0; // ensures simulation only runs once while (can.isOpen()) { - if(complete == 0){ - for(unsigned currentDay = 0; currentDay < NUM_DAYS; ++currentDay){ - printf("********Day %d********\n", currentDay+1); - p->updateStatuses(); - // p->findInfected(); - can.sleepFor(sleepTime); - p->movePersons(can); - can.sleepFor(sleepTime); - p->checkForInfection(); - } - complete = 1; - } - } + // if(complete == 0){ + // for(unsigned currentDay = 0; currentDay < numDays; ++currentDay){ + // // Update day number + // dayText->setText(L"Day " + std::to_wstring(currentDay+1)); - // Output - printf("\n***********************\ - \n* Statistics and data *\ - \n***********************\ - \n\ - \nInfection rate: %.2f\ - \n\ - \nSusceptible: %d\ - \nInfected: %d\ - \nImmune: %d\ - \nDead: %d\ - \n", infectionRate/100.0, p->getNumSusceptible(), p->getNumInfected(), p->getNumImmune(), p->getNumDead()); + // #pragma omp parallel num_threads(numPersons) + // { + // int id = omp_get_thread_num(); + + // if(personVec[id]->getStatus() != dead){ + // // Move people + // personVec[id]->moveBy(move_distr(generator), move_distr(generator), max_x, max_y); + // can.sleepFor(sleepTime); + + // // If person is infected + // if(personVec[id]->getStatus() == infected){ + // ++total_num_death_attempts; + // // Check if the person has died + // if(personVec[id]->determineIfDead(can, deadlinessFactor, chance_distr(generator))){ + // --num_currently_infected; + // ++total_num_deaths; + // // printf("Person %d dead.\n", id); + // } + // // Check if person has been infected for the duration of the disease + // else if(personVec[id]->getNumDaysInfected() >= sickDuration){ + // --num_currently_infected; + // ++total_num_recoveries; + // personVec[id]->recover(can); + // } + // // If not dead or recovered, increase number of days infected by 1 + // else{ + // personVec[id]->increaseNumDaysInfected(); + // } + // } - // Deallocate all object memory - delete p; + // // If person is susceptible + // if(personVec[id]->getStatus() == susceptible){ + // // Check if the person is within an infected radius + // if(personVec[id]->checkIfInfectedNearby(personVec, infectionRadius)){ + // ++total_num_infection_attempts; + // // Determine if the person has been infected + // if(personVec[id]->determineIfInfected(can, contagiousFactor, chance_distr(generator))){ + // --num_susceptible; + // ++num_currently_infected; + // ++total_num_infections; + // } + // } + // } + // } + // } // end pragma + // } // end the 'days' for loop + // complete = 1; + // } + } // end main while loop } int main(int argc, char* argv[]){ - int numPersons = (argc > 1) ? atoi(argv[1]) : 50; - int infectionRate = (argc > 2) ? atoi(argv[2]) : 100; - - // Checks validity of numPersons and infectionRate; if invalid, set to default - if((numPersons <= 0 or numPersons > 200) || (infectionRate < 0 or infectionRate > 100)){ - printf("Invalid argument(s).\ - \nUsage: ./testPandemic [numPersons] [infectionRate]\n \ - 1 <= numPersons <= 200\ - 0 <= infectionRate <= 100 \ - \nUsing default parameters...\n"); - numPersons = 50; - infectionRate = 20; - } - Canvas c(0, -1, 620, 620, "Pandemic Simulation"); c.setBackgroundColor(BLACK); - c.run(pandemicFunction, numPersons, infectionRate); + c.run(pandemicFunction, argc, argv); } diff --git a/src/examples/ParallelPandemic/Makefile b/src/examples/ParallelPandemic/Makefile new file mode 100644 index 000000000..435ae7cfc --- /dev/null +++ b/src/examples/ParallelPandemic/Makefile @@ -0,0 +1,63 @@ +# Makefile for Pandemic + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = statusEnums.h + +# Main source file +TARGET = testPandemic + +# Object files +ODIR = obj +_OBJ = Person.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ParallelPandemic/Person.cpp b/src/examples/ParallelPandemic/Person.cpp new file mode 100644 index 000000000..2fc3f1713 --- /dev/null +++ b/src/examples/ParallelPandemic/Person.cpp @@ -0,0 +1,212 @@ +#include "Person.h" + +using namespace tsgl; + +Person::Person(){ + // location + myX = 0; + myY = 0; + // radius + myCircleRadius = 5; + myInfectionRadius = 35; + hasInfectionRadius = false; + // infection data + myStatus = susceptible; + numInfectedNearby = 0; + numDaysInfected = 0; + isToDie = false; + myNumDaysTillDead = 0; + + // Create visual representation of person + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, ColorFloat(1,1,0,1)); // yellow + // if hasInfectionRadius is set to true, create visual representation of infection radius + if(hasInfectionRadius){ + ColorFloat infectionRadiusColor = ColorFloat(0,0,0,0); + if(myStatus == infected){ + infectionRadiusColor = ColorFloat(1,0.5,0,0.5); + } + myInfectionCircle = new Circle(myX, myY, 0.0, myInfectionRadius-myCircleRadius, // ensures that only a small part of + // a person needs to be in the visible + // radius to be at risk of infection + 0.0, 0.0, 0.0, infectionRadiusColor); + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + } +} + +Person::Person(float x, float y, GLfloat radius, float infectionRadius, char status, bool showInfectionRadius){ + // location + myX = x; + myY = y; + // radius + myCircleRadius = radius; + myInfectionRadius = infectionRadius; + hasInfectionRadius = showInfectionRadius; + // infection data + myStatus = status; + numInfectedNearby = 0; + numDaysInfected = 0; + isToDie = false; + myNumDaysTillDead = 0; + + // Determine color + switch(myStatus){ + case susceptible : + myColor = ColorFloat(1,1,0,1); // yellow + break; + case infected : + myColor = ColorFloat(1,0,0,1); // red + break; + case immune : + myColor = ColorFloat(0,1,0,1); // green + break; + case dead : + myColor = ColorFloat(0.5,0.5,0.5,1); // grey + break; + default: + myColor = ColorFloat(0,0,0,1); // black + } + + // Create visual representation of person + myCircle = new Circle(myX, myY, 0.0, myCircleRadius, 0.0, 0.0, 0.0, myColor); + // if hasInfectionRadius is set to true, create visual representation of infection radius + if(hasInfectionRadius){ + ColorFloat infectionRadiusColor = ColorFloat(0,0,0,0); + if(myStatus == infected){ + infectionRadiusColor = ColorFloat(1,0.5,0,0.5); + } + myInfectionCircle = new Circle(myX, myY, 0.0, myInfectionRadius-myCircleRadius, // ensures that only a small part of + // a person needs to be in the visible + // radius to be at risk of infection + 0.0, 0.0, 0.0, infectionRadiusColor); + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + } +} + +/** + * \brief Adds the Person to the canvas. + * \param can The Canvas on which the Person is to be drawn. + */ +void Person::draw(Canvas& can){ + if(hasInfectionRadius){ + if(myStatus == infected){ + can.add(myInfectionCircle); + } + } + can.add(myCircle); +} + + +void Person::setStatus(char status){ + myStatus = status; +} + +/** + * \brief Sets the radius of the Person's Circle to a new radius. + * \param radius The new radius. + */ +void Person::setColor(ColorFloat c){ + myCircle->setColor(c); +} + +void Person::moveBy(float x, float y, float max_x, float max_y){ + // Check if move is valid (within the window) + if((myX + x > -max_x) && (myX + x < max_x) && + (myY + y > -max_y) && (myY + y < max_y)) { + // Move Person + myCircle->changeXBy(x); myCircle->changeYBy(y); + if(hasInfectionRadius){ + myInfectionCircle->changeXBy(x); myInfectionCircle->changeYBy(y); + } + // Update info + myX += x; myY += y; + } +} + +bool Person::checkIfInfectedNearby(std::vector personVec){ + for(unsigned i = 0; i < personVec.size(); ++i){ + // Search for all people who are infected + if(personVec[i]->getStatus() == infected){ + // Check if susceptible person is in infection radius + unsigned distance = sqrt( pow(myX - personVec[i]->getX(), 2) + pow(myY - personVec[i]->getY(), 2) ); + // if((myX > personVec[i]->getX() - personVec[i]->getInfectionRadius()) && + // (myX < personVec[i]->getX() + personVec[i]->getInfectionRadius()) && + // (myY > personVec[i]->getY() - personVec[i]->getInfectionRadius()) && + // (myY < personVec[i]->getY() + personVec[i]->getInfectionRadius())) + if(distance < personVec[i]->getInfectionRadius() + myCircleRadius) + { + ++numInfectedNearby; + return true; + } + } + } + return false; +} + +bool Person::determineIfInfected(Canvas& can, int contagiousFactor, int randNum){ + if(numInfectedNearby >= 1 && randNum <= contagiousFactor){ + myStatus = infected; + myCircle->setColor(ColorFloat(1,0,0,1)); // red + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(1,0.5,0,0.5)); // orange + can.add(myInfectionCircle); + } + numInfectedNearby = 0; + return true; + } + return false; +} + +void Person::determineIsToDie(int deadlinessFactor, int randNum, int daysTillDead){ + // Determine if person will die + if(randNum <= deadlinessFactor){ + isToDie = true; + // Determine number of days until person will die + myNumDaysTillDead = daysTillDead; + } + // myStatus = dead; + // myCircle->setColor(ColorFloat(0.5,0.5,0.5,1)); // grey + // if(hasInfectionRadius){ + // myInfectionCircle->setColor(ColorFloat(0,0,0,0)); // make circle transparent to ensure it isn't visible + // myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + // can.remove(myInfectionCircle); + // // hasInfectionRadius = false; + // } + // numInfectedNearby = 0; + // return true; + // } + // return false; +} + +void Person::die(Canvas& can){ + myStatus = dead; + myCircle->setColor(ColorFloat(0.5,0.5,0.5,1)); // grey + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(0,0,0,0)); // make circle transparent to ensure it isn't visible + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + can.remove(myInfectionCircle); + // hasInfectionRadius = false; + numInfectedNearby = 0; + } +} + +void Person::recover(Canvas& can){ + myStatus = immune; + myCircle->setColor(ColorFloat(0,1,0,1)); // green + if(hasInfectionRadius){ + myInfectionCircle->setColor(ColorFloat(0,0,0,0)); // make circle transparent to ensure it isn't visible + myInfectionCircle->setOutlineColor(ColorFloat(0,0,0,0)); + can.remove(myInfectionCircle); + // hasInfectionRadius = false; + numInfectedNearby = 0; + } +} + +/*! + * \brief Destructor for Person. + */ +Person::~Person(){ + delete myCircle; + if(hasInfectionRadius){ + delete myInfectionCircle; + } +} \ No newline at end of file diff --git a/src/examples/ParallelPandemic/Person.h b/src/examples/ParallelPandemic/Person.h new file mode 100644 index 000000000..084b9d8e5 --- /dev/null +++ b/src/examples/ParallelPandemic/Person.h @@ -0,0 +1,88 @@ +#ifndef PERSON_H_ +#define PERSON_H_ + +#include +#include +#include +#include "Circle.h" +#include "statusEnums.h" + +using namespace tsgl; + +class Person { +protected: + // location + float myX, myY; + // radius + GLfloat myCircleRadius; + float myInfectionRadius; + bool hasInfectionRadius; + // TSGL shapes/objects + Circle* myCircle; + Circle* myInfectionCircle; + ColorFloat myColor; + // infection data + char myStatus; + int numInfectedNearby; + int numDaysInfected; + bool isToDie; + int myNumDaysTillDead; +public: + // Constructors // + + Person(); + + Person(float x, float y, GLfloat radius, float infectionRadius, char status, bool hasInfectedRadius); + + // Draw // + + void draw(Canvas& can); + + // Accessors// + + GLfloat getCircleRadius() { return myCircleRadius; } + + float getInfectionRadius() { return myInfectionRadius; } + + Circle * getCircle() { return myCircle; } + + float getX() { return myX; } + + float getY() { return myY; } + + char getStatus() { return myStatus; } + + int getNumDaysInfected() { return numDaysInfected; } + + bool willDie() { return isToDie; } + + int getNumDaysTillDead() { return myNumDaysTillDead; } + + // Mutators // + + void setStatus(char status); + + void setColor(ColorFloat c); + + void moveBy(float x, float y, float max_x, float max_y); + + // Checking/updating functions // + + bool checkIfInfectedNearby(std::vector personVec); + + void increaseNumDaysInfected() { numDaysInfected += 1; } + + bool determineIfInfected(Canvas& can, int contagiousFactor, int randNum); + + // bool determineIfDead(Canvas& can, int deadlinessFactor, int randNum); + + void determineIsToDie(int deadlinessFactor, int randNum, int daysTillDead); + + void die(Canvas& can); + + void recover(Canvas& can); + + virtual ~Person(); +}; + +#endif /* PERSON_H_ */ \ No newline at end of file diff --git a/src/examples/ParallelPandemic/obj/Person.o b/src/examples/ParallelPandemic/obj/Person.o new file mode 100644 index 0000000000000000000000000000000000000000..16e7499c9da43987eb9e858a8b4aba194efceade GIT binary patch literal 318592 zcmd?S33wD$);@l#(@DBh328zg0b&S<3KGb^G!hb)mS&Fx5J7E{PA5dOwA~#7t{|u& zgQB>v3~o5?JMJJ3>bRkf%ea4T!?+EjpMEYg!|y%k*4CXg35@^endkZEN%gHd_nh~f zd+vU#>Q>|VV+H-Kd)h7@;WN7!7YVG0@VWe1HBgA0WFeMbXJ^9e_{|fwOUE_VN9rwn zJ)PEw+8yH>!r`bmCF+VVRuNw)8gL6@uFHw$1zyd#714b2fj8kWAuhXF+DE@NqOfLM zFq&@%=$mqdctYbV)c6WYabo$)!+Gs63jwEjuG*yqr6o~B2d;uKd^N7Znu5w`zEtq7 z0N-`DO8XLU&3r}0QH*(@uZ_WDy+x%Jh%)|2@69oM60f4zV8RLMy%T(ob<^vP!pj5S z_82_YTU=a(DC3Xxz7xa8dW%cT4JMqB-jBiePORSIiYUB1@O>SF$9hW&DQk>B(wmxR zT=EI)Eh&lOBfXj6`!QB;NqH0>UF3n!`X}?ZFsdYw-r77XmzHm(rEV*g^ezHl=4~Eh~xQBfV?$EKE4%^p;hWS*fJ=cX>h-$LcLFipmeLh^z2Z8^u>! zQ&3(Kh35j_cJQ@pd^TLyxQMST%0A+I9(>k6;v46Wbc8H5oy!aO&eia!+SiDh9R=kT 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 bbJdl5;bhd9%>G5Y`|2XjNhzuxKE(eGpKQ)L literal 0 HcmV?d00001 diff --git a/src/examples/ParallelPandemic/statusEnums.h b/src/examples/ParallelPandemic/statusEnums.h new file mode 100644 index 000000000..4381e5859 --- /dev/null +++ b/src/examples/ParallelPandemic/statusEnums.h @@ -0,0 +1,11 @@ +#ifndef STATUS_ENUM_H_ +#define STATUS_ENUM_H_ + +#include + +/*! \brief Enum for valid Person states for the Pandemic + */ +enum PersonState { + infected = 'v', immune = 'i', susceptible = 's', dead = 'd' +}; +#endif /* STATUS_ENUM_H_ */ \ No newline at end of file diff --git a/src/examples/ParallelPandemic/testPandemic.cpp b/src/examples/ParallelPandemic/testPandemic.cpp new file mode 100644 index 000000000..54616818a --- /dev/null +++ b/src/examples/ParallelPandemic/testPandemic.cpp @@ -0,0 +1,326 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [contagiousFactor] + 1 <= numPersons <= 200, defaults to 50 + 0 <= contagiousFactor <= 100, defaults to 50 + */ + +#include +#include +#include +#include +#include "Person.h" +#include + +// disease constants +#define PERSON_RADIUS 5 // the size of each person on screen +// text constants +#define FONT "./assets/freefont/FreeSansBold.ttf" // font for all text +#define FONT_SIZE 20 // font size for all text +#define TEXT_COLOR ColorFloat(0.2,1,1,1) // color for all text (light blue) + +using namespace tsgl; + +// To parse command line for custom program options +cxxopts::ParseResult parse(int argc, char* argv[]) { + try { + cxxopts::Options options("./src/examples/ParallelPandemic/testPandemic", "- command line options"); + + options.positional_help("[optional args]").show_positional_help(); + + options.allow_unrecognised_options().add_options()("h, help", "Print help")( + "n, num", "the number of people in the model", cxxopts::value()->default_value("100"))( + "i, initial", "the number of initially infected people (1-n)", cxxopts::value()->default_value("1"))( + "R, person-radius", "the radius of each person (1-30)", cxxopts::value()->default_value("5.0"))( + "t, sick-for", "the duration of the disease (in days)", cxxopts::value()->default_value("21"))( + "c, contagiousness" , "the contagiousness factor of the disease (0-100)", cxxopts::value()->default_value("50"))( + "r, infect-radius", "the infection radius of the disease (1-200)", cxxopts::value()->default_value("35"))( + "m, mortality", "the mortality factor of the disease (0-100)", cxxopts::value()->default_value("2"))( + "s, show-radius", "include to display the infection radius around each person", + cxxopts::value()->default_value("false"))( + "a, attendance", "include to print out the thread attendance (to see if all threads are running)", + cxxopts::value()->default_value("false")); + + auto results = options.parse(argc, argv); + + if(results.count("help") || results.count("h")){ + std::cout << options.help({"", "Group"}) << std::endl; + std::cout << "Use the up and down arrow keys to increase or decrease the animation speed, respectively." << std::endl; + exit(0); + } + + return results; + + } catch (const cxxopts::OptionSpecException& e) { + std::cout << "error parsing options: " << e.what() << std::endl; + exit(1); + } +} + +void pandemicFunction(Canvas& can, int argc, char* argv[]) { + // INITIALIZE VARIABLES // + int numPersons = 100; + float personRadius = 5.0; + float infectionRadius = 35; + bool showInfectionRadius; + bool takeAttendance; + // time + int numDays = 0; + int sickDuration = 21; + // counters + int num_initially_infected = 1; + int num_currently_infected; + int num_susceptible; + // pandemic factors + int contagiousFactor = 50; + int mortalityFactor = 2; + // ending stats/counters + int total_num_infections; + int total_num_infection_attempts = 0; + int total_num_deaths = 0; + // int total_num_death_attempts = 0; + int total_num_recoveries = 0; + float true_contagiousness = 0.0; + float true_mortality = 0.0; + float avgInfectionLength; + // Parse command line + auto result = parse(argc, argv); + + // SET OPTIONS // + if (result["num"].as() > 0) { + numPersons = result["num"].as(); + } + if (result["initial"].as() > 0 and result["initial"].as() <= numPersons) { + num_initially_infected = result["initial"].as(); + } + if (result["person-radius"].as() > 0.0 and result["person-radius"].as() <= 30) { + personRadius = result["person-radius"].as(); + } + if (result["sick-for"].as() > 0) { + sickDuration = result["sick-for"].as(); + } + if (result["contagiousness"].as() >= 0 and result["contagiousness"].as() <= 100) { + contagiousFactor = result["contagiousness"].as(); + } + if (result["infect-radius"].as() > 0 and result["infect-radius"].as() <= 200) { + infectionRadius = result["infect-radius"].as(); + } + if (result["mortality"].as() >= 0 and result["mortality"].as() <= 100) { + mortalityFactor = result["mortality"].as(); + } + + // boolean switches + showInfectionRadius = result["show-radius"].as(); + takeAttendance = result["attendance"].as(); + + // counters + num_currently_infected = num_initially_infected; + num_susceptible = numPersons - num_initially_infected; + total_num_infections = num_initially_infected; + total_num_infection_attempts = num_initially_infected; + // movement bounds + float max_x = can.getWindowWidth()/2 - personRadius; + float max_y = can.getWindowHeight()/2 - personRadius - FONT_SIZE; + + // random number generator + std::default_random_engine generator; + std::uniform_int_distribution init_x_distr(-max_x, max_x); + std::uniform_int_distribution init_y_distr(-max_y, max_y); + std::uniform_int_distribution move_distr(-20, 20); + std::uniform_int_distribution sick_distr(1, sickDuration); + std::uniform_int_distribution chance_distr(1, 100); + + // Create arrays + std::vector personVec; + std::vector threadAttendance; + + // Insert infected into array + for(int i = 0; i < num_initially_infected; ++i){ + personVec.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + personRadius, infectionRadius, infected, showInfectionRadius)); + personVec[i]->draw(can); + } + // Insert susceptible into array + for(int i = num_initially_infected; i < numPersons; ++i){ + personVec.push_back(new Person(init_x_distr(generator), init_y_distr(generator), + personRadius, infectionRadius, susceptible, showInfectionRadius)); + personVec[i]->draw(can); + } + + // Set up thread "attendance sheet" + for(int i = 0; i < numPersons; ++i){ + threadAttendance.push_back(-1); + } + + // Create text to display the current day + Text * dayText = new Text(0, 300, 0, L"Day 1", FONT, FONT_SIZE, 0, 0, 0, TEXT_COLOR); + can.add(dayText); + + float sleepTime = 0.5; // initial number of seconds to sleep + + // KEY BINDINGS // -> to speed up/slow down animation + can.bindToButton(TSGL_UP, TSGL_PRESS, [&sleepTime](){ + sleepTime /= 2; + }); + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&sleepTime](){ + if(sleepTime < 1){ + sleepTime *= 2; + } + }); + + // OUTPUT INITIAL INFORMATION // + printf("\n***********************\ + \n* Initial information *\ + \n***********************\ + \n\ + \nInfection radius: %.1f\ + \nChance of infection: %d%%\ + \nChance of death: %d%%\ + \n\ + \nStarting number of people infected: %d\ + \nTotal number of people: %d\ + \n\n", infectionRadius, contagiousFactor, mortalityFactor, + num_initially_infected, numPersons); + + int complete = 0; // ensures simulation only runs once + + // RUN SIMULATION // + while (can.isOpen()) { + if(complete == 0){ + // Runs until there are no more infections + while(num_currently_infected != 0){ + // Increment number of days for pandemic + ++numDays; + // Update day number + dayText->setText(L"Day " + std::to_wstring(numDays)); + + #pragma omp parallel num_threads(numPersons) + { + int id = omp_get_thread_num(); + + // Ensure there is one thread running per person (take attendance for threads) + if(numDays == 1){ + threadAttendance[id] = id; + } + + // No actions apply to people who are dead + if(personVec[id]->getStatus() != dead){ + // Move people + personVec[id]->moveBy(move_distr(generator), move_distr(generator), max_x, max_y); + can.sleepFor(sleepTime); + + // INFECTED + if(personVec[id]->getStatus() == infected){ + // #pragma omp atomic update // to prevent race condition in updating counters between threads + // ++total_num_death_attempts; + // DEATH: check if the person has died + if(personVec[id]->willDie() and + personVec[id]->getNumDaysTillDead() == personVec[id]->getNumDaysInfected()){ + #pragma omp atomic update + --num_currently_infected; + #pragma omp atomic update + ++total_num_deaths; + personVec[id]->die(can); + } + // RECOVERY: check if person has been infected for the duration of the disease + else if( !personVec[id]->willDie() and personVec[id]->getNumDaysInfected() >= sickDuration){ + #pragma omp atomic update + --num_currently_infected; + #pragma omp atomic update + ++total_num_recoveries; + personVec[id]->recover(can); + } + // STILL INFECTED: if not dead or recovered, increase number of days infected by 1 + else{ + personVec[id]->increaseNumDaysInfected(); + } + } + + // SUSCEPTIBLE + if(personVec[id]->getStatus() == susceptible){ + // Check if the person is within an infected radius + if(personVec[id]->checkIfInfectedNearby(personVec)){ + #pragma omp atomic update + ++total_num_infection_attempts; + // Determine if the person has been infected + if(personVec[id]->determineIfInfected(can, contagiousFactor, chance_distr(generator))){ + #pragma omp atomic update + --num_susceptible; + #pragma omp atomic update + ++num_currently_infected; + #pragma omp atomic update + ++total_num_infections; + personVec[id]->determineIsToDie(mortalityFactor, chance_distr(generator), sick_distr(generator)); + } + } + } + } + } // end main parallel block + + } // end simulation while loop + complete = 1; + } + } // end Canvas while loop + + + // CALCULATIONS // + if(total_num_infection_attempts != 0){ // To avoid a divide-by-zero error (in case there were no infection attempts) + true_contagiousness = (total_num_infections/static_cast(total_num_infection_attempts)) * 100.0; + } + if(total_num_infections != 0){ // To avoid a divide-by-zero error (in case there were no infection attempts) + true_mortality = (total_num_deaths/static_cast(total_num_infections)) * 100.0; + } + for(unsigned i = 0; i < personVec.size(); ++i){ + avgInfectionLength += personVec[i]->getNumDaysInfected(); + } + avgInfectionLength /= total_num_infections; + + + // OUTPUT // + printf("\n***********************\ + \n* Statistics and data *\ + \n***********************\ + \n\ + \n*** Herd immunity achieved in %d days ***\ + \nSusceptible: %d\ + \nImmune: %d\ + \nDead: %d\ + \n", numDays, num_susceptible, + total_num_recoveries, total_num_deaths); + printf("\n*** Statistics ***\ + \nTotal number of infections: %d\ + \nTotal number of deaths: %d\ + \nTotal number of recoveries: %d\ + \nTrue contagiousness: %.2f%%\ + \nTrue mortality rate: %.2f%%\ + \n", total_num_infections, total_num_deaths, total_num_recoveries, + true_contagiousness, true_mortality); + + // Print thread attendance + if(takeAttendance){ + printf("\n*** Thread Attendance (-1 if absent) ***"); + for(unsigned i = 0; i < threadAttendance.size(); ++i){ + if(i%10 == 0){ + printf("\n"); + } + printf("%5d", threadAttendance[i]); + } + printf("\n"); + } + + // DEALLOCATION OF OBJECT MEMORY // + for(int i = 0; i < numPersons; ++i){ + delete personVec[i]; + } + delete dayText; + personVec.clear(); + threadAttendance.clear(); + +} + +int main(int argc, char* argv[]){ + Canvas c(0, -1, 620, 620, "Pandemic Simulation"); + c.setBackgroundColor(BLACK); + c.run(pandemicFunction, argc, argv); +} diff --git a/src/examples/ParallelPandemic/testPerson.cpp b/src/examples/ParallelPandemic/testPerson.cpp new file mode 100644 index 000000000..fd8a75b20 --- /dev/null +++ b/src/examples/ParallelPandemic/testPerson.cpp @@ -0,0 +1,33 @@ +/* + * testPandemic.cpp + * + * Usage: ./testPandemic [numPersons] [infectionRate] + 1 <= numPersons <= 100, defaults to 50 + 0 <= infectionRate <= 100, defaults to 20 + */ + +#include +#include +#include "Person.h" + +using namespace tsgl; + +void personFunction(Canvas& can) { + Person * p1 = new Person(0, 0, 50, susceptible); + + p1->draw(can); + + while (can.isOpen()) { + can.sleep(); + } + + // Deallocate all object memory + delete p1; + +} + +int main(int argc, char* argv[]){ + Canvas c(0, -1, 1820, 620, "Pandemic Simulation"); + c.setBackgroundColor(WHITE); + c.run(personFunction); +} diff --git a/src/examples/ProducerConsumer/Consumer.cpp b/src/examples/ProducerConsumer/Consumer.cpp new file mode 100644 index 000000000..548bce74c --- /dev/null +++ b/src/examples/ProducerConsumer/Consumer.cpp @@ -0,0 +1,81 @@ +#include "Consumer.h" + +/** + * Default-constructor for the Consumer class. + * return: The constructed Consumer object. + */ +Consumer::Consumer() : PCThread() { } + +/** + * Explicit-constructor for the Consumer class. + * param: sharedBuffer, a reference to the Queue object that is shared between the Consumer and Producer. + * param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming object from the Queue. + * return: The constructed Consumer object. + */ +Consumer::Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { + myX = can.getWindowWidth() - 50; + myShape = new Rectangle(myX, myY, 40, 40, ColorInt(0, 0, 0), BLACK); + myShape->setCenter(myX, myY); + myShape->setLayer(1); + myCountLabel->setCenter(myX, myY); + myCountLabel->setLayer(2); + myCan->add(myShape); +} + +/** + * locks the Queue for consumption + */ +void Consumer::lock() { + //Show waiting status + myShape->setColor( BLACK, WHITE ); + myCountLabel->setColor(WHITE); + if( myItem ) { + myCan->remove( myItem ); + delete myItem; + myItem = NULL; + } + + buffer->consumerLock(); //Request lock + myShape->setColor( WHITE, BLACK ); + myCountLabel->setColor(BLACK); + while( paused ) {} +} + +/** + * act goes through the process of consuming an item from Queue + */ +void Consumer::act() { + myItem = buffer->remove(); //Take out data from the Queue and consume it + int endX = myShape->getCenterX()-50, endY = myShape->getCenterY(); + animateItem(endX, endY); + while( paused ) {} + ColorFloat* fillColor = myItem->getFillColor(); + myShape->setColor( fillColor, BLACK ); //Change Consumer color to Item color + myCountLabel->setColor(fillColor->getContrast()); + delete[] fillColor; + count++; myCountLabel->setText( std::to_wstring(count) ); + if(count == 10) myCountLabel->setCenter(myX, myY); + if(count == 100) { + myCountLabel->setFontSize(22); + myCountLabel->setCenter(myX, myY); + } +} + +/** + * unlocks the Queue after consuming an item + */ +void Consumer::unlock() { + // myCan->remove(myItem); + // delete myItem; + // myItem = NULL; + buffer->consumerUnlock(); + while( paused ) {} +} + +Consumer::~Consumer() { + if(myItem) { + delete myItem; + myItem = NULL; + } +} diff --git a/src/examples/ProducerConsumer/Consumer.h b/src/examples/ProducerConsumer/Consumer.h new file mode 100644 index 000000000..427bbee76 --- /dev/null +++ b/src/examples/ProducerConsumer/Consumer.h @@ -0,0 +1,28 @@ +/** + * Consumer.h contains the class necessary in order to create a Consumer object for the Producer-Consumer visualization. + */ +#ifndef CONSUMER_H_ +#define CONSUMER_H_ + +#include +#include +#include "Queue.h" +#include "PCThread.h" +using namespace tsgl; + +/** + * Consumer class inherits from the Thread class in order to create a Consumer object. + * Inheritance: Thread class. + * Implements the run() method, which calls the consume() method. + */ +class Consumer : public PCThread { +public: + Consumer(); //Default constructor + ~Consumer(); + Consumer(Queue & sharedBuffer, unsigned long id, Canvas & can); //Explicit constructor + void lock(); + void act(); + void unlock(); +}; + +#endif /* CONSUMER_H_ */ diff --git a/src/examples/ProducerConsumer/Makefile b/src/examples/ProducerConsumer/Makefile new file mode 100644 index 000000000..ad5ca9b52 --- /dev/null +++ b/src/examples/ProducerConsumer/Makefile @@ -0,0 +1,63 @@ +# Makefile for ProducerConsumer + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = Queue.h \ + +# Main source file +TARGET = testProducerConsumer + +# Object files +ODIR = obj +_OBJ = Consumer.o PCThread.o Producer.o Thread.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ProducerConsumer/PCThread.cpp b/src/examples/ProducerConsumer/PCThread.cpp new file mode 100644 index 000000000..da60b3ef0 --- /dev/null +++ b/src/examples/ProducerConsumer/PCThread.cpp @@ -0,0 +1,88 @@ +#include "PCThread.h" + +std::atomic PCThread::paused(false); + +/** + * \brief Default-constructor for the PCThread class. + * \return: The constructed PCThread object. + */ +PCThread::PCThread() : Thread() { + buffer = NULL; + myCan = NULL; + myShape = NULL; + myItem = NULL; + myArrow = NULL; + myCountLabel = NULL; + count = 0; + myX = myY = 0; +} + +/** + * Explicit-constructor for the PCThread class. + * param: sharedBuffer, a reference to the Queue object that is shared between the Producer and Consumer. + * param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming objects from the Queue. + * return: The constructed PCThread object. + */ +PCThread::PCThread(Queue & sharedBuffer, unsigned long id, Canvas & can) : Thread(id) { + count = 0; + buffer = &sharedBuffer; //Get the handle to the Queue + myCan = &can; //Get the handle to the Canvas + myY = 50 * (id + 1); + myX = 0; //Set in subclass constructor + myItem = NULL; + myArrow = NULL; + myCountLabel = new Text( std::to_wstring(count), myX, myY+5, 24, WHITE); + myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); + // myCountLabel->setLayer(3); + myCan->add( myCountLabel ); +} + +//TODO: comment and improve +void PCThread::wait() { + myCan->sleepFor( (rand()%10+3.0)/5.0 ); + while( paused ) {} +} + +void PCThread::run() { + while( myCan->isOpen() ) { + wait(); + lock(); + act(); + unlock(); + } +} + +void PCThread::animateItem(int endX, int endY) { + const int steps = 20; + const float timeInterval = 0.7; + int startX = myItem->getCenterX(), startY = myItem->getCenterY(); + + myArrow = new Arrow (startX, startY, endX, endY, BLACK, false); + myCan->add(myArrow); + + float deltaX = (endX - startX) / float(steps); //Change in x each step + float deltaY = (endY - startY) / float(steps); //Change in y each step + + for(int i = 0; i <= steps; i++) { + myItem->setCenter( round( startX+ i*deltaX ), round(startY+i*deltaY)); + myCan->sleepFor( timeInterval / steps ); + while( paused ) {} + } + myCan->remove(myArrow); + delete myArrow; + myArrow = NULL; +} + +PCThread::~PCThread() { + delete myCountLabel; + delete myShape; + if(myItem) { + delete myItem; + myItem = NULL; + } + if(myArrow) { + delete myArrow; + myArrow = NULL; + } +} diff --git a/src/examples/ProducerConsumer/PCThread.h b/src/examples/ProducerConsumer/PCThread.h new file mode 100644 index 000000000..454cd6471 --- /dev/null +++ b/src/examples/ProducerConsumer/PCThread.h @@ -0,0 +1,42 @@ +/** + * PCThread.h contains the subclass of Thread and superclass of Producer and Consumer for the Producer-Consumer visualization. + * Includes details for drawing Threads to the Canvas + */ +#ifndef PCTHREAD_H_ +#define PCTHREAD_H_ + +#include +#include "Thread.h" +#include "Queue.h" +#include +#include +using namespace tsgl; + +/** + * PChread class inherits from the Thread class in order to create a PCThread object. + * Inheritance: Thread class. + */ +class PCThread : public Thread { +public: + PCThread(); //Default constructor + virtual ~PCThread(); + PCThread(Queue & sharedBuffer, unsigned long id, Canvas & can); //Explicit constructor + virtual void run(); + virtual void wait(); + virtual void lock() = 0; //Must be implemented by subclass + virtual void act() = 0; //Must be implemented by subclass + virtual void unlock() = 0; //Must be implemented by subclass + static std::atomic paused; +protected: + void animateItem(int endX, int endY); + int myX, myY; //Center coordinates for the PCThread + int count; //Number of colors processed (produced or consumed) + Queue * buffer; //Handle to the current buffer + Canvas * myCan; //Handle to the Canvas + ConvexPolygon * myShape; + Arrow * myArrow; + Star * myItem; //Handle to item Produced/Consumed + Text * myCountLabel; //Text label for number Produced/Consumed +}; + +#endif /* PCTHREAD_H_ */ diff --git a/src/examples/ProducerConsumer/Producer.cpp b/src/examples/ProducerConsumer/Producer.cpp new file mode 100644 index 000000000..2813e3213 --- /dev/null +++ b/src/examples/ProducerConsumer/Producer.cpp @@ -0,0 +1,102 @@ +#include "Producer.h" + +/** + * Default-constructor for the Producer class. + * @return: The constructed Producer object. + */ +Producer::Producer() : PCThread() { } + +/** + * Explicit-constructor for the Producer class. + * @param: sharedBuffer, a reference to the Queue object that is shared between the Consumer and Producer. + * @param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * @param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue producing object into the Queue. + * @return: The constructed Producer object. + */ +Producer::Producer(Queue & sharedBuffer, unsigned long id, Canvas & can) : PCThread(sharedBuffer, id, can) { + myX = 50; //Set the x-coordinate to 50 + myShape = new Circle(myX, myY, 20, ColorInt(0, 0, 0), BLACK); + myShape->setLayer(1); + myCountLabel->setBottomLeftCorner(myX - 5, myY + 10); + myCountLabel->setLayer(2); + myCan->add(myShape); +} + +/** + * randColor generates a new random ColorInt + */ +ColorInt Producer::randColor() { + int red = rand() % 255; + int green = rand() % 255; + int blue = rand() % 255; + return ColorInt(red, green, blue); +} + +/** + * nextItem generates a new Star with a random color + */ +Star* Producer::nextItem() { + return new Star(myX+50, myY, 20, 5, randColor() ); +} + +/** + * wait takes some time to find the next color + */ +void Producer::wait() { + myItem = nextItem(); + ColorFloat * fillColor = myItem->getFillColor(); + myShape->setColor( fillColor, BLACK ); + myCountLabel->setColor(fillColor->getContrast()); + delete[] fillColor; + PCThread::wait(); +} + +/** + * locks the Queue for production + */ +void Producer::lock() { + myCan->add( myItem ); + myShape->setColor( BLACK, WHITE ); + myCountLabel->setColor(WHITE); + buffer->producerLock(); + myShape->setColor( WHITE, BLACK ); + myCountLabel->setColor(BLACK); + while( paused ) {} +} + +/** + * act goes through the process of adding a produced item to Queue + */ +void Producer::act() { + while( paused ) {} + myCan->sleep(); + int i = buffer->getLastIndex(); + buffer->append(myItem, getId()); //Append something and pass your id along too + //Show Item added to Queue + float itAngle = (i*2*PI + PI)/8; // angle of item + int endX = 100*cos(itAngle)+300, endY = 100*sin(itAngle)+175; + animateItem(endX, endY); + + count++; myCountLabel->setText( std::to_wstring(count) ); + if(count == 10) myCountLabel->setCenter(myX, myY); + if(count == 100) { + myCountLabel->setFontSize(22); + myCountLabel->setCenter(myX, myY); + } + myItem = NULL; +} + +/** + * unlocks the Queue after production + */ +void Producer::unlock() { + buffer->producerUnlock(); //TODO: change name of method + while( paused ) {} +} + +Producer::~Producer() { + if(myItem) { + delete myItem; + myItem = NULL; + } +} diff --git a/src/examples/ProducerConsumer/Producer.h b/src/examples/ProducerConsumer/Producer.h new file mode 100644 index 000000000..f0e5f909a --- /dev/null +++ b/src/examples/ProducerConsumer/Producer.h @@ -0,0 +1,33 @@ +/** + * Producer.h contains the class necessary in order to create a Producer object for the Producer-Consumer visualization. + */ +#ifndef PRODUCER_H_ +#define PRODUCER_H_ + +#include +#include +#include "Queue.h" +#include "PCThread.h" +using namespace tsgl; + +/** + * Producer class creates a Producer object and inherits from the Thread class. + * Inheritance: Thread class. + * Implements the abstract run() method from the Thread class so that the pthread runs the produce() method. + */ +class Producer : public PCThread { +public: + Producer(); //Default constructor + ~Producer(); + Producer(Queue & sharedBuffer, unsigned long id, Canvas & can); //Size of data to generate and id of pthread + void wait(); + void lock(); + void act(); + void unlock(); + +private: + Star* nextItem(); + ColorInt randColor(); +}; + +#endif /* PRODUCER_H_ */ diff --git a/src/examples/ProducerConsumer/Queue.h b/src/examples/ProducerConsumer/Queue.h new file mode 100644 index 000000000..d027c2cc7 --- /dev/null +++ b/src/examples/ProducerConsumer/Queue.h @@ -0,0 +1,289 @@ +/** + * Queue.h contains the class template code in order to create a custom Queue object. + * Used in the Producer-Consumer visualization in order to visualize a shared buffer amongst pthreads. + * A mutex and condition variables are used to synchronize accesses to the Queue and to avoid race conditions. + * (Condition variable logic was adapted from the TS_Queue code given to me by Professor Joel Adams). + * (Self-synchronization logic was also adapted from TS_Queue). + */ + +#ifndef QUEUE_H_ +#define QUEUE_H_ + +#include +#include +#include +#include +using namespace tsgl; + +template + +/** + * Queue class contains the data necessary in order to create a custom Queue object. + * Used as a shared buffer in the Producer-Consumer visualization. + */ +class Queue { +public: + Queue(); //Default constructor + Queue(int size, Canvas & can); //Explicit Constructor + void append(Item it, int proId); //Push an Item onto the Queue + Item remove(); //Get an Item off of the Queue + //Accessors + Item* getArray(); + int getCount(); + Item getFirst(); + Item getLast(); + int getCapacity(); + int* getPthreadIds(); //Stored Pthread ids + int getLastIndex() { return myLast; } + int getFirstIndex() { return myFirst; } + //Utility methods + bool isEmpty() const; + bool isFull() const; + void producerLock(); + void producerUnlock(); + void consumerLock(); + void consumerUnlock(); + ~Queue(); //Destructor + +private: + Item * myArray; //Array of data + int mySize, myCount, myFirst, myLast; //Size, number of elements, and first and last indice + pthread_mutex_t myMutex; + //Broadcast a signal indicating that the Queue is not full (append, Producers) and that the Queue is not empty (remove, Consumers) + pthread_cond_t notEmpty; //Condition variable for remove + pthread_cond_t notFull; //Condition variable for append + pthread_cond_t notOpen; //Condition variable for determining if the Canvas is open + //Reference to the Canvas + Canvas * myCan; + int * myPthreadIds; //Producer pthread ids (to color the rectangles around the Queue in the visualization) +}; + +/** + * Default constructor for the Queue class. + */ +template +Queue::Queue() { + myArray = NULL; + myPthreadIds = NULL; + mySize = myCount = myFirst = myLast = 0; + pthread_cond_init( ¬Empty, NULL ); //Initialize the condition variables and the mutex + pthread_cond_init( ¬Full, NULL ); + pthread_cond_init( ¬Open, NULL ); + pthread_mutex_init( &myMutex, NULL ); + myCan = NULL; +} + +/** + * Explicit-constructor for the Queue class. + * @param: size, the size of the Queue. + */ +template +Queue::Queue(int size, Canvas & can) { + myArray = new Item[size]; + myPthreadIds = new int[size]; + mySize = size; //Max number of elements to be in the Queue + myCount = 0; //Number of elements currently in the Queue + myFirst = myLast = 0; + pthread_cond_init( ¬Empty, NULL ); //Initialize the condition variables and the mutex + pthread_cond_init( ¬Full, NULL ); + pthread_cond_init( ¬Open, NULL ); + pthread_mutex_init( &myMutex, NULL ); + myCan = &can; +} + +/** + * append() puts an item into the Queue. + * @param: it, an Item to put into the Queue. + * @param: proId, an int representing the pthread id. + * (Pthread condition variable logic adapted from TS_Queue code given to me by Professor Joel Adams). + */ +template +void Queue::append(Item it, int proId) { + myArray[myLast] = it; + myLast = (myLast + 1) % mySize; //Increment the indexer to my last item + myCount++; + myPthreadIds[myLast] = proId; //Store the most recent pthread id + pthread_cond_signal(¬Empty); //Signal that the Queue is not empty. + myPthreadIds[myLast] = proId; //Store the most recent pthread id +} + +/** + * producerLock() locks the Queue for the thread to append an item + */ +template +void Queue::producerLock() { + pthread_mutex_lock( &myMutex ); //Lock the mutex so only one thread can append + while(myCount == mySize) { + pthread_cond_wait(¬Full, &myMutex); //The Queue is full, please wait until it is not full. + } + if(!myCan->isOpen()) { //If the Canvas is not open, wake up all of the sleeping threads + pthread_cond_broadcast( ¬Open ); + pthread_mutex_unlock( &myMutex ); + } //Else... +} + +/** + * producerUnlock() unlocks the Queue after the thread appends an item + */ +template +void Queue::producerUnlock() { + pthread_cond_signal(¬Empty); //Signal that the Queue is not empty. + pthread_mutex_unlock( &myMutex ); //Unlock for other threads +} + +/** + * remove() takes an Item out of the Queue. + * @return: temp, an Item that was taken out of the Queue. + * (Pthread condition variable logic adapted from TS_Queue code given to me by Professor Joel Adams). + */ +template +Item Queue::remove() { + //ColorInt white(255, 255, 255); + Item temp = myArray[myFirst]; // Item to be removed from Queue + //myArray[myFirst] = white; + myFirst = (myFirst + 1) % mySize; + myCount--; + return temp; +} + +/** + * consumerLock() locks the Queue for the thread to remove an item + */ +template +void Queue::consumerLock() { + pthread_mutex_lock( &myMutex ); //Lock the mutex + if(!myCan->isOpen()) { //If the Canvas is not open, wake up all of the sleeping threads + pthread_cond_broadcast( ¬Open ); + pthread_mutex_unlock( &myMutex ); + } else { //Else... + while(myCount == 0) { + pthread_cond_wait(¬Empty, &myMutex); //The Queue is empty, please wait until it is not empty + } + } +} + +/** + * consumerUnlock() locks the Queue after the thread to removes an item + */ +template +void Queue::consumerUnlock() { + pthread_cond_signal(¬Full); //Signal that the Queue is not full + pthread_mutex_unlock( &myMutex ); //Unlock before returning +} + +//Accessors + +/** + * getArray() is the accessor method for the array of the Queue. + * @return: array, the array of items in the Queue. + */ +template +Item* Queue::getArray() { + Item * array; + pthread_mutex_lock( &myMutex ); + array = myArray; + pthread_mutex_unlock( &myMutex ); + return array; +} + +/** + * getCount() is the accessor method for the number of elements currently in the Queue. + * @return: count, an int representing the current number of elements in the Queue. + */ +template +int Queue::getCount() { + int count; + pthread_mutex_lock( &myMutex ); + count = myCount; + pthread_mutex_unlock( &myMutex ); + return count; +} + +/** + * getFirst() is the accessor method for the first element in the Queue. + * @return: first, an Item representing the first element in the Queue. + */ +template +Item Queue::getFirst() { + Item first; + pthread_mutex_lock( &myMutex ); + first = myArray[myFirst]; + pthread_mutex_unlock( &myMutex ); + return first; +} + +/** + * getLast() is the accessor method for the last element in the Queue. + * @return: last, an Iteme representing the last element in the Queue. + */ +template +Item Queue::getLast() { + Item last; + pthread_mutex_lock( &myMutex ); + last = myArray[(myLast-1+mySize) % mySize]; + pthread_mutex_unlock( &myMutex ); + return last; +} + +/** + * getCapacity() is the accessor method for the size of the Queue. + * @return: size, an int representing the size of the Queue. + */ +template +int Queue::getCapacity() { + int size; + pthread_mutex_lock( &myMutex ); + size = mySize; + pthread_mutex_unlock( &myMutex ); + return size; +} + +/** + * getPthreadIds() is the accessor method for the stored pthread ids of the Producers. + * (They are used to determine the color of the Rectangle drawn around the circles in the visualization). + * @return: ids, the array of stored pthread ids. + */ +template +int* Queue::getPthreadIds() { + int * ids; + pthread_mutex_lock( &myMutex ); + ids = myPthreadIds; + pthread_mutex_unlock( &myMutex ); + return ids; +} + +//Utility methods + +/** + * isEmpty() determines if the Queue is empty or not. + * @return: myCount == 0, a boolean expression which evalutes to true or false. + */ +template +bool Queue::isEmpty() const { + return myCount == 0; +} + +/** + * isFull() determines if the Queue is full or not. + * @return: myCount == mySize, a boolean expression which evalutes to true or false. + */ +template +bool Queue::isFull() const { + return myCount == mySize; +} + +/** + * Destructor for the Queue. + */ +template +Queue::~Queue() { + pthread_cond_destroy(¬Empty); //Destroy the condition variables and mutex + pthread_cond_destroy(¬Full); + pthread_cond_destroy(¬Open); + pthread_mutex_destroy(&myMutex); + delete [] myArray; //Deallocate the array + delete [] myPthreadIds; + myArray = NULL; +} + +#endif /*QUEUE_H_*/ diff --git a/src/examples/ProducerConsumer/Thread.cpp b/src/examples/ProducerConsumer/Thread.cpp new file mode 100644 index 000000000..2236127f7 --- /dev/null +++ b/src/examples/ProducerConsumer/Thread.cpp @@ -0,0 +1,53 @@ +#include "Thread.h" + +/** + * Default-constructor for a Thread object. + * @return: The constructed Thread object with id == 0. + */ +Thread::Thread() { + myId = 0; +} + +/** + * Explicit-constructor for a Thread object. + * @param: myId, an unsigned long representing the id for the Thread object. + * @return: The constructed Thread object with id == myId. + */ +Thread::Thread(unsigned long id) { + myId = id; +} + +/** + * threadFunction() is the function that the pthread should run as soon as it is created. + * @param: obj, a void* that will be statically casted into a Thread object. + * It will run the run() function, which will be defined by the inheriting subclass. + ^ @return: NULL. + */ +void* Thread::threadFunction(void* obj) { + Thread * thread = static_cast(obj); + thread->run(); //This NEEDS to be defined by the subclass + pthread_exit(0); //Exit upon completion +} + +/** + * start() function creates the pthread inside of the Thread class. + */ +void Thread::start() { + pthread_create(&myThread, NULL, threadFunction, this); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); +} + +/** + * join() function cancels the pthread inside of the Thread class. + */ +void Thread::join() { + pthread_cancel(myThread); +} + +/** + * getId() is the accessor function for the id of the Thread object. + * @return: myId, an unsigned long representing the id of the Thread object. + */ +unsigned long Thread::getId() const { + return myId; +} diff --git a/src/examples/ProducerConsumer/Thread.h b/src/examples/ProducerConsumer/Thread.h new file mode 100644 index 000000000..7e2f80d83 --- /dev/null +++ b/src/examples/ProducerConsumer/Thread.h @@ -0,0 +1,35 @@ +/** + * Thread.h contains the abstract class necessary in order to have pthreads for Producers and Consumers. + * Adapted from: http://jrdodds.blogs.com/blog/2006/06/encapsulating_a.html + * https://slworkthings.wordpress.com/2009/11/10/a-pthread-wrapper-class-part-1/ + * https://cppcodetips.wordpress.com/2013/12/05/pthread-c-wrapper/ + * http://peter.bourgon.org/blog/2010/10/27/who-needs-boost-a-simple-pthreads-wrapper.html + * Practical Guide To Pthread Programming in C++ By Swaminathan Bhaskar (pdf) + */ +#ifndef THREAD_H_ +#define THREAD_H_ + +#include + +/** + * The Thread class encapsulates the details of creating a pthread. + * It is abstract; cannot be instantiated. + */ +class Thread { +public: + Thread(); //Default-constructor + Thread(unsigned long id); //Constructor + unsigned long getId() const; //Accessor for the id + void start(); //Create the pthread and run the corresponding method + virtual void run() = 0; //Needs to be defined by the inheriting subclass + void join(); //Join at the end + +protected: + static void* threadFunction(void* obj); //The function that the pthread will run + +private: + unsigned long myId; //Id for the Thread object + pthread_t myThread; //pthread +}; + +#endif /* THREAD_H_ */ diff --git a/src/examples/ProducerConsumer/testProducerConsumer.cpp b/src/examples/ProducerConsumer/testProducerConsumer.cpp new file mode 100644 index 000000000..a3e1d1f29 --- /dev/null +++ b/src/examples/ProducerConsumer/testProducerConsumer.cpp @@ -0,0 +1,171 @@ +/** + * main.cpp contains the code that shows the visualization for the Producer-Consumer problem using TSGL and pthreads. + * It utilizes a custom Queue class to make the shared buffer. + * Producer and Consumer classes have been made in order to make the Producers and Consumers + * A Thread class has been made in order to have an encapsulated pthread (which the Producer and Consumer class both inherit from). + * Usage: ./ProducerConsumer + */ + +#include +#include +#include +#include //for try-catch debugging +#include "ProducerConsumer/Producer.h" +#include "ProducerConsumer/Consumer.h" +using namespace tsgl; + + +//Global constants +const int INNERRAD = 75; // radius of the inner circle +const int OUTERRAD = 150; // radius of the outercircle +const int CAPACITY = 8; +const int WINDOW_WIDTH = 600, WINDOW_HEIGHT = 550, MAX_DATA = 8; //Size of Canvas and limit on amount of data to be stored in Queue +Canvas queueDisplay(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Producer-Consumer", WHITE, FRAME ); //Canvas to draw on +Queue sharedBuffer(MAX_DATA, queueDisplay); //Shared buffer (has colored data) + + +/** + * displayLegend helps the main method by controlling the legendDisplay + */ +void displayLegend(Circle *waitingCircle, Rectangle *waitingSquare, Canvas *queueDisplay) { + Star** bufferArray = sharedBuffer.getArray(); + int produceIndex; + int cap = sharedBuffer.getCapacity(); + int oldFirstIndex = 0; + ColorFloat* prodFillColor; + ColorFloat* consFillColor; + while( queueDisplay->isOpen() ) { + if(!sharedBuffer.isEmpty()) { + produceIndex = (sharedBuffer.getLastIndex() + cap - 1) % cap; + prodFillColor = bufferArray[produceIndex]->getFillColor(); + waitingCircle->setColor( prodFillColor[0], BLACK ); + delete[] prodFillColor; + } + if(oldFirstIndex != sharedBuffer.getFirstIndex()) { + consFillColor = bufferArray[oldFirstIndex]->getFillColor(); + waitingSquare->setColor( consFillColor[0], BLACK ); + delete[] consFillColor; + oldFirstIndex = sharedBuffer.getFirstIndex(); + } + } +} + +//Main method +int main(int argc, char * argv[]) { + int numProducers, numConsumers; //Number of producers, consumers + + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./ProducerConsumer [numberOfProducers] [numberOfConsumers]" << std::endl; + } + + //Check the command line + numProducers = (argc > 1) ? atoi(argv[1]) : 5; //Producers defaults to 5 + numConsumers = (argc > 2) ? atoi(argv[2]) : 5; //Consumers defaults to 5 + + //Set to max number of producers && consumers if negative, zero values + if(numProducers <= 0 || numConsumers <= 0) { + std::cout << "Invalid input! Now changing to max default values..." << std::endl; + numProducers = numConsumers = 8; + } else if(numProducers > 8 || numConsumers > 8) { + std::cout << "Too many producers/consumers! Now changing to max default values..." << std::endl; + numProducers = numConsumers = 8; + } + + srand(time(NULL)); // seed the random number generator + + //Fire up the visualization + queueDisplay.start(); + + queueDisplay.bindToButton(TSGL_SPACE, TSGL_PRESS, []() { // toggle pause when spacebar is pressed + PCThread::paused = !PCThread::paused; + }); + + //Prepare the display with background items + int centerY = 175; + int centerX = 300; + for(int i = 0; i < CAPACITY; i++) { + float langle = (i*2*PI)/CAPACITY; // line angle + queueDisplay.drawLine(-INNERRAD*sin(langle)+centerX, INNERRAD*cos(langle)+centerY, -OUTERRAD*sin(langle)+centerX, OUTERRAD*cos(langle)+centerY, BLACK); + } + + queueDisplay.drawRegularPolygon(centerX, centerY, OUTERRAD, CAPACITY, BLACK, false); + queueDisplay.drawRegularPolygon(centerX, centerY, INNERRAD, CAPACITY, BLACK, false); + + //Add notes to bottom of main Canvas + queueDisplay.drawText("*Numbers indicate counts of items produced and consumed", WINDOW_WIDTH-370, WINDOW_HEIGHT-20, 12, BLACK); + // Label Readers and Writers + queueDisplay.drawText("Producers", 30, 20, 24, BLACK); + queueDisplay.drawText("Consumers", WINDOW_WIDTH-150, 20, 24, BLACK); + + int LEGENDOFFSET = 300; + + //Text labels + queueDisplay.drawText("producing",100,70+LEGENDOFFSET,24,BLACK); + queueDisplay.drawText("waiting for lock",100,130+LEGENDOFFSET,24,BLACK); + queueDisplay.drawText("holding lock",100,190+LEGENDOFFSET,24,BLACK); + queueDisplay.drawText("consuming",350,70+LEGENDOFFSET,24,BLACK); + queueDisplay.drawText("waiting for lock",350,130+LEGENDOFFSET,24,BLACK); + queueDisplay.drawText("holding lock",350,190+LEGENDOFFSET,24,BLACK); + + //Create legend items + Circle waitingCircle(50, 60+LEGENDOFFSET, 20, BLACK, BLACK); //waiting for lock + Circle thinkingCircle(50, 120+LEGENDOFFSET, 20, BLACK, true); //waiting, not seeking lock + Circle lockCircle(50, 180+LEGENDOFFSET, 20, BLACK, false); //has lock + Rectangle waitingSquare(WINDOW_WIDTH-70, 40+LEGENDOFFSET, 40, 40, BLACK, BLACK); + Rectangle thinkingSquare(WINDOW_WIDTH-70, 100+LEGENDOFFSET, 40, 40, BLACK, true); + Rectangle lockSquare(WINDOW_WIDTH-70, 160+LEGENDOFFSET, 40, 40, BLACK, false); + queueDisplay.add( &waitingCircle ); queueDisplay.add( &thinkingCircle ); + queueDisplay.add( &lockCircle ); queueDisplay.add( &waitingSquare ); + queueDisplay.add( &thinkingSquare ); queueDisplay.add( &lockSquare ); + + //LEGENDEND + + std::thread legendUpdater (displayLegend, &waitingCircle, &waitingSquare, &queueDisplay); + + Producer** pro = new Producer*[numProducers]; //Array of Producers + Consumer** con = new Consumer*[numConsumers]; //Array of Consumers + + //Fill the arrays of Producers and Consumers with Producer and Consumer objects + for(int i = 0; i < numProducers; i++) { + pro[i] = new Producer(sharedBuffer, i, queueDisplay); + } + + for(int j = 0; j < numConsumers; j++) { + con[j] = new Consumer(sharedBuffer, j, queueDisplay); + } + + //Start up the pthreads for Producers and Consumers + for(int k = 0; k < numProducers; k++) { + pro[k]->start(); + sleep(0.3); + } + for(int l = 0; l < numConsumers; l++) { + con[l]->start(); + sleep(0.3); + } + + queueDisplay.wait(); + + //Now join them + for(int p = 0; p < numProducers; p++) { //Join the pthreads for the Producers + pro[p]->join(); + } + + for(int c = 0; c < numConsumers; c++) { //Join the pthreads for the Consumers + con[c]->join(); + } + + legendUpdater.join(); + + while( !sharedBuffer.isEmpty() ) { + Star * tempPtr = sharedBuffer.remove(); + delete tempPtr; + } + + delete [] pro; + delete [] con; + pro = NULL; + con = NULL; + + return 0; +} From 3675288ac755b4a2a118d0cc07eae9eb5a987f8a Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:58:09 -0400 Subject: [PATCH 072/105] Add updated examples From 377475aea87c6bfcb3db7da89a35c17284125d95 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:01:29 -0400 Subject: [PATCH 073/105] Add updated examples --- src/examples/Makefile | 34 ++++- src/examples/ReaderWriter/FLock.cpp | 55 +++++++ src/examples/ReaderWriter/FLock.h | 37 +++++ src/examples/ReaderWriter/Lock.cpp | 29 ++++ src/examples/ReaderWriter/Lock.h | 39 +++++ src/examples/ReaderWriter/Makefile | 63 ++++++++ src/examples/ReaderWriter/RLock.cpp | 67 +++++++++ src/examples/ReaderWriter/RLock.h | 30 ++++ src/examples/ReaderWriter/RWDatabase.h | 85 +++++++++++ src/examples/ReaderWriter/RWThread.cpp | 65 +++++++++ src/examples/ReaderWriter/RWThread.h | 46 ++++++ src/examples/ReaderWriter/Reader.cpp | 71 +++++++++ src/examples/ReaderWriter/Reader.h | 32 +++++ src/examples/ReaderWriter/Thread.cpp | 53 +++++++ src/examples/ReaderWriter/Thread.h | 37 +++++ src/examples/ReaderWriter/WLock.cpp | 66 +++++++++ src/examples/ReaderWriter/WLock.h | 28 ++++ src/examples/ReaderWriter/Writer.cpp | 118 +++++++++++++++ src/examples/ReaderWriter/Writer.h | 38 +++++ .../ReaderWriter/testReaderWriter.cpp | 136 ++++++++++++++++++ src/examples/SeaUrchin/testSeaUrchin.cpp | 3 +- src/examples/ShakerSort/testShakerSort.cpp | 1 - src/examples/SolarSystem/testSolarSystem.cpp | 3 +- src/examples/ThreadedSolarSystem/Makefile | 63 ++++++++ .../testThreadedSolarSystem.cpp | 103 +++++++++++++ src/examples/Voronoi/Makefile | 63 ++++++++ src/examples/Voronoi/ShadedVoronoi.cpp | 63 ++++++++ src/examples/Voronoi/ShadedVoronoi.h | 46 ++++++ src/examples/Voronoi/Voronoi.cpp | 65 +++++++++ src/examples/Voronoi/Voronoi.h | 56 ++++++++ src/examples/Voronoi/testVoronoi.cpp | 101 +++++++++++++ 31 files changed, 1688 insertions(+), 8 deletions(-) create mode 100644 src/examples/ReaderWriter/FLock.cpp create mode 100644 src/examples/ReaderWriter/FLock.h create mode 100644 src/examples/ReaderWriter/Lock.cpp create mode 100644 src/examples/ReaderWriter/Lock.h create mode 100644 src/examples/ReaderWriter/Makefile create mode 100644 src/examples/ReaderWriter/RLock.cpp create mode 100644 src/examples/ReaderWriter/RLock.h create mode 100644 src/examples/ReaderWriter/RWDatabase.h create mode 100644 src/examples/ReaderWriter/RWThread.cpp create mode 100644 src/examples/ReaderWriter/RWThread.h create mode 100644 src/examples/ReaderWriter/Reader.cpp create mode 100644 src/examples/ReaderWriter/Reader.h create mode 100644 src/examples/ReaderWriter/Thread.cpp create mode 100644 src/examples/ReaderWriter/Thread.h create mode 100644 src/examples/ReaderWriter/WLock.cpp create mode 100644 src/examples/ReaderWriter/WLock.h create mode 100644 src/examples/ReaderWriter/Writer.cpp create mode 100644 src/examples/ReaderWriter/Writer.h create mode 100644 src/examples/ReaderWriter/testReaderWriter.cpp create mode 100644 src/examples/ThreadedSolarSystem/Makefile create mode 100644 src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp create mode 100644 src/examples/Voronoi/Makefile create mode 100644 src/examples/Voronoi/ShadedVoronoi.cpp create mode 100644 src/examples/Voronoi/ShadedVoronoi.h create mode 100644 src/examples/Voronoi/Voronoi.cpp create mode 100644 src/examples/Voronoi/Voronoi.h create mode 100644 src/examples/Voronoi/testVoronoi.cpp diff --git a/src/examples/Makefile b/src/examples/Makefile index d556b3ebd..8378a6f6d 100644 --- a/src/examples/Makefile +++ b/src/examples/Makefile @@ -2,15 +2,43 @@ # ***************************************************** -SUBDIRS_TO_BUILD := $(wildcard */.) # Used to build the examples +# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the examples +SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ + ArrayShakerSort/. \ + Ballroom/. \ + Clock/. \ + CubeRun/. \ + DiningPhilosophers/. \ + DiningPhilosophers3D/. \ + MergeSort/. \ + NewtonPendulum/. \ + Pong/. \ + SeaUrchin/. \ + ShakerSort/. \ + SolarSystem/. \ + ThreadedArrayAddition/. \ + ThreadedArrayBubbleSort/. \ + ThreadedArrayOperations/. \ + ThreadedSolarSystem/. \ +# Conway/. \ +# Fireworks/. \ +# ForestFire/. \ +# Langton/. \ +# Mandelbrot/. \ +# ParallelPandemic/. \ +# ProducerConsumer/. \ +# ReaderWriter/. \ + + SUBDIRS_TO_CLEAN := $(subst /.,..., $(SUBDIRS_TO_BUILD)) # Used to clean the examples + all: $(SUBDIRS_TO_BUILD) $(SUBDIRS_TO_BUILD): @echo "" @tput setaf 3; - @echo "++++++++++++++++ Generating Binaries for$(subst /., , $@)++++++++++++++++" + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" @tput sgr0; @echo "" $(MAKE) -C $@ @@ -20,4 +48,4 @@ $(SUBDIRS_TO_BUILD): clean: $(SUBDIRS_TO_CLEAN) $(SUBDIRS_TO_CLEAN): - cd $(subst ...,/.,$@) && $(MAKE) clean + cd $(subst ...,,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/examples/ReaderWriter/FLock.cpp b/src/examples/ReaderWriter/FLock.cpp new file mode 100644 index 000000000..07fb60f90 --- /dev/null +++ b/src/examples/ReaderWriter/FLock.cpp @@ -0,0 +1,55 @@ +#include "FLock.h" +/** + * FLock.cpp provides the monitor for the Reader-Writer visualization that gives a fair preference. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + */ + +FLock::FLock() : Lock() { + counterLock = PTHREAD_MUTEX_INITIALIZER; + writerLock = PTHREAD_MUTEX_INITIALIZER; +} + +FLock::FLock(RWDatabase* data) : Lock(data) { + counterLock = PTHREAD_MUTEX_INITIALIZER; + writerLock = PTHREAD_MUTEX_INITIALIZER; +} + +/** + * \brief readLock() implements the abstract method in Lock + * \details Grants the calling thread access for reading + */ +void FLock::readLock() { + pthread_mutex_lock( &this->lock ); + pthread_mutex_lock( &this->counterLock ); + if( (++activeReaders) == 1) pthread_mutex_lock( &this->writerLock ); + pthread_mutex_unlock( &this->lock ); + pthread_mutex_unlock( &this->counterLock ); +} + +/** + * \brief readUnlock() implements the abstract method in Lock + * \details Releases the calling thread's read lock + */ +void FLock::readUnlock() { + pthread_mutex_lock( &this->counterLock ); + if ( (--activeReaders) == 0 ) pthread_mutex_unlock( &this->writerLock ); + pthread_mutex_unlock( &this->counterLock ); +} + +/** + * \brief writeLock() implements the abstract method in Lock + * \details Grants the calling thread acces for writing + */ +void FLock::writeLock() { + pthread_mutex_lock( &this->lock ); + pthread_mutex_lock( &this->writerLock ); +} + +/** + * \brief writeUnlock() implements the abstract method in Lock + * \details Releases the calling thread's write lock + */ +void FLock::writeUnlock() { + pthread_mutex_unlock( &this->writerLock ); + pthread_mutex_unlock( &this->lock ); +} diff --git a/src/examples/ReaderWriter/FLock.h b/src/examples/ReaderWriter/FLock.h new file mode 100644 index 000000000..604ebe4b3 --- /dev/null +++ b/src/examples/ReaderWriter/FLock.h @@ -0,0 +1,37 @@ +/** + * FLock.h provides the fair monitor for the Reader-Writer visualization that gives equal preference to the Readers and Writers. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + * implements the "commonly known solution" presented in: https://arxiv.org/pdf/1309.4507.pdf + */ + +#ifndef RWLOCK_H_ +#define RWLOCK_H_ + +#include +#include +#include "Lock.h" +#include "RWDatabase.h" + +/** + * \class FLock + * \brief A lock giving equal priority to Readers and Writers. + * \details Inheritance: Lock class. + * \details Implements the locking and unlocking methods of a monitor. + */ +class FLock : public Lock { +public: + FLock(); //Default constructor + FLock(RWDatabase* data); //Explicit constructor + void readLock(); //Inherited from Lock class + void readUnlock(); //Inherited from Lock class + void writeLock();//Inherited from Lock class + void writeUnlock(); //Inherited from Lock class +private: + + // TODO: name these better + pthread_mutex_t counterLock; + pthread_mutex_t writerLock; + +}; + +#endif /*RWLOCK_H_*/ diff --git a/src/examples/ReaderWriter/Lock.cpp b/src/examples/ReaderWriter/Lock.cpp new file mode 100644 index 000000000..2d9e8d61d --- /dev/null +++ b/src/examples/ReaderWriter/Lock.cpp @@ -0,0 +1,29 @@ +#include "Lock.h" +/** + * Lock.cpp provides a Lock class for the Reader-Writer visualization. + * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. + */ + +/** + * \brief Default constructor for the Lock class + * \return: The constructed Lock object. + */ +Lock::Lock() { + activeWriters = activeReaders = waitingWriters = waitingReaders = 0; + lock = PTHREAD_MUTEX_INITIALIZER; + okToRead = PTHREAD_COND_INITIALIZER; + okToWrite = PTHREAD_COND_INITIALIZER; +} + +/** + * \brief Explicit constructor for the Lock class + * \param data, the database being protected + * \return: The constructed Lock object. + */ +Lock::Lock(RWDatabase* database) { + activeWriters = activeReaders = waitingWriters = waitingReaders = 0; + lock = PTHREAD_MUTEX_INITIALIZER; + okToRead = PTHREAD_COND_INITIALIZER; + okToWrite = PTHREAD_COND_INITIALIZER; + data = database; +} diff --git a/src/examples/ReaderWriter/Lock.h b/src/examples/ReaderWriter/Lock.h new file mode 100644 index 000000000..5f9ccb4f8 --- /dev/null +++ b/src/examples/ReaderWriter/Lock.h @@ -0,0 +1,39 @@ +/** + * Lock.h provides a Lock class for the Reader-Writer visualization. + * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. + */ + +#ifndef LOCK_H_ +#define LOCK_H_ + +#include +#include +#include +#include +#include +#include "RWDatabase.h" +using namespace std; + +/** + * \class Lock + * \brief An abstract database protecting a vector of data + * \details Database has its locks + * \details Locking methods must be implemented in subclass, giving priority to different types of threads. + */ +class Lock { +public: + Lock(); //Default constructor + Lock(RWDatabase* data); //Explicit constructor + virtual void readLock() = 0; //Must be defined by subclass + virtual void readUnlock() = 0; //Must be defined by subclass + virtual void writeLock() = 0; //Must be defined by subclass + virtual void writeUnlock() = 0; //Must be defined by subclass + +protected: + int activeWriters, activeReaders, waitingWriters, waitingReaders; + pthread_mutex_t lock; + pthread_cond_t okToRead, okToWrite; + RWDatabase* data; +}; + +#endif /*LOCK_H_*/ diff --git a/src/examples/ReaderWriter/Makefile b/src/examples/ReaderWriter/Makefile new file mode 100644 index 000000000..559685352 --- /dev/null +++ b/src/examples/ReaderWriter/Makefile @@ -0,0 +1,63 @@ +# Makefile for ReaderWriter + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = RWDatabase.h \ + +# Main source file +TARGET = testReaderWriter + +# Object files +ODIR = obj +_OBJ = FLock.o Lock.o Reader.o RLock.o RWThread.o Thread.o WLock.o Writer.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ReaderWriter/RLock.cpp b/src/examples/ReaderWriter/RLock.cpp new file mode 100644 index 000000000..064b87d6c --- /dev/null +++ b/src/examples/ReaderWriter/RLock.cpp @@ -0,0 +1,67 @@ +#include "RLock.h" +/** + * RLock.cpp provides the monitor for the Reader-Writer visualization that gives preference to the Readers. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + */ + +/** + * \brief readLock() implements the abstract method in Lock + * \details Grants the calling thread access for reading, giving priority to readers + */ +void RLock::readLock() { + pthread_mutex_lock( &this->lock ); + ++this->waitingReaders; + while( data->getItemCount() == 0 ) { //Wait for okToRead while vector is empty + pthread_cond_wait( &this->okToRead, &this->lock ); + } + while( this->activeWriters > 0 ) { //Yield only to active Writers + pthread_cond_wait( &this->okToRead, &this->lock ); + } + --this->waitingReaders; + ++this->activeReaders; + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief readUnlock() implements the abstract method in Lock + * \details Releases the calling thread's read lock + */ +void RLock::readUnlock() { + pthread_mutex_lock( &this->lock ); + --this->activeReaders; + if( this->activeReaders == 0 && this->waitingWriters > 0 ) { //Last out alerts Writers + pthread_cond_signal( &this->okToWrite ); + } + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief writeLock() implements the abstract method in Lock + * \details Grants the calling thread acces for writing, giving priority to Readers + */ +void RLock::writeLock() { + pthread_mutex_lock( &this->lock ); + while( this->activeWriters > 0 || this->activeReaders > 0 || this->waitingReaders > 0) { + //Yield to active Writers and all Readers + ++this->waitingWriters; + pthread_cond_wait( &this->okToWrite, &this->lock ); + --this->waitingWriters; + } + ++this->activeWriters; + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief writeUnlock() implements the abstract method in Lock + * \details Releases the calling thread's write lock + */ +void RLock::writeUnlock() { + pthread_mutex_lock( &this->lock ); + --this->activeWriters; + if( this->waitingReaders > 0 ) { //Alert all Readers data is available + pthread_cond_broadcast( &this->okToRead ); + } else if( this->waitingWriters > 0 ) { //Alert other Writers only if no Readers + pthread_cond_signal( &this->okToWrite ); + } + pthread_mutex_unlock( &this->lock ); +} diff --git a/src/examples/ReaderWriter/RLock.h b/src/examples/ReaderWriter/RLock.h new file mode 100644 index 000000000..973e26416 --- /dev/null +++ b/src/examples/ReaderWriter/RLock.h @@ -0,0 +1,30 @@ +/** + * RLock.h provides the monitor for the Reader-Writer visualization that gives preference to the Readers. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + */ + +#ifndef RLOCK_H_ +#define RLOCK_H_ + +#include +#include +#include "Lock.h" +#include "RWDatabase.h" + +/** + * \class RLock + * \brief A lock giving priority to Readers. + * \details Inheritance: Lock class. + * \details Implements the locking and unlocking methods of a monitor. + */ +class RLock : public Lock { +public: + RLock() : Lock() {}; //Default constructor + RLock(RWDatabase* data) : Lock(data) {}; //Explicit constructor + void readLock(); //Inherited from Lock class + void readUnlock(); //Inherited from Lock class + void writeLock();//Inherited from Lock class + void writeUnlock(); //Inherited from Lock class +}; + +#endif /*RLOCK_H_*/ diff --git a/src/examples/ReaderWriter/RWDatabase.h b/src/examples/ReaderWriter/RWDatabase.h new file mode 100644 index 000000000..ffdd1cf1d --- /dev/null +++ b/src/examples/ReaderWriter/RWDatabase.h @@ -0,0 +1,85 @@ +/** + * RWDatabase.h provides a RWDatabase class for the Reader-Writer visualization. + * This class provides a superclass for the monitors with Reader or Writer preference, which are used by the threads. + */ + +#ifndef RWDATA_H_ +#define RWDATA_H_ + +#include +#include +#include +using namespace std; + +template + +/** + * \class RWDatabase + * \brief An abstract database protecting a vector of data + * \details Database has its locks and a vector + * \details Locking methods must be implemented in subclass, giving priority to different types of threads. + */ +class RWDatabase { +public: + RWDatabase(); //Default constructor + RWDatabase(int max); //Explicit constructor + int getItemCount() { return vec.size(); } //Get number of items in vector + int getMaxCapacity() { return maxCapacity; }//Get maximum items in vector + Item read(unsigned index); //Access item at index + void write(Item it, unsigned index); //Set item at index + +protected: + std::vector vec; + unsigned maxCapacity; +}; + +/** + * \brief Default constructor for the RWDatabase class + * \return: The constructed RWDatabase object. + */ +template +RWDatabase::RWDatabase() { + vec = vector(); +} + +/** + * \brief Explicit constructor for the RWDatabase class + * \param max, an int describing the maximum size of the contained vector + * \return: The constructed RWDatabase object. + */ +template +RWDatabase::RWDatabase(int max) { + vec = vector(); + maxCapacity = max; +} + +/** + * \brief read() returns the Item from the vector at an index + * \param index, an index in the vector to access a piece of data + */ +template +Item RWDatabase::read(unsigned index) { + if( index >= vec.size() ) + throw range_error("Access attempted beyond present items"); + else + return vec[index]; +} + +/** + * \brief write() sets an item at an index + * \param it, an Item to add to the vector + * \param index, the index to add the Item it + */ +template +void RWDatabase::write(Item it, unsigned index) { + if( index >= vec.size() ) { + if( index > maxCapacity ) + throw range_error("Item added beyond max capacity"); + else + vec.push_back(it); + } else { + vec[index] = it; + } +} + +#endif /*RWDATA_H_*/ diff --git a/src/examples/ReaderWriter/RWThread.cpp b/src/examples/ReaderWriter/RWThread.cpp new file mode 100644 index 000000000..e210790ef --- /dev/null +++ b/src/examples/ReaderWriter/RWThread.cpp @@ -0,0 +1,65 @@ +#include "RWThread.h" + +int RWThread::WAIT_RANGE = 40, RWThread::WAIT_MIN = 15; + // used 32 and 160 for 8 threads and it took forever but worked + // 40 and 15 worked very well with the new version of ReaderWriter + // Still need to have these change based on number of threads. + const int RWThread::width = 20; //Width of each object + const int RWThread::dataX = 200, RWThread::dataY = 670; //Bottom left coordinates of the data area + const int RWThread::dataHeight = 600, RWThread::dataWidth = 200; //Dimensions of the data area + int RWThread::threadCount = 0; + float RWThread::access_wait = 1.0; + atomic RWThread::paused(false); + +/** + * \brief Default-constructor for the RWThread class. + * \return: The constructed RWThread object. + */ +RWThread::RWThread() : Thread() { + myX = myY = count = 0; + data = NULL; + monitor = NULL; + myCan = NULL; + myCircle = NULL; + myCountLabel = NULL; +} + +/** + * \brief Explicit-constructor for the RWThread class. + * \param: sharedDatabase, a reference to the RWDatabase object that is shared between the Reader and Writer. + * \param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * \param: can, a handle to the Canvas that will be drawn on and will determine whether or not to continue consuming object from the Queue. + * \return: The constructed RWThread object. + */ +RWThread::RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : Thread(id) { + //Update static variables + threadCount++; + access_wait = 1.0/threadCount; + + count = 0; + data = &sharedDatabase; //Get the handle to the Database + monitor = &lock; //Get the handle to the monitor + myCan = &can; //Get the handle to the Canvas + myY = RWThread::dataY - 50 * (id + 1); + myX = 0; //Set in subclass constructor + myCircle = new Circle(myX, myY, 20, GRAY); //Move based on new x in subclass + myCircle->setLayer(3); + myCan->add(myCircle); + myCountLabel = new Text( to_wstring(count), myX, myY+5, 24, BLACK); + myCountLabel->setFont("../assets/freefont/FreeSans.ttf"); + myCountLabel->setLayer(4); + myCan->add( myCountLabel ); +} + +void RWThread::run() { + while( myCan->isOpen() ) { + lock(); + act(); + unlock(); + wait(); + } +} + +void RWThread::wait() { + myCan->sleepFor( (rand()%RWThread::WAIT_RANGE+RWThread::WAIT_MIN)/10.0 ); //Wait for a random time +} diff --git a/src/examples/ReaderWriter/RWThread.h b/src/examples/ReaderWriter/RWThread.h new file mode 100644 index 000000000..aba8058ff --- /dev/null +++ b/src/examples/ReaderWriter/RWThread.h @@ -0,0 +1,46 @@ +/** + * RWThread.h contains the subclass of Thread and superclass of Reader and Writer for the Reader-Writer visualization. + * Includes details for drawing Threads to the Canvas + */ +#ifndef RWTHREAD_H_ +#define RWTHREAD_H_ + +#include +#include +#include //atomic paused +#include "RWDatabase.h" +#include "Thread.h" +#include "Lock.h" +using namespace tsgl; + +/** + * RWThread class inherits from the Thread class in order to create a RWThread object. + * Inheritance: Thread class. + */ +class RWThread : public Thread { +public: + RWThread(); //Default constructor + RWThread(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor + void run(); + void wait(); + virtual void lock() = 0; //Must be implemented by subclass + virtual void act() = 0; //Must be implemented by subclass + virtual void unlock() = 0; //Must be implemented by subclass + static const int width, dataX, dataY, dataHeight, dataWidth; //constants for display + static int WAIT_MIN, WAIT_RANGE; + static float access_wait; + static atomic paused; +protected: + int myX, myY; //Center coordinates for the RWThread + int count; //Number of colors processed (read or written) + RWDatabase * data; //Handle to the current database + Lock* monitor; //Handle to the current monitor + Canvas * myCan; //Handle to the Canvas + Circle * myCircle; //Circle representing the Thread + Text * myCountLabel; //Text label for number processed + + //Static values + static int threadCount; +}; + +#endif /* RWTHREAD_H_ */ diff --git a/src/examples/ReaderWriter/Reader.cpp b/src/examples/ReaderWriter/Reader.cpp new file mode 100644 index 000000000..8757d9584 --- /dev/null +++ b/src/examples/ReaderWriter/Reader.cpp @@ -0,0 +1,71 @@ +#include "Reader.h" + +/** + * \brief Default-constructor for the Reader class. + * \return: The constructed Reader object. + */ +Reader::Reader() : RWThread() { } + +/** + * \brief Explicit-constructor for the Reader class. + * \param: sharedData, a reference to the RWDatabase object that is shared between the Reader and Writer. + * \param: id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * \param: can, a handle to the Canvas that will be drawn on. + * \return: The constructed Reader object. + */ +Reader::Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { + myX = can.getWindowWidth()-50; + myCircle->setCenter(myX, myY); + myCountLabel->setCenter(myX, myY); +} + +/** + * \brief Draws and removes Arrow from Canvas + * \details Helps the read() method + * \details Includes a half second pause + */ +void Reader::drawArrow(int x, int y) { + Arrow arrow(myCircle->getCenterX()-20, myY, x, y, BLACK, false); + arrow.setLayer(5); + myCan->add(&arrow); + myCan->sleepFor(0.5); + while( paused ) {} + myCan->remove(&arrow); +} + +//TODO: comment +void Reader::lock() { + myCircle->setCenter(myX-75, myY); //Move towards data + myCountLabel->setCenter(myX-75, myY); + monitor->readLock(); //Lock data for reading + myCan->sleepFor(RWThread::access_wait); + while( paused ) {} + myCircle->setCenter(myX-127, myY); //Move inside data + myCountLabel->setCenter(myX-127, myY); +} + +//TODO: comment +void Reader::act() { + //Read + Rectangle * rec = data->read(rand()%data->getItemCount()); //Get the color + ColorFloat* fillColor = rec->getFillColor(); + myCircle->setColor( fillColor[0] ); + myCountLabel->setColor( fillColor[0].getContrast() ); + delete[] fillColor; + + //Draw and erase the arrow + drawArrow(rec->getCenterX(), rec->getCenterY()); +} + +//TODO: comment +void Reader::unlock() { + //Release lock + count++; myCountLabel->setText( to_wstring(count) ); //Finished another read + if( count == 100 ) { + myCountLabel->setFontSize(22); + } + while( paused ) {} + myCircle->setCenter(myX, myY); //Return to home location + myCountLabel->setCenter(myX, myY); + monitor->readUnlock(); //Unlock the data +} diff --git a/src/examples/ReaderWriter/Reader.h b/src/examples/ReaderWriter/Reader.h new file mode 100644 index 000000000..396722879 --- /dev/null +++ b/src/examples/ReaderWriter/Reader.h @@ -0,0 +1,32 @@ +/** + * Reader.h contains the class necessary in order to create a Reader object for the Reader-Writer visualization. + */ +#ifndef READER_H_ +#define READER_H_ + +#include +#include +#include "RWDatabase.h" +#include "RLock.h" +#include "RWThread.h" +#include "Thread.h" +using namespace tsgl; + +/** + * \class Reader + * \brief Reader class inherits from the RWThread class in order to create a Reader object. + * \details Inheritance: RWThread class. + * \details Implements the run() method, which calls the read() method. + */ +class Reader : public RWThread { +public: + Reader(); //Default constructor + Reader(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor + void lock(); + void act(); + void unlock(); +private: + void drawArrow(int x, int y); +}; + +#endif /* READER_H_ */ diff --git a/src/examples/ReaderWriter/Thread.cpp b/src/examples/ReaderWriter/Thread.cpp new file mode 100644 index 000000000..b6de9570a --- /dev/null +++ b/src/examples/ReaderWriter/Thread.cpp @@ -0,0 +1,53 @@ +#include "Thread.h" + +/** + * \brief Default-constructor for a Thread object. + * \return: The constructed Thread object with id == 0. + */ +Thread::Thread() { + myId = 0; +} + +/** + * \brief Explicit-constructor for a Thread object. + * \param myId, an unsigned long representing the id for the Thread object. + * \return: The constructed Thread object with id == myId. + */ +Thread::Thread(unsigned long id) { + myId = id; +} + +/** + * \brief threadFunction() is the function that the pthread should run as soon as it is created. + * \param obj, a void* that will be statically casted into a Thread object. + * It will run the run() function, which will be defined by the inheriting subclass. + * \return: NULL. + */ +void* Thread::threadFunction(void* obj) { + Thread * thread = static_cast(obj); + thread->run(); //This NEEDS to be defined by the subclass + pthread_exit(0); //Exit upon completion +} + +/** + * \brief start() function creates the pthread inside of the Thread class. + */ +void Thread::start() { + pthread_create(&myThread, NULL, threadFunction, this); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); +} + +/** + * \brief join() function cancels the pthread inside of the Thread class. + */ +void Thread::join() { + pthread_cancel(myThread); // solution to hanging process bug +} + +/** + * \brief getId() is the accessor function for the id of the Thread object. + * \return: myId, an unsigned long representing the id of the Thread object. + */ +unsigned long Thread::getId() const { + return myId; +} diff --git a/src/examples/ReaderWriter/Thread.h b/src/examples/ReaderWriter/Thread.h new file mode 100644 index 000000000..fba976088 --- /dev/null +++ b/src/examples/ReaderWriter/Thread.h @@ -0,0 +1,37 @@ +/** + * Thread.h contains the abstract class necessary in order to have pthreads for Readers and Writers. + * Adapted from: http://jrdodds.blogs.com/blog/2006/06/encapsulating_a.html + * https://slworkthings.wordpress.com/2009/11/10/a-pthread-wrapper-class-part-1/ + * https://cppcodetips.wordpress.com/2013/12/05/pthread-c-wrapper/ + * http://peter.bourgon.org/blog/2010/10/27/who-needs-boost-a-simple-pthreads-wrapper.html + * Practical Guide To Pthread Programming in C++ By Swaminathan Bhaskar (pdf) + */ +#ifndef THREAD_H_ +#define THREAD_H_ + +#include +#include + +/** + * \class Thread + * \brief The Thread class encapsulates the details of creating a pthread. + * \details It is abstract; cannot be instantiated. + */ +class Thread { +public: + Thread(); //Default-constructor + Thread(unsigned long id); //Constructor + unsigned long getId() const; //Accessor for the id + void start(); //Create the pthread and run the corresponding method + virtual void run() = 0; //Needs to be defined by the inheriting subclass + void join(); //Join at the end + +protected: + static void* threadFunction(void* obj); //The function that the pthread will run + +private: + unsigned long myId; //Id for the Thread object + pthread_t myThread; //pthread +}; + +#endif /* THREAD_H_ */ diff --git a/src/examples/ReaderWriter/WLock.cpp b/src/examples/ReaderWriter/WLock.cpp new file mode 100644 index 000000000..df03ec7b1 --- /dev/null +++ b/src/examples/ReaderWriter/WLock.cpp @@ -0,0 +1,66 @@ +#include "WLock.h" +/** + * WLock.cpp provides the monitor for the Reader-Writer visualization that gives preference to the Writers. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + */ + +/** + * \brief readLock() implements the abstract method in Lock + * \details Grants the calling thread access for reading, giving priority to writers + */ +void WLock::readLock() { + pthread_mutex_lock( &this->lock ); + ++this->waitingReaders; + while( data->getItemCount() == 0 ) { //Wait for okToRead while vector is empty + pthread_cond_wait( &this->okToRead, &this->lock ); + } + while( this->activeWriters > 0 || this->waitingWriters > 0) { //Yield to all Writers + pthread_cond_wait( &this->okToRead, &this->lock ); + } + --this->waitingReaders; + ++this->activeReaders; + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief readUnlock() implements the abstract method in Lock + * \details Releases the calling thread's read lock + */ +void WLock::readUnlock() { + pthread_mutex_lock( &this->lock ); + --this->activeReaders; + if( this->activeReaders == 0 && this->waitingWriters > 0 ) { + pthread_cond_signal( &this->okToWrite ); //Alert Writer data is available + } + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief writeLock() implements the abstract method in Lock + * \details Grants the calling thread acces for writing, giving priority to writers + */ +void WLock::writeLock() { + pthread_mutex_lock( &this->lock ); + while( this->activeWriters > 0 || this->activeReaders > 0) { //Wait for anyone already in data + ++this->waitingWriters; + pthread_cond_wait( &this->okToWrite, &this->lock ); + --this->waitingWriters; + } + ++this->activeWriters; + pthread_mutex_unlock( &this->lock ); +} + +/** + * \brief writeUnlock() implements the abstract method in Lock + * \details Releases the calling thread's write lock + */ +void WLock::writeUnlock() { + pthread_mutex_lock( &this->lock ); + --this->activeWriters; + if( this->waitingWriters > 0 ) { //Alert waiting Writer + pthread_cond_signal( &this->okToWrite ); + } else if( this->waitingReaders > 0 ) { //Alert waiting Readers only if no waiting Writers + pthread_cond_broadcast( &this->okToRead ); + } + pthread_mutex_unlock( &this->lock ); +} diff --git a/src/examples/ReaderWriter/WLock.h b/src/examples/ReaderWriter/WLock.h new file mode 100644 index 000000000..22d119a5d --- /dev/null +++ b/src/examples/ReaderWriter/WLock.h @@ -0,0 +1,28 @@ +/** + * WLock.h provides the monitor for the Reader-Writer visualization that gives preference to the Writers. + * This class is a subclass of Lock and implements its locking and unlocking virtual methods. + */ + +#ifndef WLOCK_H_ +#define WLOCK_H_ + +#include +#include "Lock.h" + +/** + * \class WLock + * \brief A lock giving priority to Writers in the visualization. + * \details Inheritance: Lock class. + * \details Implements the locking and unlocking methods of a monitor. + */ +class WLock : public Lock { +public: + WLock() : Lock() {}; //Default constructor + WLock(RWDatabase* data) : Lock(data) {}; //Explicit constructor + void readLock(); //Inherited from Lock class + void readUnlock(); //Inherited from Lock class + void writeLock(); //Inherited from Lock class + void writeUnlock(); //Inherited from Lock class +}; + +#endif /*WLOCK_H_*/ diff --git a/src/examples/ReaderWriter/Writer.cpp b/src/examples/ReaderWriter/Writer.cpp new file mode 100644 index 000000000..9c7447725 --- /dev/null +++ b/src/examples/ReaderWriter/Writer.cpp @@ -0,0 +1,118 @@ +#include "Writer.h" +Text * Writer::dataLabel = NULL; + +/** + * \brief Default-constructor for the Writer class. + * \return: The constructed Writer object. + */ +Writer::Writer() : RWThread() { dataLabel = NULL; } + +/** + * \brief Explicit-constructor for the Writer class. + * \param sharedDatabase, a reference to the RWDatabase object that is shared between the Reader and Writer. + * \param id, an unsigned long that will be passed to the Thread() constructor that will act as the id for the Thread object. + * \param can, a handle to the Canvas that will be drawn on. + * \return: The constructed Writer object. + */ +Writer::Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can) : RWThread(sharedDatabase, lock, id, can) { + myX = 50; //Set the x-coordinate to 50 + myCircle->setCenter(myX, myY); + myCountLabel->setCenter(myX, myY); + if( !dataLabel ) { + dataLabel = new Text(L"0/300", RWThread::dataX-40, RWThread::dataY-RWThread::dataHeight-20, 16, BLACK); + dataLabel->setCenter(RWThread::dataX - 20, RWThread::dataY-RWThread::dataHeight-15); + myCan->add( dataLabel ); + dataLabel->setLayer(3); + } +} + +/** + * \brief Draws and removes Arrow from Canvas + * \details Helps the write() method + * \details Includes a half second pause + */ +void Writer::drawArrow(int x, int y) { + Arrow arrow(myCircle->getCenterX()+20, myY, x, y, BLACK); + arrow.setLayer(5); + myCan->add(&arrow); + myCan->sleepFor(0.5); + while( paused ) {} + myCan->remove(&arrow); +} + +/** + * \brief newColor() generates a new random color for writing. + */ +ColorInt Writer::randColor() { + int red = rand() % 255; + int green = rand() % 255; + int blue = rand() % 255; + return ColorInt(red, green, blue); +} + +/** + * \brief randIndex() generates an index number to add a new item + */ +int Writer::randIndex() { + int i = rand()%(data->getMaxCapacity()); //Random index between 0 and the max number of items in data + if( i > data->getItemCount() ) //Max index is next empty index + i = data->getItemCount(); + return i; +} + +/** + * \brief makeRec() creates a new Rectangle representing a random color + */ +Rectangle * Writer::makeRec(int index) { + int x = dataX + index%(200/RWThread::width) * RWThread::width; // start of data + column + int y = dataY - (index/(200/RWThread::width) + 1) * RWThread::width; // start of data + row + + return new Rectangle(x, y, RWThread::width, RWThread::width, randColor()); +} + +//TODO: comment +void Writer::lock() { + myCircle->setCenter(myX+75, myY); //Move in toward data + myCountLabel->setCenter(myX+75, myY); + monitor->writeLock(); //Lock data for writing + myCan->sleepFor(RWThread::access_wait); +} + +//TODO: comment +void Writer::act() { + while( paused ) {} + int id = randIndex(); + myCircle->setCenter(myX+127, myY); //Move inside data + myCountLabel->setCenter(myX+127, myY); + Rectangle * rec; + if( id < data->getItemCount() ) { //Change the color of an item + rec = data->read(id); + rec->setColor(randColor()); + } else { //Create a new item + rec = makeRec(id); //Make random color at random index + data->write(rec, id); // Write the item to the data + rec->setLayer(3); + myCan->add(rec); + dataLabel->setText( to_wstring( data->getItemCount() ) + L"/" + to_wstring( data->getMaxCapacity() ) ); + } + ColorFloat* fillColor = rec->getFillColor(); + myCircle->setColor( fillColor[0] ); + myCountLabel->setColor(fillColor[0].getContrast()); + delete[] fillColor; + + //Draw an arrow down to the item + drawArrow(rec->getCenterX(), rec->getCenterY()); +} + +//TODO: comment +void Writer::unlock() { + //Release lock + count++; myCountLabel->setText( to_wstring(count) ); //Finished another write + if( count == 100 ) { + myCountLabel->setFontSize(22); + } + while( paused ) {} + myCircle->setCenter(myX, myY); //Return to home location + myCountLabel->setCenter(myX, myY); + monitor->writeUnlock(); //Unlock the data for writing +} diff --git a/src/examples/ReaderWriter/Writer.h b/src/examples/ReaderWriter/Writer.h new file mode 100644 index 000000000..33c5871a4 --- /dev/null +++ b/src/examples/ReaderWriter/Writer.h @@ -0,0 +1,38 @@ +/** + * Writer.h contains the class necessary in order to create a Writer object for the Reader-Writer visualization. + */ +#ifndef WRITER_H_ +#define WRITER_H_ + +//#include +#include +#include "RWDatabase.h" +#include "Lock.h" +#include "RWThread.h" +#include "Thread.h" +using namespace tsgl; + +/** + * \class Writer + * \brief A Thread that writes items in the visualization. + * \details Writer class creates a Writer object and inherits from the RWThread class. + * \details Inheritance: RWThread class. + * \details Implements the abstract run() method from the Thread class so that the pthread runs the write() method. + */ +class Writer : public RWThread { +public: + Writer(); //Default constructor + Writer(RWDatabase & sharedDatabase, Lock& lock, unsigned long id, Canvas & can); //Explicit constructor + void lock(); + void act(); + void unlock(); +private: + ColorInt randColor(); + int randIndex(); + TextureHandler loader; + void drawArrow(int x, int y); + Rectangle * makeRec(int index); + static Text * dataLabel; +}; + +#endif /* WRITER_H_ */ diff --git a/src/examples/ReaderWriter/testReaderWriter.cpp b/src/examples/ReaderWriter/testReaderWriter.cpp new file mode 100644 index 000000000..36a66082f --- /dev/null +++ b/src/examples/ReaderWriter/testReaderWriter.cpp @@ -0,0 +1,136 @@ +/** + * testReaderWriter.cpp contains the code to run the Readers-Writers Problem animation using TSGL and POSIX threads. + * The program utilizes Reader and Writer classes as well as a custom monitor class to hold the shared data. + * Usage: ./ReaderWriter + * can be 'w' for writer priority or 'r' for reader priority and defaults to writer priority + * should be 's' for the starved versions, or anything else for the balanced timing + */ + +//#include +#include +#include +#include "ReaderWriter/Reader.h" +#include "ReaderWriter/Writer.h" +#include "ReaderWriter/RWDatabase.h" +#include "ReaderWriter/Lock.h" +#include "ReaderWriter/RLock.h" +#include "ReaderWriter/WLock.h" +#include "ReaderWriter/FLock.h" +using namespace tsgl; + +//Constants +const int WINDOW_WIDTH = 600, WINDOW_HEIGHT = 800, MARGIN = 45; //Size of Canvas and margin around data + +int main(int argc, char* argv[]) { + + if( argc == 1) { + std::cout << "\nTo run the program with different values, use the format:\n\t./ReaderWriter " + << "\nwhere is w or r for reader or writer priority lock and \n\t is s for starving lower priority threads or b for the more balanced version." << std::endl; + } + + //Number of readers is the first argument or defaults to 6 + int numReaders = ( (argc > 1) && (atoi(argv[1]) > 0) && (atoi(argv[1]) <= 9) ) ? atoi(argv[1]) : 6; + //Number of writers is the second argument or defaults to 6 + int numWriters = ( (argc > 2) && (atoi(argv[2]) > 0) && (atoi(argv[2]) <= 9) ) ? atoi(argv[2]) : 6; + + //Start Reader-Writer visualization + Canvas can(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Reader-Writer", WHITE, 1.0f/2); //Canvas to draw on + + //Start the visualization + can.start(); + + //Create monitor + Lock * lock; + wstring lockString; //String description of lock style + int maxItems = floor(RWThread::dataWidth / RWThread::width) * floor(RWThread::dataHeight / RWThread::width); + RWDatabase* database = new RWDatabase(maxItems); + if( argc > 3 && *argv[3] == 'r' ) { + //Reader preference + lock = new RLock(database); + lockString = L"Reader priority"; + } else if (argc > 3 && *argv[3] == 'w' ) { + //Writer preference + lock = new WLock(database); + lockString = L"Writer priority"; + } else { + lock = new FLock(database); + lockString = L"Fair priority"; + } + + Reader ** readers = new Reader*[numReaders]; //Array of Readers + Writer ** writers = new Writer*[numWriters]; //Array of Writers + + //Create labels + can.drawRectangle(RWThread::dataX-MARGIN, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth+2*MARGIN, RWThread::dataHeight, GRAY); + can.drawRectangle(RWThread::dataX, RWThread::dataY-RWThread::dataHeight, RWThread::dataWidth, RWThread::dataHeight, DARKGRAY); // draw data area + can.drawLine(RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX+RWThread::dataWidth+MARGIN*2.5, RWThread::dataY, BLACK); + can.drawLine(RWThread::dataX-MARGIN*2.5, RWThread::dataY-RWThread::dataHeight, RWThread::dataX-MARGIN*2.5, RWThread::dataY, BLACK); + can.drawText(lockString, 100, RWThread::dataY + 40, 20, BLACK); + can.drawText(L"Numbers indicate", WINDOW_WIDTH-200, RWThread::dataY + 40, 20, BLACK); + can.drawText(L"counts of reads/writes", WINDOW_WIDTH-200, RWThread::dataY + 60, 20, BLACK); + can.drawText(L"Writers", 72, 60, 24, BLACK); + can.drawText(L"Readers", WINDOW_WIDTH-140, 60, 24, BLACK); + can.drawText(L"Shared Data Store", 226, 692, 20, BLACK); + + //Create and rotate more labels + can.drawText(L"Thinking", 484, 127, 28, GRAY, "", PI/2); + can.drawText(L"Waiting", 423, 127, 28, GRAY, "", PI/2); + can.drawText(L"Thinking", 14, 127, 28, GRAY, "", -PI/2); + can.drawText(L"Waiting", 88, 127, 28, GRAY, "", -PI/2); + + //Fill the Reader and Writer arrays with their objects + for(int i = 0; i < numReaders; i++) { + readers[i] = new Reader(*database, *lock, i, can); //Reader created + } + for(int i = 0; i < numWriters; i++) { + writers[i] = new Writer(*database, *lock, i, can); //Writer created + } + + //Check if using starved version + //Starves Readers if there are at least 3 Writers + //Nearly starves Writers with 3 or more Readers + if( argc > 4 && *argv[4] == 's' ) { //Set for starved possibility + if( *argv[3] == 'r' ) { //Readers mostly starve Writers + RWThread::WAIT_MIN = 0; + RWThread::WAIT_RANGE = 20; + RWThread::access_wait *= 20.0; + } else { //Writers starve Readers + RWThread::WAIT_MIN = 2; + RWThread::WAIT_RANGE = 10; + } + } //else change nothing + + srand(time(NULL)); //Seed random number generator for colors and wait times + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, []() { // toggle pause when spacebar is pressed + RWThread::paused = !RWThread::paused; + }); + + //Start the Reader and Writer pthreads + for(int i = 0; i < numWriters; i++) { + writers[i]->start(); + sleep(0.1); + } + for(int i = 0; i < numReaders; i++) { + readers[i]->start(); + sleep(0.1); + } + + can.wait(); //Wait for the main Canvas to be closed + + //End threads + for(int i = 0; i < numReaders; i++) { + readers[i]->join(); + } + for(int i = 0; i < numWriters; i++) { + writers[i]->join(); + } + + //Cleanup + delete [] readers; + delete [] writers; + readers = NULL; + writers = NULL; + + return 0; +} diff --git a/src/examples/SeaUrchin/testSeaUrchin.cpp b/src/examples/SeaUrchin/testSeaUrchin.cpp index 22d4257d7..b6482af34 100644 --- a/src/examples/SeaUrchin/testSeaUrchin.cpp +++ b/src/examples/SeaUrchin/testSeaUrchin.cpp @@ -58,8 +58,7 @@ void seaUrchinFunction(Canvas& can, int threads) { int main(int argc, char * argv[]) { int nthreads = (argc > 1) ? atoi(argv[1]) : 16; //Number of threads clamp(nthreads,1,16); //Max number of threads is 16 - Canvas c(-1, -1, 885, 230, "Sea Urchins!", FRAME * 2); - c.setBackgroundColor(BLACK); + Canvas c(-1, -1, 885, 230, "Sea Urchins!", BLACK, FRAME * 2); c.run(seaUrchinFunction, nthreads); } diff --git a/src/examples/ShakerSort/testShakerSort.cpp b/src/examples/ShakerSort/testShakerSort.cpp index bef6a0f43..a1ca28d03 100644 --- a/src/examples/ShakerSort/testShakerSort.cpp +++ b/src/examples/ShakerSort/testShakerSort.cpp @@ -52,7 +52,6 @@ void shakerSortFunction(Canvas& can) { numbers[i] = rectangles[i]->getHeight(); can.add(rectangles[i]); } - can.setBackgroundColor(GRAY); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class if (min >= max) { // We are done sorting. diff --git a/src/examples/SolarSystem/testSolarSystem.cpp b/src/examples/SolarSystem/testSolarSystem.cpp index c35dc459f..eb9a4fd4d 100644 --- a/src/examples/SolarSystem/testSolarSystem.cpp +++ b/src/examples/SolarSystem/testSolarSystem.cpp @@ -70,7 +70,6 @@ void ssFunction(Canvas& can) { } int main(int argc, char* argv[]) { - Canvas c(0, -1, 1800, 620, "Solar System"); - c.setBackgroundColor(BLACK); + Canvas c(0, -1, 1800, 620, "Solar System", BLACK); c.run(ssFunction); } \ No newline at end of file diff --git a/src/examples/ThreadedSolarSystem/Makefile b/src/examples/ThreadedSolarSystem/Makefile new file mode 100644 index 000000000..b9fd3ea18 --- /dev/null +++ b/src/examples/ThreadedSolarSystem/Makefile @@ -0,0 +1,63 @@ +# Makefile for ThreadedSolarSystem + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testThreadedSolarSystem + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp b/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp new file mode 100644 index 000000000..1cdc1f967 --- /dev/null +++ b/src/examples/ThreadedSolarSystem/testThreadedSolarSystem.cpp @@ -0,0 +1,103 @@ +/* + * testThreadedSolarSystem.cpp + * + * Usage: ./testThreadedSolarSystem + */ + +#include +#include +#include + +using namespace tsgl; + +class ThreadData{ +private: + unsigned myThreadID; + Drawable * myPlanet; // the Drawable object the thread is responsible for + float myPitchDelta; + +public: + ThreadData(unsigned tid, Drawable * object, float pitch){ + myThreadID = tid; + myPlanet = object; + myPitchDelta = pitch; + } + + void changePitch(){ + myPlanet->changePitchBy(myPitchDelta); + } +}; + + +void ssFunction(Canvas& can) { + Sphere * sun = new Sphere(0, 0, 0, 75, 15, 0.0, 15.0, YELLOW); + Sphere * mercury = new Sphere(95, 0, 0, 15, 15, 0.0, 15.0, ColorFloat(.8,.55,0,1)); + Sphere * venus = new Sphere(140, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(1,.8,.5,1)); + Sphere * earth = new Sphere(205, 0, 0, 30, 15, 0.0, 15.0, ColorFloat(0,0.8,0.3,1)); + Sphere * mars = new Sphere(270, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(1,.4,0,1)); + Sphere * jupiter = new Sphere(345, 0, 0, 50, 15, 0.0, 15.0, ColorFloat(1,0.9,.6,1)); + Sphere * saturn = new Sphere(445, 0, 0, 40, 15, 0.0, 15.0, ColorFloat(.9,.65,.25,1)); + Circle * saturnRings = new Circle(445, 0, 0, 70, 15, 0, 75, ColorFloat(.9,.8,.3,0.5)); + Sphere * uranus = new Sphere(515, 0, 0, 25, 15, 0.0, 15.0, ColorFloat(.2,.6,1,1)); + Sphere * neptune = new Sphere(575, 0, 0, 20, 15, 0.0, 15.0, ColorFloat(.25,.65,1,1)); + + // saturnRings->displayOutlineEdges(false); + + mercury->setRotationPoint(0,0,0); + venus->setRotationPoint(0,0,0); + earth->setRotationPoint(0,0,0); + mars->setRotationPoint(0,0,0); + jupiter->setRotationPoint(0,0,0); + saturn->setRotationPoint(0,0,0); + saturnRings->setRotationPoint(0,0,0); + uranus->setRotationPoint(0,0,0); + neptune->setRotationPoint(0,0,0); + + // Items in planetArray have the same index as their corresponding rotation speeds in rotationArray + Drawable * planetArray[] = {mercury, venus, earth, mars, jupiter, saturn, saturnRings, uranus, neptune}; + float rotationArray[] = {4.0, 3.0/2.0, 1.0, 1.0/2.0, 1.0/12.0, 1.0/30.0, 1.0/30.0, 1.0/90.0, 1.0/180.0}; + + can.add(sun); + can.add(mercury); + can.add(venus); + can.add(earth); + can.add(mars); + can.add(jupiter); + can.add(saturn); + can.add(saturnRings); + can.add(uranus); + can.add(neptune); + + while (can.isOpen()) { + can.sleep(); + #pragma omp parallel + { + unsigned tid = omp_get_thread_num(); + unsigned numThreads = omp_get_num_threads(); + + for(unsigned i = tid; i < 9; i += numThreads){ + ThreadData * td = new ThreadData(tid, planetArray[i], rotationArray[i]); + // printf("Thread %d out of %d running planet %d\n", + // tid, numThreads - 1, i); + td->changePitch(); + } + } + } + + delete sun; + delete mercury; + delete venus; + delete earth; + delete mars; + delete jupiter; + delete saturn; + delete saturnRings; + delete uranus; + delete neptune; +} + +int main(int argc, char* argv[]) { + Canvas c(0, -1, 1800, 620, "Solar System"); + c.setBackgroundColor(BLACK); + c.run(ssFunction); +} \ No newline at end of file diff --git a/src/examples/Voronoi/Makefile b/src/examples/Voronoi/Makefile new file mode 100644 index 000000000..50361c397 --- /dev/null +++ b/src/examples/Voronoi/Makefile @@ -0,0 +1,63 @@ +# Makefile for Voronoi + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testVoronoi + +# Object files +ODIR = obj +_OBJ = ShadedVoronoi.o Voronoi.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/examples/Voronoi/ShadedVoronoi.cpp b/src/examples/Voronoi/ShadedVoronoi.cpp new file mode 100644 index 000000000..167f36de6 --- /dev/null +++ b/src/examples/Voronoi/ShadedVoronoi.cpp @@ -0,0 +1,63 @@ +/* + * ShadedVoronoi.cpp + */ + +#include "ShadedVoronoi.h" + +using namespace tsgl; + +ShadedVoronoi::ShadedVoronoi(Canvas& can) : Voronoi(can) { + const int WW = can.getWindowWidth(), // Set the screen sizes + WH = can.getWindowHeight(); // Create a mapping of control point values + myKValue2 = new int[WW * WH](); // Create a mapping of more control point values +} + +void ShadedVoronoi::draw(Canvas& can) { + const int WW = can.getWindowWidth(), // Set the screen sizes + WH = can.getWindowHeight(); + #pragma omp parallel for + for (int i = 0; i < WW; i++) { // For each individual point... + for (int j = 0; j < WH; j++) { + int myBestK = -1, myNextBestK = -1; + float myBDist = 9999, myNBDist = 9999; // Reset the best distance + for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point + float myXD = i - myX[k], myYD = j - myY[k]; + float myDist = sqrt(myXD * myXD + myYD * myYD); // Calculate the distance from each control point + if (myDist < myBDist) { // If it's the closest one + myNBDist = myBDist; // Update the next best distance and control point + myNextBestK = myBestK; + myBDist = myDist; // Update the best distance and control point + myBestK = k; + } else if (myDist < myNBDist) { // If it's the second closest one + myNBDist = myDist; // Just update the next best distance / CP + myNextBestK = k; + } + } + myKValue[i * WH + j] = myBestK; + myKValue2[i * WH + j] = myNextBestK; + can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color + } + } + #pragma omp parallel for + for (int i = 0; i < WW; i++) { // For each individual point... + for (int j = 0; j < WH; j++) { + int k = myKValue[i * WH + j]; // Find its closest control point + int nk = myKValue2[i * WH + j]; // Then find its second closest + float xd1 = i - myX[k]; + float yd1 = j - myY[k]; + float d1 = xd1 * xd1 + yd1 * yd1; // Find the distance to it closest + float xkd = myX[k] - myX[nk]; + float ykd = myY[k] - myY[nk]; + float kd = xkd * xkd + ykd * ykd; // Find the distance between the CPs themselves + float shading = sqrt(d1 / kd); + clamp(shading,0,1); + can.drawPoint(i, j, ColorFloat(0, 0, 0, shading)); // Draw the point with the closest control's color + } + } +} + +ShadedVoronoi::~ShadedVoronoi() { + delete [] myKValue2; + myKValue2 = NULL; +} + diff --git a/src/examples/Voronoi/ShadedVoronoi.h b/src/examples/Voronoi/ShadedVoronoi.h new file mode 100644 index 000000000..2faf6bf1c --- /dev/null +++ b/src/examples/Voronoi/ShadedVoronoi.h @@ -0,0 +1,46 @@ +/* + * ShadedVoronoi.h + */ + +#ifndef SHADEDVORONOI_H_ +#define SHADEDVORONOI_H_ + +#include "Voronoi.h" + +/*! + * \class ShadedVoronoi + * \brief Voronoi diagram, only shaded! + * \details Creates a Shaded Voronoi diagram. + * \details Similar to a Voronoi diagram, but with some parts shaded in. + * \details Subclass of the Voronoi class. + * \see Voronoi class. + */ +class ShadedVoronoi : public Voronoi { +private: + int * myKValue2; +public: + + /*! + * \brief Explicitly construct a ShadedVoronoi object. + * \details Explicit constructor for a ShadedVoronoi object. + * \param can Reference to the Canvas to draw to. + * \return The constructed ShadedVoronoi object. + */ + ShadedVoronoi(Canvas& can); + + /*! + * \brief Draw the ShadedVoronoi object. + * \details Actually draws the ShadedVoronoi object onto the Canvas. + * \param can Reference to the Canvas to draw to. + */ + void draw(Canvas& can); + + /*! + * \brief Destroy a ShadedVoronoi object. + * \details Destructor for a ShadedVoronoi object. + * \return The memory allocated to a ShadedVoronoi object. + */ + virtual ~ShadedVoronoi(); +}; + +#endif /* SHADEDVORONOI_H_ */ diff --git a/src/examples/Voronoi/Voronoi.cpp b/src/examples/Voronoi/Voronoi.cpp new file mode 100644 index 000000000..c1f6c6bc5 --- /dev/null +++ b/src/examples/Voronoi/Voronoi.cpp @@ -0,0 +1,65 @@ +/* + * Voronoi.cpp + */ + +#include "Voronoi.h" + +using namespace tsgl; + +Voronoi::Voronoi(Canvas& can) { + const int WW = can.getWindowWidth(), // Set the screen sizes + WH = can.getWindowHeight(); + srand(time(NULL)); + myX = new int[MY_POINTS](); + myY = new int[MY_POINTS](); + myKValue = new int[WW * WH](); + for (int i = 0; i < MY_POINTS; i++) { // Randomize the control points + myX[i] = rand() % WW; + myY[i] = rand() % WH; + } + srand(time(NULL)); + myTC = Colors::randomColor(1.0f); // Randomize the axis colors + myRC = Colors::randomColor(1.0f); + myLC = Colors::randomColor(1.0f); + myBC = Colors::randomColor(1.0f); + for (int j = 0; j < MY_POINTS; j++) { // For each control point... + float xx = (float) myX[j] / WW; // Calculate an value from 0:1 based on x coord + float yy = (float) myY[j] / WH; // Do the same for y + myXC = Colors::blend(myLC, myRC, xx); // Interpolate between the left and right colors + myYC = Colors::blend(myTC, myBC, yy); // Do the same for top and bottom + myColor[j] = Colors::blend(myXC, myYC, 0.5f); // Complete the 4-way interpolation + } + +} + +void Voronoi::draw(Canvas& can) { + int myBestK = 0; // Keep track of the current best k-value + float myBDist, myDist, myXD, myYD; // Keep track of the closes matches and current distances + #pragma omp parallel for private(myBDist, myXD, myYD, myDist, myBestK) + for (int i = 0; i < can.getWindowWidth(); i++) { // For each individual point... + myBestK = 0; + for (int j = 0; j < can.getWindowHeight(); j++) { + myBDist = 9999; // Reset the best distance + for (int k = 0; k < MY_POINTS; k++) { // Find the closest control point + myXD = i - myX[k]; // Calculate the distance from each control point + myYD = j - myY[k]; + myDist = sqrt(myXD * myXD + myYD * myYD); + if (myDist < myBDist) { // If it's the closest one + myBDist = myDist; // Update the best distance and control point + myBestK = k; + } + } + myKValue[i * can.getWindowHeight() + j] = myBestK; + can.drawPoint(i, j, myColor[myBestK]); // Draw the point with the closest control's color + if (!can.isOpen()) break; + } + } +} + +Voronoi::~Voronoi() { + delete [] myX; + delete [] myY; + delete [] myKValue; + myX = myY = myKValue = NULL; +} + diff --git a/src/examples/Voronoi/Voronoi.h b/src/examples/Voronoi/Voronoi.h new file mode 100644 index 000000000..632aa9f11 --- /dev/null +++ b/src/examples/Voronoi/Voronoi.h @@ -0,0 +1,56 @@ +/* + * Voronoi.h + */ + +#ifndef VORONOI_H_ +#define VORONOI_H_ + +#include +#include +#include +#include +#include +#include "Util.h" + +using namespace tsgl; + +/*! + * \class Voronoi + * \brief A Voronoi diagram. + * \details Creates a Voronoi diagram to be drawn onto a Canvas. + * \see http://en.wikipedia.org/wiki/Voronoi_diagram. + */ +class Voronoi { +protected: + static const int MY_POINTS = 100 * 4; + int * myX; + int * myY; + int * myKValue; + ColorFloat myColor[MY_POINTS]; // And for an array of colors + ColorFloat myTC, myRC, myLC, myBC, myXC, myYC; // Color for the top, right, left, bottom, x-average, and y-average +public: + + /*! + * \brief Explicitly construct a Voronoi object. + * \details Explicit constructor for a Voronoi object. + * \param can Reference to the Canvas to draw to. + * \return The constructed Voronoi object. + */ + Voronoi(Canvas& can); + + /*! + * \brief Draw the Voronoi object. + * \details Actually draws the Voronoi object onto the Canvas. + * \param can Reference to the Canvas to draw to. + */ + void draw(Canvas& can); + + /*! + * \brief Destroy a Voronoi object. + * \details Destructor for a Voronoi object. + * \return The memory allocated to a Voronoi object. + */ + virtual ~Voronoi(); +}; + +#endif /* VORONOI_H_ */ diff --git a/src/examples/Voronoi/testVoronoi.cpp b/src/examples/Voronoi/testVoronoi.cpp new file mode 100644 index 000000000..d0a05d6e9 --- /dev/null +++ b/src/examples/Voronoi/testVoronoi.cpp @@ -0,0 +1,101 @@ +/* + * testVoronoi.cpp + * + * Usage: ./testVoronoi + */ + +/* testVoronoi.cpp contains multiple functions that display a Voronoi diagram in similar fashions. */ + +#include "Voronoi/Voronoi.h" +#include "Voronoi/ShadedVoronoi.h" + +using namespace tsgl; + +/*! + * \brief Draws a randomly generated Voronoi diagram, using OMP and private variables + * ( see http://en.wikipedia.org/wiki/Voronoi_diagram ). + * \details + * - The data and methods for drawing are stored in a class. + * - When you create an instance of the class: + * - The Canvas's dimensions are stored in local constants. + * - The number of control points are predetermined and stored a protected class instance variable. + * - We seed the random number generator with the time. + * - We allocate arrays for x and y coordinates for each of the points. + * - We allocate an array of k-values for each pixel on the Canvas. + * - For each control point: + * - Fill the x-coordinate and y-coordinate arrays with random values (thereby randomizing the locations + * of the control points). + * . + * - Seed the random number generator again with the time. + * - We initialize variables for the top, right, left, and bottom corner colors. + * - For each control point: + * - We get its x coordinate and y coordinate. + * - We determine its x-color based on a linear interpolation on the x-axis. + * - We determine its y-color based on a linear interpolation on the y-axis. + * - We determine its color based on an even mixture of its x-color and y-color. + * . + * . + * - When you draw: + * - The best k-value is initially set to 0. + * - We initialize variables keeping track of the best and current distances. + * - We start a parallel OMP block, allowing the system to determine the best means of parallelization. + * - For each column, we set the best k to 0. Then: + * - For each row: + * - Reset the best distance to a large value. + * - For each control point: + * - We calculate the distance from row,col to the control point. + * - If this distance is less than the best distance, we update the best distance and best-k + * (best point). + * - We set the k-value for row,col to the best-k. + * - We draw a pixel at row,col with the best-k's point color. + * - If we closed the Canvas, break. + * . + * . + * . + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void voronoiFunction(Canvas& can) { + Voronoi v1(can); //Make the Voronoi object + v1.draw(can); //Draw it on the Canvas +} + +/*! + * \brief Draws a randomly generated Voronoi diagram with fancy shading. + * \details Same principle as voronoiFunction(). Also has a class. + * - Key differences: + * - We keep track of the second best distance to each point in \b nbdist. + * - We keep track of the kvalues of each 2nd best point in the array \b kvalue2. + * - In a second post-processing loop through the screen: + * - Find the closest and 2nd closest control points to each pixel. + * - Find the distance from the pixel to the closest control point and store it in: \b d1. + * - Find the distance from the closest to the 2nd closest control point and store it in: \b kd. + * - Set \b shading to ( \b d1 / \b kd ). + * - Bind \b shading between 0 and 1, and shade the pixel with \b shading. + * - Break if the Canvas is closed. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void shadedVoronoiFunction(Canvas& can) { + ShadedVoronoi s1(can); + s1.draw(can); +} + +//Takes command line arguments for the width and height of the window +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + //Normal Voronoi + std::cout << "Regular Voronoi" << std::endl; + Canvas c1(-1, -1, w, h, "Voronoi"); + c1.run(voronoiFunction); + + //Shaded Voronoi + std::cout << "Special Voronoi" << std::endl; + Canvas c2(-1, -1, w, h, "Shaded Voronoi"); + c2.run(shadedVoronoiFunction); +} From f35ffd873430222950be1321507d6595046b41f0 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:03:07 -0400 Subject: [PATCH 074/105] Create readme.md --- src/tests/readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/tests/readme.md diff --git a/src/tests/readme.md b/src/tests/readme.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/tests/readme.md @@ -0,0 +1 @@ + From a3689d15bd1013e54d1c54e13370d42462f28150 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:05:18 -0400 Subject: [PATCH 075/105] Add updated tests --- src/tests/test2Dvs3D/Makefile | 63 ++++ src/tests/test2Dvs3D/test2Dvs3D.cpp | 96 ++++++ src/tests/test3DRotation/Makefile | 63 ++++ src/tests/test3DRotation/test3DRotation.cpp | 48 +++ src/tests/testAlphaRectangle/Makefile | 63 ++++ .../testAlphaRectangle/testAlphaRectangle.cpp | 49 +++ src/tests/testArrows/Makefile | 63 ++++ src/tests/testArrows/testArrows.cpp | 51 +++ src/tests/testAura/Makefile | 63 ++++ src/tests/testAura/testAura.cpp | 111 +++++++ src/tests/testBackground/Makefile | 63 ++++ src/tests/testBackground/testBackground.cpp | 70 ++++ src/tests/testBlurImage/Makefile | 63 ++++ src/tests/testBlurImage/testBlurImage.cpp | 62 ++++ src/tests/testCalcPi/Makefile | 63 ++++ src/tests/testCalcPi/testCalcPi.cpp | 76 +++++ src/tests/testCircle/Makefile | 63 ++++ src/tests/testCircle/testCircle.cpp | 67 ++++ src/tests/testColorWheel/Makefile | 63 ++++ src/tests/testColorWheel/testColorWheel.cpp | 75 +++++ src/tests/testConcavePolygon/Makefile | 63 ++++ .../testConcavePolygon/testConcavePolygon.cpp | 91 ++++++ src/tests/testCone/Makefile | 63 ++++ src/tests/testCone/testCone.cpp | 88 +++++ src/tests/testConstructors/Makefile | 63 ++++ .../testConstructors/testConstructors.cpp | 304 ++++++++++++++++++ src/tests/testConvexPolygon/Makefile | 63 ++++ .../testConvexPolygon/testConvexPolygon.cpp | 57 ++++ src/tests/testCosineIntegral/Makefile | 63 ++++ .../testCosineIntegral/testCosineIntegral.cpp | 84 +++++ src/tests/testCube/Makefile | 63 ++++ src/tests/testCube/testCube.cpp | 80 +++++ src/tests/testCuboid/Makefile | 63 ++++ src/tests/testCuboid/testCuboid.cpp | 85 +++++ src/tests/testCylinder/Makefile | 63 ++++ src/tests/testCylinder/testCylinder.cpp | 75 +++++ src/tests/testDice/Makefile | 63 ++++ src/tests/testDice/testDice.cpp | 179 +++++++++++ src/tests/testDiorama/Makefile | 63 ++++ src/tests/testDiorama/testDiorama.cpp | 118 +++++++ src/tests/testEllipse/Makefile | 63 ++++ src/tests/testEllipse/testEllipse.cpp | 71 ++++ src/tests/testEllipsoid/Makefile | 63 ++++ src/tests/testEllipsoid/testEllipsoid.cpp | 112 +++++++ src/tests/testFunction/Makefile | 63 ++++ src/tests/testFunction/testFunction.cpp | 51 +++ src/tests/testGetPixels/Makefile | 63 ++++ src/tests/testGetPixels/testGetPixels.cpp | 62 ++++ src/tests/testGradientWheel/Makefile | 63 ++++ .../testGradientWheel/testGradientWheel.cpp | 65 ++++ src/tests/testGraydient/Makefile | 63 ++++ src/tests/testGraydient/testGraydient.cpp | 52 +++ src/tests/testGreyscale/Makefile | 63 ++++ src/tests/testGreyscale/testGreyscale.cpp | 86 +++++ src/tests/testHighData/Makefile | 63 ++++ src/tests/testHighData/testHighData.cpp | 54 ++++ src/tests/testImage/Makefile | 63 ++++ src/tests/testImage/testImage.cpp | 101 ++++++ src/tests/testImageCart/Makefile | 63 ++++ src/tests/testImageCart/testImageCart.cpp | 37 +++ src/tests/testInverter/ImageInverter.cpp | 56 ++++ src/tests/testInverter/ImageInverter.h | 79 +++++ src/tests/testInverter/Makefile | 63 ++++ src/tests/testInverter/testInverter.cpp | 16 + src/tests/testLineChain/Makefile | 63 ++++ src/tests/testLineChain/testLineChain.cpp | 82 +++++ src/tests/testLineFan/Makefile | 63 ++++ src/tests/testLineFan/testLineFan.cpp | 66 ++++ src/tests/testLines/Makefile | 63 ++++ src/tests/testLines/testLines.cpp | 67 ++++ src/tests/testMouse/Makefile | 63 ++++ src/tests/testMouse/testMouse.cpp | 103 ++++++ src/tests/testPixels/Makefile | 63 ++++ src/tests/testPixels/testPixels.cpp | 103 ++++++ src/tests/testPrism/Makefile | 63 ++++ src/tests/testPrism/testPrism.cpp | 84 +++++ src/tests/testProcedural/Makefile | 63 ++++ src/tests/testProcedural/testProcedural.cpp | 125 +++++++ src/tests/testProgressBar/Makefile | 63 ++++ src/tests/testProgressBar/testProgressBar.cpp | 58 ++++ src/tests/testProjectiles/Makefile | 63 ++++ src/tests/testProjectiles/testProjectiles.cpp | 121 +++++++ src/tests/testPyramid/Makefile | 63 ++++ src/tests/testPyramid/testPyramid.cpp | 78 +++++ src/tests/test_specs/Makefile | 63 ++++ src/tests/test_specs/test_specs.cpp | 31 ++ 86 files changed, 6272 insertions(+) create mode 100644 src/tests/test2Dvs3D/Makefile create mode 100644 src/tests/test2Dvs3D/test2Dvs3D.cpp create mode 100644 src/tests/test3DRotation/Makefile create mode 100644 src/tests/test3DRotation/test3DRotation.cpp create mode 100644 src/tests/testAlphaRectangle/Makefile create mode 100644 src/tests/testAlphaRectangle/testAlphaRectangle.cpp create mode 100644 src/tests/testArrows/Makefile create mode 100644 src/tests/testArrows/testArrows.cpp create mode 100644 src/tests/testAura/Makefile create mode 100644 src/tests/testAura/testAura.cpp create mode 100644 src/tests/testBackground/Makefile create mode 100644 src/tests/testBackground/testBackground.cpp create mode 100644 src/tests/testBlurImage/Makefile create mode 100644 src/tests/testBlurImage/testBlurImage.cpp create mode 100644 src/tests/testCalcPi/Makefile create mode 100644 src/tests/testCalcPi/testCalcPi.cpp create mode 100644 src/tests/testCircle/Makefile create mode 100644 src/tests/testCircle/testCircle.cpp create mode 100644 src/tests/testColorWheel/Makefile create mode 100644 src/tests/testColorWheel/testColorWheel.cpp create mode 100644 src/tests/testConcavePolygon/Makefile create mode 100644 src/tests/testConcavePolygon/testConcavePolygon.cpp create mode 100644 src/tests/testCone/Makefile create mode 100644 src/tests/testCone/testCone.cpp create mode 100644 src/tests/testConstructors/Makefile create mode 100644 src/tests/testConstructors/testConstructors.cpp create mode 100644 src/tests/testConvexPolygon/Makefile create mode 100644 src/tests/testConvexPolygon/testConvexPolygon.cpp create mode 100644 src/tests/testCosineIntegral/Makefile create mode 100644 src/tests/testCosineIntegral/testCosineIntegral.cpp create mode 100644 src/tests/testCube/Makefile create mode 100644 src/tests/testCube/testCube.cpp create mode 100644 src/tests/testCuboid/Makefile create mode 100644 src/tests/testCuboid/testCuboid.cpp create mode 100644 src/tests/testCylinder/Makefile create mode 100644 src/tests/testCylinder/testCylinder.cpp create mode 100644 src/tests/testDice/Makefile create mode 100644 src/tests/testDice/testDice.cpp create mode 100644 src/tests/testDiorama/Makefile create mode 100644 src/tests/testDiorama/testDiorama.cpp create mode 100644 src/tests/testEllipse/Makefile create mode 100644 src/tests/testEllipse/testEllipse.cpp create mode 100644 src/tests/testEllipsoid/Makefile create mode 100644 src/tests/testEllipsoid/testEllipsoid.cpp create mode 100644 src/tests/testFunction/Makefile create mode 100644 src/tests/testFunction/testFunction.cpp create mode 100644 src/tests/testGetPixels/Makefile create mode 100644 src/tests/testGetPixels/testGetPixels.cpp create mode 100644 src/tests/testGradientWheel/Makefile create mode 100644 src/tests/testGradientWheel/testGradientWheel.cpp create mode 100644 src/tests/testGraydient/Makefile create mode 100644 src/tests/testGraydient/testGraydient.cpp create mode 100644 src/tests/testGreyscale/Makefile create mode 100644 src/tests/testGreyscale/testGreyscale.cpp create mode 100644 src/tests/testHighData/Makefile create mode 100644 src/tests/testHighData/testHighData.cpp create mode 100644 src/tests/testImage/Makefile create mode 100644 src/tests/testImage/testImage.cpp create mode 100644 src/tests/testImageCart/Makefile create mode 100644 src/tests/testImageCart/testImageCart.cpp create mode 100644 src/tests/testInverter/ImageInverter.cpp create mode 100644 src/tests/testInverter/ImageInverter.h create mode 100644 src/tests/testInverter/Makefile create mode 100644 src/tests/testInverter/testInverter.cpp create mode 100644 src/tests/testLineChain/Makefile create mode 100644 src/tests/testLineChain/testLineChain.cpp create mode 100644 src/tests/testLineFan/Makefile create mode 100644 src/tests/testLineFan/testLineFan.cpp create mode 100644 src/tests/testLines/Makefile create mode 100644 src/tests/testLines/testLines.cpp create mode 100644 src/tests/testMouse/Makefile create mode 100644 src/tests/testMouse/testMouse.cpp create mode 100644 src/tests/testPixels/Makefile create mode 100644 src/tests/testPixels/testPixels.cpp create mode 100644 src/tests/testPrism/Makefile create mode 100644 src/tests/testPrism/testPrism.cpp create mode 100644 src/tests/testProcedural/Makefile create mode 100644 src/tests/testProcedural/testProcedural.cpp create mode 100644 src/tests/testProgressBar/Makefile create mode 100644 src/tests/testProgressBar/testProgressBar.cpp create mode 100644 src/tests/testProjectiles/Makefile create mode 100644 src/tests/testProjectiles/testProjectiles.cpp create mode 100644 src/tests/testPyramid/Makefile create mode 100644 src/tests/testPyramid/testPyramid.cpp create mode 100644 src/tests/test_specs/Makefile create mode 100644 src/tests/test_specs/test_specs.cpp diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile new file mode 100644 index 000000000..2e37f36e4 --- /dev/null +++ b/src/tests/test2Dvs3D/Makefile @@ -0,0 +1,63 @@ +# Makefile for test2Dvs3D + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test2Dvs3D + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp new file mode 100644 index 000000000..2c47d5f79 --- /dev/null +++ b/src/tests/test2Dvs3D/test2Dvs3D.cpp @@ -0,0 +1,96 @@ +/* + * test2Dvs3D.cpp + * + * Usage: ./test2Dvs3D + */ + +#include +#include + +using namespace tsgl; + +void contrastFunction(Canvas& can) { + ColorFloat pyramidcolors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + ColorFloat triangle2Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(0,1,0,1) }; + ColorFloat triangle3Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(1,0,1,1), ColorFloat(1,0,0,1) }; + ColorFloat triangle6Colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1) }; + Pyramid * testPyramid = new Pyramid(-200, 0.0, -100, 4, 200, 200, 0.0, 0.0, 45.0, pyramidcolors); + // can.add(testPyramid); + Triangle * triangle1 = new Triangle(139,66,0,350,-52,0,162,-200,0,0,0,0,pyramidcolors); + // can.add(triangle1); + Triangle * triangle2 = new Triangle(139,66,0,49,-52,0,162,-200,0,0,0,0,triangle2Colors); + // can.add(triangle2); + Triangle * triangle3 = new Triangle(139,66,0,350,-52,0,227,40,0,0,0,0,triangle3Colors); + // can.add(triangle3); + Triangle * triangle4 = new Triangle(265,64,0,331,-44,0,263,-194,0,0,0,0,pyramidcolors); + // can.add(triangle4); + Triangle * triangle5 = new Triangle(265,64,0,16,-70,0,263,-194,0,0,0,0,triangle2Colors); + // can.add(triangle5); + Triangle * triangle6 = new Triangle(265,64,0,16,-70,0,166,47,0,0,0,0,triangle6Colors); + // can.add(triangle6); + // testPyramid->setPitch(45); + int stepsTaken = 0; + while (can.isOpen()) { + can.sleep(); + if (can.getFrameNumber() >= 1700 && stepsTaken < 1) { + can.add(triangle1); + stepsTaken++; + } + if (can.getFrameNumber() >= 1800 && stepsTaken < 2) { + can.add(triangle2); + stepsTaken++; + } + if (can.getFrameNumber() >= 1900 && stepsTaken < 3) { + can.add(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 2600 && stepsTaken < 4) { + can.add(testPyramid); + stepsTaken++; + } + if (can.getFrameNumber() >= 3300 && stepsTaken < 5) { + can.remove(triangle1); + can.remove(triangle2); + can.remove(triangle3); + stepsTaken++; + } + if (can.getFrameNumber() >= 3800 && stepsTaken < 6) { + can.add(triangle4); + stepsTaken++; + } + if (can.getFrameNumber() >= 3900 && stepsTaken < 7) { + can.add(triangle5); + stepsTaken++; + } + if (can.getFrameNumber() >= 4000 && stepsTaken < 8) { + can.add(triangle6); + stepsTaken++; + } + if (can.getFrameNumber() >= 4400 && stepsTaken < 9) { + if (testPyramid->getPitch() < 45) { + testPyramid->changePitchBy(0.5); + } else { + testPyramid->setPitch(45); + stepsTaken++; + } + } + } + + delete testPyramid; + delete triangle1; + delete triangle2; + delete triangle3; + delete triangle4; + delete triangle5; + delete triangle6; + +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Drawing vs. 2D Drawing", BLACK); + c.run(contrastFunction); +} \ No newline at end of file diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile new file mode 100644 index 000000000..03345c4c7 --- /dev/null +++ b/src/tests/test3DRotation/Makefile @@ -0,0 +1,63 @@ +# Makefile for test3DRotation + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test3DRotation + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test3DRotation/test3DRotation.cpp b/src/tests/test3DRotation/test3DRotation.cpp new file mode 100644 index 000000000..1ed4e77bd --- /dev/null +++ b/src/tests/test3DRotation/test3DRotation.cpp @@ -0,0 +1,48 @@ +/* + * test3DRotation.cpp + * + * Usage: ./test3DRotation + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Cube * testCube = new Cube(200, 0.0, 0.0, 100, 0.0, 0.0, 0.0, colors); + testCube->setRotationPoint(0,0,0); + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 90.0, colors); + Sphere * testSphere = new Sphere(300, 0, 0, 100, 0.0, 0.0, 0.0, colors); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + can.add(testCube); + can.add(testPrism); + can.add(testSphere); + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + testCube->setYaw(rotation); + testPrism->setYaw(-rotation); + testSphere->setRotationPoint(testCube->getCenterX(), testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setCenter(testCube->getCenterX() + 100, testCube->getCenterY(), testCube->getCenterZ()); + testSphere->setYaw(-rotation); + rotation += 1; + } + + delete testCube; + delete testPrism; + delete testSphere; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "3D Rotation", BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile new file mode 100644 index 000000000..072c3514f --- /dev/null +++ b/src/tests/testAlphaRectangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAlphaRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAlphaRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAlphaRectangle/testAlphaRectangle.cpp b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp new file mode 100644 index 000000000..8721ee1ea --- /dev/null +++ b/src/tests/testAlphaRectangle/testAlphaRectangle.cpp @@ -0,0 +1,49 @@ +/* + * testAlphaRectangle.cpp + * + * Usage: ./testAlphaRectangle + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws semi-transparent rectangles on a Canvas. + * \details + * - Store the Canvas' width and height in variables for easy reuse. + * - Set up the internal timer of the Canvas to expire once every \b FRAME / 10 seconds. + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - Select a random position on the Canvas for a corner of a rectangle. + * - Draw a rectangle stretching from the specified corner to another corner on the Canvas, + * with a random color and a transparency of 16 (~0.06). + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void alphaRectangleFunction(Canvas& can) { + Background * bg = can.getBackground(); + const int WW = can.getWindowWidth(), WH = can.getWindowHeight(); + int a, b, c, d, x, y, w, h; + while (can.isOpen()) { + can.sleep(); + a = saferand(-WW/2,WW/2); b = saferand(-WH/2, WH/2); + c = saferand(-WW/2,WW/2); d = saferand(-WH/2, WH/2); + x = (a + c) / 2; + y = (b + d) / 2; + w = abs(c - a); + h = abs(d - b); + bg->drawRectangle(x, y, 0, w, h, 0,0,0, ColorFloat(randfloat(), randfloat(), randfloat(), (float) 16/255)); + } +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Fancy Rectangles", BLACK); + c.run(alphaRectangleFunction); +} diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile new file mode 100644 index 000000000..7411d70f1 --- /dev/null +++ b/src/tests/testArrows/Makefile @@ -0,0 +1,63 @@ +# Makefile for testArrows + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testArrows + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp new file mode 100644 index 000000000..61b13731c --- /dev/null +++ b/src/tests/testArrows/testArrows.cpp @@ -0,0 +1,51 @@ +/** + * testArrows.cpp tests displaying the Line class's Arrow and Dotted attributes + */ +#include +using namespace tsgl; + +void arrowFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.5), ColorFloat(0,1,0,1) }; + Arrow* doubleArrow = new Arrow(0, 0, 0, 200, 5,0,0,0, colors, false); + Arrow* arrow2 = new Arrow(100 ,100 ,-1 ,200 ,5,0,0,0,ColorFloat(0,0,1,0.65), true); + c.add(doubleArrow); + c.add(arrow2); + // doubleArrow->setCenterX(100); + // doubleArrow->setRotationPoint(0,0,0); + // doubleArrow->setYaw(45); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", doubleArrow->getAlpha()); + // doubleArrow->setColor(colors); + // printf("%f\n", doubleArrow->getAlpha()); + float floatVal = 0.0f; + GLfloat delta = 5; + bool boolean = true; + while( c.isOpen() ) { + c.sleep(); + // doubleArrow->setCenterX(sin(floatVal/90)); + // doubleArrow->setCenterY(sin(floatVal/90)); + // doubleArrow->setCenterZ(sin(floatVal/90)); + // doubleArrow->setYaw(floatVal); + // doubleArrow->setPitch(floatVal); + // doubleArrow->setRoll(floatVal); + // doubleArrow->setLength(sin(floatVal/90) * 100 + 200); + if (doubleArrow->getLength() > 300 || doubleArrow->getLength() < 100) { + delta *= -1; + arrow2->setIsOutlined(boolean); + arrow2->setIsFilled(!boolean); + boolean = !boolean; + } + doubleArrow->changeLengthBy(delta); + floatVal += 1; + } + + delete doubleArrow; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Arrows"); + c.run(arrowFunction); +} \ No newline at end of file diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile new file mode 100644 index 000000000..f1487e646 --- /dev/null +++ b/src/tests/testAura/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAura + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAura + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testAura/testAura.cpp b/src/tests/testAura/testAura.cpp new file mode 100644 index 000000000..5620f36d7 --- /dev/null +++ b/src/tests/testAura/testAura.cpp @@ -0,0 +1,111 @@ +/* + * testMouse.cpp + * + * Usage: ./testMouse + */ + +#include + +using namespace tsgl; + +inline float dist(float x1, float y1, float x2, float y2) { + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +inline void scatter(float& f, float max) { + float am = 1.0f - ((rand() % 20000) / 10000.0f); + f += max*am; +} + +/*! + * + */ +void auraFunction(Canvas& can, int segs) { + const float SR2 = sqrt(2); + const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); + const int ccw = CW/2, cch = CH/2; + const float ROT = 0.01f; + const float HUEDELTA = 0.01f; + const float OFF = (2*PI/segs); + const float START = PI/2; + + int mx, my; + ColorHSV *cf = new ColorHSV[segs]; + bool *drawn = new bool[segs]; + float *x1 = new float[segs], *y1 = new float[segs], + *x2 = new float[segs], *y2 = new float[segs]; + + float mangle = 0; + float mdist = 0; + + for (int i = 0; i < segs; ++i) { + cf[i] = Colors::highContrastColor(i); + cf[i].A = 0.01f; + } + + while(can.isOpen()) { + //Update mouse coordinates + scatter(mangle,0.02f); + scatter(mdist,2.0f); + if (mdist > 100) mdist *= 0.99f; + mx = can.getMouseX()+mdist*cos(mangle); + my = can.getMouseY()+mdist*sin(mangle); + + //Update positions of the edges of the triangles + float ang = START + ROT*can.getFrameNumber(); + for (int i = 0; i < segs; ++i) { + cf[i].H += HUEDELTA; + if (cf[i].H > 6.0f) cf[i].H = 0.0f; + float sang = sin(ang), cang = cos(ang); + if (fabs(cang) > fabs(sang)) { + x1[i] = (cang > 0) ? CW : 0; + y1[i] = cch+cch*sang*SR2; + } else { + y1[i] = (sang > 0) ? CH : 0; + x1[i] = ccw+ccw*cang*SR2; + } + ang += OFF; + } + for (int i = 0; i < segs; ++i) { + x2[i] = x1[(i+1)%segs]; + y2[i] = y1[(i+1)%segs]; + } + + //Draw the triangles + can.pauseDrawing(); + for (int i = 0; i < segs; drawn[i++] = false); + for (int i = 0; i < segs; ++i) { + int next = -1; + float bdist = 999999; + //Draw the triangles closest to the mouse first (lazy depth test) + for (int j = 0; j < segs; ++j) { + if (drawn[j]) + continue; + float d = dist(mx,my,x1[j],y1[j]) + dist(mx,my,x2[j],y2[j]); + if (d < bdist) { + bdist = d; + next = j; + } + } + if (next >= 0) { + can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); + drawn[next] = true; + } + } + can.resumeDrawing(); + can.sleep(); + } + + //Clean up + delete [] x1; delete [] y1; + delete [] x2; delete [] y2; + delete [] drawn; delete [] cf; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : -1; + int h = (argc > 2) ? atoi(argv[2]) : w; + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs()*2; + Canvas c(-1, -1, w, h, "Aura", BLACK); + c.run(auraFunction,t); +} diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile new file mode 100644 index 000000000..9389a941a --- /dev/null +++ b/src/tests/testBackground/Makefile @@ -0,0 +1,63 @@ +# Makefile for testBackground + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBackground + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBackground/testBackground.cpp b/src/tests/testBackground/testBackground.cpp new file mode 100644 index 000000000..58d1362bf --- /dev/null +++ b/src/tests/testBackground/testBackground.cpp @@ -0,0 +1,70 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include +#include + +using namespace tsgl; + +void backgroundFunction(Canvas& can) { + Background * bg = can.getBackground(); + Cube * cube = new Cube(-250,0,0,100,0,45,45,YELLOW); + float x = 0; + + can.bindToButton(TSGL_LEFT, TSGL_PRESS, [&cube]() { + cube->changeXBy(-10); + }); + + can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeXBy(10); + }); + + can.bindToButton(TSGL_UP, TSGL_PRESS, [&cube]() { + cube->changeYBy(10); + }); + + can.bindToButton(TSGL_DOWN, TSGL_PRESS, [&cube]() { + cube->changeYBy(-10); + }); + + can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&cube]() { + cube->changeZBy(-50); + }); + + can.bindToButton(TSGL_MOUSE_RIGHT, TSGL_PRESS, [&cube]() { + cube->changeZBy(50); + }); + + // bg->drawSquare(0,0,0,200,0,0,0,RED); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&bg, &can]() { + bg->setClearColor(Colors::randomColor()); + // can.setBackgroundColor(Colors::randomColor()); + bg->clear(); + // can.clearBackground(); + // printf("%f, %f, %f, %f\n", can.getBackgroundColor().R, can.getBackgroundColor().G, can.getBackgroundColor().B, can.getBackgroundColor().A); + // printf("%f, %f, %f, %f\n", bg->getClearColor().R, bg->getClearColor().G, bg->getClearColor().B, bg->getClearColor().A); + }); + + can.add(cube); + while (can.isOpen()) { + can.sleep(); + // bg->clear(); + x = 200 * sin( (float) can.getFrameNumber()/90); + bg->drawSquare(x,0,0,200,0,0,0,RED, true); + // cube->setCenterZ(500 * cos((float) can.getFrameNumber()/50)); + } + delete cube; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Background", BLUE); + c.run(backgroundFunction); +} \ No newline at end of file diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile new file mode 100644 index 000000000..a41f766fc --- /dev/null +++ b/src/tests/testBlurImage/Makefile @@ -0,0 +1,63 @@ +# Makefile for testBlurImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testBlurImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testBlurImage/testBlurImage.cpp b/src/tests/testBlurImage/testBlurImage.cpp new file mode 100644 index 000000000..005d6399d --- /dev/null +++ b/src/tests/testBlurImage/testBlurImage.cpp @@ -0,0 +1,62 @@ +/* + * testBlurImage.cpp + * + * Usage: ./testBlurImage + */ + +#include +#include + +using namespace tsgl; + +int depthtest(int xmin, int ymin, int xmax, int ymax) { + int xd = 0, yd = 0; + for (float d = xmax-xmin; d > 1; d=ceil(d/2), ++xd); + for (float d = ymax-ymin; d > 1; d=ceil(d/2), ++yd); + return ((xd > yd) ? xd : yd); +} + +bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { + if (xmin > xmax || ymin > ymax) + return false; + if (depth > 0) { + int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; + blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); + blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); + blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); + blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); + return false; + } + ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); + ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); + for (int j = ymin; j <= ymax; ++j) + for (int i = xmin; i <= xmax; ++i) + can.drawPoint(i,j,Colors::blend(top,bot)); + return true; +} + +void blurImageFunction(Canvas& can, std::string fpath, int threads) { + int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + int side = sqrt(threads); //Square root of the number of threads, rounded down + can.drawImage(fpath, 0, 0, cww, cwh); + can.sleepFor(0.5f); + #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square + { + side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads + int tid = omp_get_thread_num(); + int ndrawn = 0, xblock = cww/side, yblock = cwh/side; + int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; + int xmax = xmin+xblock; clamp(xmax,0,cww-1); + int ymax = ymin+yblock; clamp(ymax,0,cwh-1); + int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); + for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); + } +} + +int main(int argc, char* argv[]) { + int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; + TextureHandler::getDimensions(fname,w,h); + Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); + c.run(blurImageFunction,fname,t); +} diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile new file mode 100644 index 000000000..4d79e6724 --- /dev/null +++ b/src/tests/testCalcPi/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCalcPi + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCalcPi + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCalcPi/testCalcPi.cpp b/src/tests/testCalcPi/testCalcPi.cpp new file mode 100644 index 000000000..6a3a6074c --- /dev/null +++ b/src/tests/testCalcPi/testCalcPi.cpp @@ -0,0 +1,76 @@ +/* + * testCalcPi.cpp + * + * Usage: ./testCalcPi + */ + +#include // printf(), ... +#include // stoll(), ... +#include // exit() +#include // OpenMP functions +#include // IntegralViewer + +using namespace tsgl; + +/*! + * \brief Compute a y-coordinate. + * \details Takes in an x-coordinate and calculates its corresponding y-coordinate. + * The IntegralViewer class then plots that point. + * \param x The x-coordinate to calculate the y-coordinate for. + * \return The calculated y-coordinate for the passed x value. + * \see IntegralViewer class. + */ +inline Decimal unitCircleFunction(Decimal x) { + return (fabs(x) < 1.0L) ? sqrt( 1.0L - (x*x) ) : 0.0L; +} + +/*! + * \brief Computes the Cosine value for an x-coordinate. + * \param x The x value to calculate the Cosine value for. + * \return The Cosine value for the passed x value. + */ +inline Decimal sineFunction(Decimal x) { + return cos(8*x); +} + +/*! + * \brief testCalcPi's main method. + * \details Everything that is needed in order to run testCalcPi is in this main method. + * - Handle command-line arguments that were passed. If more than 2 were passed, print an error message and + * exit the process. + * - Now, check and see if any command-line arguments were passed at all. If not, set default values + * for the number of intervals and the number of threads to use. + * - Setup the IntegralViewer object; set the number of threads to use and create the IntergralViewer + * object with the information given and calculated. + * - Evaluate the integral of the unit circle function using rectangles, then evaluate it using trapezoids. + * - Now evaluate the Cosine function integral using rectangles and trapezoids. + * . + */ +int main(int argc, char** argv) { + //Handle command line + if (argc > 3) { + fprintf(stderr, "\nUsage: calcPI2 [intervals] [numThreads]\n\n"); + exit(1); + } + + //Check if the number of intervals and the number of threads was passed + //If one was not, set it to a default value + long long numIntervals = (argc > 1) ? std::stoll(argv[1], 0, 10) : 1; + unsigned numThreads = (argc > 2) ? std::stoll(argv[2], 0, 10) : 1; + + //Setup + omp_set_num_threads(numThreads); + IntegralViewer i1(&unitCircleFunction, 800, 800, 0.0l, 1.0l, 0.0l, 1.0l, "unit circle"); + + //Go! + printf("Reference pi: 3.141592653589793238462643383279...)\n"); + long double rectanglesPi = i1.rectangleEvaluate(numIntervals) * 4.0; + printf("Rectangles pi: %32.30Lf in %f secs\n", rectanglesPi, i1.getRecTime() ); + long double trapezoidsPi = i1.trapezoidEvaluate(numIntervals) * 4.0; + printf("Trapezoids pi: %32.30Lf in %f secs\n", trapezoidsPi, i1.getTrapTime() ); + + //Bonus! + IntegralViewer i2(&sineFunction, 1200, 800, -1.1l, 1.2l, -1.3l, 1.4l, "cosine"); + i2.rectangleEvaluate(numIntervals); + i2.trapezoidEvaluate(numIntervals); +} diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile new file mode 100644 index 000000000..dbd7c9653 --- /dev/null +++ b/src/tests/testCircle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCircle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCircle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCircle/testCircle.cpp b/src/tests/testCircle/testCircle.cpp new file mode 100644 index 000000000..e1740776d --- /dev/null +++ b/src/tests/testCircle/testCircle.cpp @@ -0,0 +1,67 @@ +/* + * testCircle.cpp + * + * Usage: ./testCircle + */ + +#include +#include + +using namespace tsgl; + +void circleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Circle * circle = new Circle(0,0,0,100,0,0,0,colors); + + // printf("%f\n", circle->getAlpha()); + // circle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", circle->getAlpha()); + // circle->setColor(colors); + // printf("%f\n", circle->getAlpha()); + // circle->setCenterX(200); + // circle->setRotationPoint(0,0,0); + can.add(circle); + float floatVal = 0.0f; + GLfloat delta = 1; + while (can.isOpen()) { + can.sleep(); + // circle->setCenterX(sin(floatVal/90) * 100); + // circle->setCenterY(sin(floatVal/90) * 100); + // circle->setCenterZ(sin(floatVal/90) * 100); + // circle->setYaw(floatVal); + // circle->setPitch(floatVal); + // circle->setRoll(floatVal); + // circle->setRadius(sin(floatVal/90) * 100 + 100); + if (circle->getRadius() > 300 || circle->getRadius() < 100) { + delta *= -1; + } + circle->changeRadiusBy(delta); + if (delta > 0) { + circle->setColor(colors); + } else { + circle->setColor(RED); + } + floatVal += 1; + } + + delete circle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Basic Circle", BLACK); + c.run(circleFunction); +} \ No newline at end of file diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile new file mode 100644 index 000000000..5fbc43185 --- /dev/null +++ b/src/tests/testColorWheel/Makefile @@ -0,0 +1,63 @@ +# Makefile for testColorWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testColorWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testColorWheel/testColorWheel.cpp b/src/tests/testColorWheel/testColorWheel.cpp new file mode 100644 index 000000000..3a7404d33 --- /dev/null +++ b/src/tests/testColorWheel/testColorWheel.cpp @@ -0,0 +1,75 @@ +/* + * testColorWheel.cpp + * + * Usage: ./testColorWheel + */ + +#include +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/*! + * \brief Draws a gradient color wheel using OMP with multiple threads per processor and private per-thread variables. + * \details + * - \b THREADS is set to a number greater than the number of physical processors. + * - The center of the canvas is computed and stored. + * - The radius of the wheel is computed (using the minimum of the Canvas width / height) and stored. + * - The size of the \b GRADIENT is computed and stored. + * - Variables for the second and third vertices of a triangle and the current shading are initialized. + * - The internal timer of the Canvas is set up to expire every \b FRAME seconds. + * - The predetermined number of parallel threads is forked off using OMP, pulling along the coordinate + * and shading variables. + * - The actual number of threads is stored in: \b nthreads. + * - A color \b delta is computed. + * - Each thread's thread id ( \b tid ) is stored. + * - Each thread's shading is computed using it's id and \b nthreads. + * - While the Canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - Each thread's \b start is computed using the timer's lifetime and it's current id. + * - The second and third coordinates of a triangle approximating an arc of a circle are + * computed using the \b GRADIENT and the thread's \b start position. + * - A triangle is drawn on the Canvas for each thread, with the first vertex in the center, and + * the second and third vertices as computed above, with a hue based on the precomputed \b start, + * full saturation, and a value of \b shading. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void colorWheelFunction(Canvas& can, int threads) { + const int CW = can.getWindowWidth() / 2, // Half the window's width + CH = can.getWindowHeight() / 2; // Half the window's height + const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel + GRADIENT = 2 * PI / NUM_COLORS; // Gap between wedges + #pragma omp parallel num_threads(threads) + { + float x2, x3, y2, y3, shading; + int tid = omp_get_thread_num(); + int delta = tid * NUM_COLORS / threads; // Distance between threads to compute + shading = 1 - (float) tid / threads; + while (can.isOpen()) { + can.sleep(); + int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; + x2 = CW + RADIUS * sin(GRADIENT * start); + y2 = CH + RADIUS * cos(GRADIENT * start); + x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); + y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); + can.drawTriangle(CW, CH, x2, y2, x3, y3, + ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); + } + } +} + + +//Takes command line arguments for the height and width of the window +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : 64; + Canvas c(-1, -1, w, h, "Color Wheel"); + c.run(colorWheelFunction,t); +} diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile new file mode 100644 index 000000000..b6163fc7e --- /dev/null +++ b/src/tests/testConcavePolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConcavePolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConcavePolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConcavePolygon/testConcavePolygon.cpp b/src/tests/testConcavePolygon/testConcavePolygon.cpp new file mode 100644 index 000000000..00cf81104 --- /dev/null +++ b/src/tests/testConcavePolygon/testConcavePolygon.cpp @@ -0,0 +1,91 @@ +/* + * testConcavePolygon.cpp + * + * Usage: ./testConcavePolygon + */ + +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/** + * \brief Draw Concave polygons, which have one or more interior angles > 180 + * \note See http://www.mathopenref.com/polygonconcave.html + * \details + * - Initialize a constant \b PSIZE. + * - Have two arrays of integers, \b xx and \b yy and set them to have size \b PSIZE. + * - Create an empty array of colors of size \b PSIZE and fill it with random colors. + * - Fill the arrays of integers, \b xx and \b yy, with specific values. + * - While the Canvas is open: + * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. + * - Draw a Concave polygon on the Canvas and pass x-coordinate, y-coordinate, z-coordinate, \b PSIZE, the arrays \b xx and \b yy, yaw, pitch, roll, and the array of colors as arguments. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void concavePolygonFunction(Canvas& can) { + const int PSIZE = 64; + + float xx[PSIZE]; + float yy[PSIZE]; + ColorFloat color[PSIZE]; + for (unsigned i = 0; i < PSIZE; ++i) + color[i] = ColorFloat(randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX), randfloat(RAND_MAX)); + + color[1] = color[PSIZE-1]; + + xx[0] = 0; + yy[0] = 0; + for (int i = 0; i < PSIZE-1; ++i) { + if (i % 2 == 0) { + xx[i+1] = 0 + 250 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 250 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } else { + xx[i+1] = 0 + 150 * sin((1.0f*i)/(PSIZE-2) * PI * 2); + yy[i+1] = 0 - 150 * cos((1.0f*i)/(PSIZE-2) * PI * 2); + } + } + + // for (int i = 0; i < PSIZE; ++i) { + // if (i % 2 == 0) { + // xx[i] = 0 + 250 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 250 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } else { + // xx[i] = 0 + 150 * sin((1.0f*i)/(PSIZE) * PI * 2); + // yy[i] = 0 - 150 * cos((1.0f*i)/(PSIZE) * PI * 2); + // } + // } + + ConcavePolygon * c2 = new ConcavePolygon(0,0,0,PSIZE, xx, yy, 0,0,0,color); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", c2->getAlpha()); + // c2->setColor(color); + // printf("%f\n", c2->getAlpha()); + can.add(c2); + + float floatVal = 0.0f; + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + // c2->setCenterX(sin(floatVal/90)); + // c2->setCenterY(sin(floatVal/90)); + // c2->setCenterZ(sin(floatVal/90)); + // c2->setYaw(floatVal); + // c2->setPitch(floatVal); + // c2->setRoll(floatVal); + floatVal += 1; + } + + delete c2; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Concave Polygons", WHITE); + c.run(concavePolygonFunction); +} diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile new file mode 100644 index 000000000..38b60a4c2 --- /dev/null +++ b/src/tests/testCone/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCone + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCone + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCone/testCone.cpp b/src/tests/testCone/testCone.cpp new file mode 100644 index 000000000..951d05b18 --- /dev/null +++ b/src/tests/testCone/testCone.cpp @@ -0,0 +1,88 @@ +/* + * testCone.cpp + * + * Usage: ./testCone + */ + +#include +#include + +using namespace tsgl; + +void coneFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1), + ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1) }; + Cone * testCone = new Cone(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 0.0, colors); + Cone * testCone2 = new Cone(-300.0, 0.0, 0.0, 200, 100.0, 0.0, 0.0, 90.0, RED); + can.add(testCone); + can.add(testCone2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCone->setCenterX(sin(rotation)*2); + // testCone->setCenterY(cos(rotation)*2); + // testCone->setCenterZ(sin(rotation)); + // testCone->setYaw(rotation*45); + // testCone->setPitch(rotation*45); + testCone->setRoll(rotation*45); + // testCone->setHeight(sin(rotation)+1.01); + // testCone->setRadius(sin(rotation)+1.01); + // if(testCone->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCone->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeHeightBy(delta); + // if(testCone->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCone->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCone->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCone->setColor(RED); + } else { + testCone->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCone; + delete testCone2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cone", BLACK); + c.run(coneFunction); +} \ No newline at end of file diff --git a/src/tests/testConstructors/Makefile b/src/tests/testConstructors/Makefile new file mode 100644 index 000000000..c01fe882d --- /dev/null +++ b/src/tests/testConstructors/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConstructors + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConstructors + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConstructors/testConstructors.cpp b/src/tests/testConstructors/testConstructors.cpp new file mode 100644 index 000000000..062fa79e5 --- /dev/null +++ b/src/tests/testConstructors/testConstructors.cpp @@ -0,0 +1,304 @@ +/* + * testConcavePolygon.cpp + * + * Usage: ./testConcavePolygon + */ + +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/** + * \brief Draw Concave polygons, which have one or more interior angles > 180 + * \note See http://www.mathopenref.com/polygonconcave.html + * \details + * - Initialize a constant \b PSIZE. + * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. + * - Create an empty array of colors of size \b PSIZE and fill it with random colors. + * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). + * - Fill the other arrays of integers, \b xx and \b yy, with specific values. + * - While the Canvas is open: + * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. + * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. + * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void constructorFunction(Canvas& can) { + // srand(time(NULL)); + const int PSIZE = 50; + + ColorFloat fillColor[PSIZE]; + ColorFloat outlineColor[PSIZE]; + for (unsigned i = 0; i < PSIZE; ++i) { + fillColor[i] = Colors::randomColor(1.0f); + outlineColor[i] = Colors::randomColor(1.0f); + } + + can.drawRectangle(15, 5, 70, 95, fillColor[0], true); + can.drawRectangle(115, 5, 70, 95, fillColor[0], false); + can.drawRectangle(215, 5, 70, 95, fillColor, true); + can.drawRectangle(315, 5, 70, 95, fillColor, false); + + can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); + can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); + can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); + can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); + + can.drawSquare(5, 105, 90, fillColor[0], true); + can.drawSquare(105, 105, 90, fillColor[0], false); + can.drawSquare(205, 105, 90, fillColor, true); + can.drawSquare(305, 105, 90, fillColor, false); + + can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); + can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); + can.drawSquare(605, 105, 90, fillColor[0], outlineColor); + can.drawSquare(705, 105, 90, fillColor, outlineColor); + + can.drawStar(50, 250, 45, 6, fillColor[0], true, false); + can.drawStar(150, 250, 45, 6, fillColor[0], false, true); + can.drawStar(250, 250, 45, 6, fillColor, true, false); + can.drawStar(350, 250, 45, 6, fillColor, false, true); + + can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); + can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); + can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); + can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); + + can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); + can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); + can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); + can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); + + can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); + can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); + can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); + can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); + + can.drawEllipse(50, 450, 35, 45, fillColor[0], true); + can.drawEllipse(150, 450, 35, 45, fillColor[0], false); + can.drawEllipse(250, 450, 35, 45, fillColor, true); + can.drawEllipse(350, 450, 35, 45, fillColor, false); + + can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); + can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); + can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); + can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); + + can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); + can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); + can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); + can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); + + can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); + can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); + can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); + can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); + + can.drawCircle(50, 650, 45, fillColor[0], true); + can.drawCircle(150, 650, 45, fillColor[0], false); + can.drawCircle(250, 650, 45, fillColor, true); + can.drawCircle(350, 650, 45, fillColor, false); + + can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); + can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); + can.drawCircle(650, 650, 45, fillColor[0], outlineColor); + can.drawCircle(750, 650, 45, fillColor, outlineColor); + + int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; + + x1[0] = x1[1] = 5; + x1[2] = 50; + x1[3] = x1[4] = 95; + + x2[0] = x2[1] = 105; + x2[2] = 150; + x2[3] = x2[4] = 195; + + x3[0] = x3[1] = 205; + x3[2] = 250; + x3[3] = x3[4] = 295; + + x4[0] = x4[1] = 305; + x4[2] = 350; + x4[3] = x4[4] = 395; + + x5[0] = x5[1] = 405; + x5[2] = 450; + x5[3] = x5[4] = 495; + + x6[0] = x6[1] = 505; + x6[2] = 550; + x6[3] = x6[4] = 595; + + x7[0] = x7[1] = 605; + x7[2] = 650; + x7[3] = x7[4] = 695; + + x8[0] = x8[1] = 705; + x8[2] = 750; + x8[3] = x8[4] = 795; + + y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; + y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; + y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; + y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; + y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; + + can.drawTriangleStrip(5, x1, y1, fillColor[0], true); + can.drawTriangleStrip(5, x2, y2, fillColor[0], false); + can.drawTriangleStrip(5, x3, y3, fillColor, true); + can.drawTriangleStrip(5, x4, y4, fillColor, false); + + can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); + can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); + can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); + can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); + + int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], + y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; + + x9[0] = x9[1] = 5; + x9[2] = x9[5] = 50; + x9[3] = x9[4] = 95; + + x10[0] = x10[1] = 105; + x10[2] = x10[5] = 150; + x10[3] = x10[4] = 195; + + x11[0] = x11[1] = 205; + x11[2] = x11[5] = 250; + x11[3] = x11[4] = 295; + + x12[0] = x12[1] = 305; + x12[2] = x12[5] = 350; + x12[3] = x12[4] = 395; + + x13[0] = x13[1] = 405; + x13[2] = x13[5] = 450; + x13[3] = x13[4] = 495; + + x14[0] = x14[1] = 505; + x14[2] = x14[5] = 550; + x14[3] = x14[4] = 595; + + x15[0] = x15[1] = 605; + x15[2] = x15[5] = 650; + x15[3] = x15[4] = 695; + + x16[0] = x16[1] = 705; + x16[2] = x16[5] = 750; + x16[3] = x16[4] = 795; + + y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; + y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; + y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; + y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; + y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; + y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; + + can.drawConvexPolygon(6, x9, y9, fillColor[0], true); + can.drawConvexPolygon(6, x10, y10, fillColor[0], false); + can.drawConvexPolygon(6, x11, y11, fillColor, true); + can.drawConvexPolygon(6, x12, y12, fillColor, false); + + can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); + can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); + can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); + can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); + + int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], + y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; + + x17[0] = x17[1] = 5; + x17[2] = x17[5] = 50; + x17[3] = x17[4] = 95; + + x18[0] = x18[1] = 105; + x18[2] = x18[5] = 150; + x18[3] = x18[4] = 195; + + x19[0] = x19[1] = 205; + x19[2] = x19[5] = 250; + x19[3] = x19[4] = 295; + + x20[0] = x20[1] = 305; + x20[2] = x20[5] = 350; + x20[3] = x20[4] = 395; + + x21[0] = x21[1] = 405; + x21[2] = x21[5] = 450; + x21[3] = x21[4] = 495; + + x22[0] = x22[1] = 505; + x22[2] = x22[5] = 550; + x22[3] = x22[4] = 595; + + x23[0] = x23[1] = 605; + x23[2] = x23[5] = 650; + x23[3] = x23[4] = 695; + + x24[0] = x24[1] = 705; + x24[2] = x24[5] = 750; + x24[3] = x24[4] = 795; + + y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; + y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; + y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; + y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; + y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; + y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; + + can.drawConcavePolygon(6, x17, y17, fillColor[0], true); + can.drawConcavePolygon(6, x18, y18, fillColor[0], true); + can.drawConcavePolygon(6, x19, y19, fillColor, true); + can.drawConcavePolygon(6, x20, y20, fillColor, true); + + can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); + can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); + can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); + can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); + + can.drawArrow(805, 5, 895, 95, fillColor[3], true); + can.drawArrow(805, 105, 895, 195, fillColor, true); + + can.drawLine(805, 205, 895, 295, fillColor[3]); + can.drawLine(805, 305, 895, 395, fillColor); + + int x25[5], x26[5], y25[5], y26[5]; + + x25[0] = x26[0] = 820; + x25[1] = x26[1] = 805; + x25[2] = x26[2] = 880; + x25[3] = x26[3] = 895; + x25[4] = x26[4] = 870; + + y25[0] = 450; + y25[1] = 405; + y25[2] = 420; + y25[3] = 460; + y25[4] = 495; + + y26[0] = 550; + y26[1] = 505; + y26[2] = 520; + y26[3] = 560; + y26[4] = 595; + + can.drawPolyline(5, x25, y25, fillColor[3]); + can.drawPolyline(5, x26, y26, outlineColor); + + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + + } +} + +int main(int argc, char* argv[]) { + int w = 0.9*Canvas::getDisplayHeight(); + int h = w; + Canvas c(-1, -1, w, h, "Constructors", WHITE); + c.run(constructorFunction); +} diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile new file mode 100644 index 000000000..642cd99a6 --- /dev/null +++ b/src/tests/testConvexPolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testConvexPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testConvexPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testConvexPolygon/testConvexPolygon.cpp b/src/tests/testConvexPolygon/testConvexPolygon.cpp new file mode 100644 index 000000000..43174f924 --- /dev/null +++ b/src/tests/testConvexPolygon/testConvexPolygon.cpp @@ -0,0 +1,57 @@ +/* + * testConvexPolygon.cpp + * + * Usage: ./testConvexPolygon + */ + +#include +#include + +using namespace tsgl; + +void convexPolygonFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { -50,-50, 0,25,50, 50, 25 }; + float y[] = { -50, 25,50,40,10,-10,-50 }; + ConvexPolygon * cp = new ConvexPolygon(0,0,0,7,x,y,0,0,0,colors); + // cp->setCenterX(2); + // cp->setRotationPoint(0,0,0); + can.add(cp); + float floatVal = 0.0f; + while (can.isOpen()) { + can.sleep(); + // cp->setCenterX(sin(floatVal/90) * 100); + // cp->setCenterY(sin(floatVal/90) * 100); + // cp->setCenterZ(sin(floatVal/90) * 100); + // cp->setYaw(floatVal); + // cp->setPitch(floatVal); + // cp->setRoll(floatVal); + // if (floatVal < 200) { + // cp->setColor(colors); + // } else { + // cp->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete cp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic ConvexPolygon", BLACK); + c.run(convexPolygonFunction); +} \ No newline at end of file diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile new file mode 100644 index 000000000..7190a88d7 --- /dev/null +++ b/src/tests/testCosineIntegral/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCosineIntegral + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCosineIntegral + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCosineIntegral/testCosineIntegral.cpp b/src/tests/testCosineIntegral/testCosineIntegral.cpp new file mode 100644 index 000000000..470c99be9 --- /dev/null +++ b/src/tests/testCosineIntegral/testCosineIntegral.cpp @@ -0,0 +1,84 @@ +/* + * testCosineIntegral.cpp + * + * Usage: ./testCosineIntegral + */ + +#include +#include +#include +#include +#include +#include "Util.h" //Constants + +using namespace tsgl; + +/*! + * \brief Draws the area under a predefined function (the integral) using CartesianCanvas + * and takes a command line argument for the number of threads to use. + * \details + * - Use the number of threads passed via command-line arguments. + * - If that number is negative, just use one thread. + * - Set up the internal timer of the Canvas to expire once every \b FRAME / 2 seconds . + * - Draw axes through the origin, with spacing PI/4 between x ticks and 0.5 between y ticks. + * - Store the width of the canvas's pixel in \b pw to avoid thousands of multiple function calls. + * - Initialize and draw a CosineFunction using the currently rendered area of the CartesianCanvas. + * - Set the CartesianCanvas' font from an external font file using setFont(). + * - Draw some labels on the CartesianCanvas to make things look pretty. + * - Set up a parallel block with OMP using \b threads as the number of threads to use. + * - Set \b nthreads to the actual number of threads spawned. + * - Calculate each thread's share of the work and store it in: \b offset. + * - Calculate each thread's starting position and store it in: \b start. + * - Calculate each thread's stopping position and store it in: \b stop. + * - For each thread, from \b start to \b stop with step size \b pw: + * - If the Canvas was closed, break. + * - Sleep the internal timer until it's ready to render. + * - Draw a line from x,0 to x,f(x) for the current x. + * . + * . + * \param can Reference to the CartesianCanvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void cosineIntegralFunction(Cart& can, int numberOfThreads) { + int threads = numberOfThreads; + if (threads <= 0) { + threads = 1; + } + + can.drawAxes(0, 0, PI/4, .5); + long double pw = can.getPixelWidth(); + CosineFunction function1; + can.drawFunction(function1); + + //\u03C0 = Ï€ + can.setFont("../assets/freefont/FreeSerif.ttf"); + can.drawText(L"-1.5\u03C0", -1.5 * PI - .1, .25, 20); // Note the important capital L, used to support Unicode. + can.drawText(L"1.5\u03C0", 1.5 * PI - .2, .25, 20); + can.drawText(L"1", .1, 1.05, 20); + can.drawText(L"-1", .1, -1.1, 20); + +#pragma omp parallel num_threads(threads) + { + threads = omp_get_num_threads(); + long double offset = 3*PI / threads; + long double start = -1.5*PI + omp_get_thread_num() * offset; + long double stop = start + offset; + for (long double i = start; i < stop; i += pw) { + if (!can.isOpen()) break; + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + can.drawLine(i, 0, i, function1.valueAt(i), Colors::highContrastColor(omp_get_thread_num())); + } + } +} + +//Takes in command line arguments for the width and height of the window +//as well as the number of threads to use +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads to use + Cart c(-1, -1, w, h, -5,-1.5,5,1.5, "Cosine Integral", WHITE, FRAME / 2); + c.run(cosineIntegralFunction,t); +} diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile new file mode 100644 index 000000000..9373a2ea4 --- /dev/null +++ b/src/tests/testCube/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCube + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCube + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCube/testCube.cpp b/src/tests/testCube/testCube.cpp new file mode 100644 index 000000000..30b640e4b --- /dev/null +++ b/src/tests/testCube/testCube.cpp @@ -0,0 +1,80 @@ +/* + * testCube.cpp + * + * Usage: ./testCube + */ + +#include +#include + +using namespace tsgl; + +void cubeFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cube * testCube = new Cube(0.0, 0.0, 0.0, 200, 0.0, 45.0, 45.0, RED); + Cube * testCube2 = new Cube(-300, 0.0, 0.0, 200, 0.0, 45.0, 45.0, colors); + can.add(testCube); + + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCube2->getAlpha()); + // testCube2->setColor(colors); + // printf("%f\n", testCube2->getAlpha()); + can.add(testCube2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&testCube, &boolean]() { + testCube->setIsOutlined(boolean); + boolean = !boolean; + }); + + bool ss = false; + while (can.isOpen()) { + can.sleep(); + // testCube->setCenterX(sin(rotation)*200); + // testCube->setCenterY(cos(rotation)*200); + // testCube->setCenterZ(sin(rotation)*100); + // testCube->setYaw(rotation*45); + testCube->setPitch(rotation*45); + // testCube->setRoll(rotation*45); + // testCube->setSideLength(cos(rotation) * 100 +101); + // if(testCube->getSideLength() >= 2) { + // delta = -5; + // } + // if(testCube->getSideLength() <= 5) { + // delta = 5; + // } + // testCube->changeSideLengthBy(delta); + //testCube2->setRoll(rotation); + // if (rotation*45 >= 360) { + // if (boolean) { + // testCube->setColor(RED); + // } else { + // testCube->setColor(colors); + // } + // boolean = !boolean; + // rotation = 0; + // } + if (can.getFrameNumber() > 50 && !ss) { + can.takeScreenShot(); + ss = true; + } + rotation+=0.01; + } + + delete testCube; + delete testCube2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cube", BLACK); + c.run(cubeFunction); +} \ No newline at end of file diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile new file mode 100644 index 000000000..4a5120ec3 --- /dev/null +++ b/src/tests/testCuboid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCuboid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCuboid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCuboid/testCuboid.cpp b/src/tests/testCuboid/testCuboid.cpp new file mode 100644 index 000000000..ac407e5e9 --- /dev/null +++ b/src/tests/testCuboid/testCuboid.cpp @@ -0,0 +1,85 @@ +/* + * testCuboid.cpp + * + * Usage: ./testCuboid + */ + +#include +#include + +using namespace tsgl; + +void cuboidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8) }; + Cuboid * testCuboid = new Cuboid(0.0, 0.0, 0.0, 100, 400, 200, 0.0, 45.0, 0.0, ColorFloat(1,0,0,1)); + Cuboid * testCuboid2 = new Cuboid(-300, 0.0, 0.0, 100, 400, 200, 0.0, 0.0, 0.0, colors); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testCuboid2->getAlpha()); + // testCuboid2->setColor(colors); + // printf("%f\n", testCuboid2->getAlpha()); + can.add(testCuboid); + can.add(testCuboid2); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false;; + while (can.isOpen()) { + can.sleep(); + // testCuboid->setCenterX(sin(rotation)*200); + // testCuboid->setCenterY(cos(rotation)*200); + // testCuboid->setCenterZ(sin(rotation)*100); + // testCuboid->setYaw(rotation*45); + testCuboid->setPitch(rotation*45); + // testCuboid->setRoll(rotation*45); + // testCuboid->setWidth(cos(rotation)*100+101); + // testCuboid->setHeight(cos(rotation)*100+301); + // testCuboid->setLength(cos(rotation)*100+201); + // if(testCuboid->getWidth() >= 200) { + // delta = -5; + // } + // if(testCuboid->getWidth() <= 5) { + // delta = 5; + // } + // testCuboid->changeWidthBy(delta); + + // if(testCuboid->getHeight() >= 500) { + // delta = -5; + // } + // if(testCuboid->getHeight() <= 300) { + // delta = 5; + // } + // testCuboid->changeHeightBy(delta); + + // if(testCuboid->getLength() >= 300) { + // delta = -5; + // } + // if(testCuboid->getLength() <= 100) { + // delta = 5; + // } + // testCuboid->changeLengthBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testCuboid->setColor(RED); + } else { + testCuboid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCuboid; + delete testCuboid2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cuboid", BLACK); + c.run(cuboidFunction); +} \ No newline at end of file diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile new file mode 100644 index 000000000..aff15ef0d --- /dev/null +++ b/src/tests/testCylinder/Makefile @@ -0,0 +1,63 @@ +# Makefile for testCylinder + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testCylinder + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testCylinder/testCylinder.cpp b/src/tests/testCylinder/testCylinder.cpp new file mode 100644 index 000000000..8df38a692 --- /dev/null +++ b/src/tests/testCylinder/testCylinder.cpp @@ -0,0 +1,75 @@ +/* + * testCylinder.cpp + * + * Usage: ./testCylinder + */ + +#include +#include + +using namespace tsgl; + +void cylinderFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); + can.add(testCylinder); + can.add(testCylinder2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCylinder->setCenterX(sin(rotation)*2); + // testCylinder->setCenterY(cos(rotation)*2); + // testCylinder->setCenterZ(sin(rotation)); + // testCylinder->setYaw(rotation*45); + testCylinder->setPitch(rotation*45); + // testCylinder->setRoll(rotation*45); + // testCylinder->setHeight(sin(rotation)+1.01); + // testCylinder->setRadius(sin(rotation)+1.01); + // if(testCylinder->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeHeightBy(delta); + // if(testCylinder->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testCylinder->setColor(RED); + } else { + testCylinder->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCylinder; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); + c.run(cylinderFunction); +} \ No newline at end of file diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile new file mode 100644 index 000000000..eef80cbac --- /dev/null +++ b/src/tests/testDice/Makefile @@ -0,0 +1,63 @@ +# Makefile for testDice + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDice + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDice/testDice.cpp b/src/tests/testDice/testDice.cpp new file mode 100644 index 000000000..5d674296b --- /dev/null +++ b/src/tests/testDice/testDice.cpp @@ -0,0 +1,179 @@ +/* + * testDice.cpp + * + * Usage: ./testDice + * Note: currently has some interesting rotation issues that mean that the + * API will probably have to be updated. Not compiling since it won't + * really work, alter the Makefile to understand the issue. Has to do with composite + * Euler angles. + */ + +#include +#include + +using namespace tsgl; + +void diceFunction(Canvas& can) { + Cube * die = new Cube(0.0, 0.0, 0.0, 2, 0.0, 0.0, 0.0, WHITE); + can.add(die); + + RegularPolygon * spot1 = new RegularPolygon(0,0,1.01,0.5,6,0,0,0,BLACK); + can.add(spot1); + spot1->setRotationPoint(0,0,0); + + + RegularPolygon * spot2_1 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_1->setRotationPoint(0,0,0); + can.add(spot2_1); + RegularPolygon * spot2_2 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,-90,BLACK); + spot2_2->setRotationPoint(0,0,0); + can.add(spot2_2); + + RegularPolygon * spot3_1 = new RegularPolygon(0,1.01,0,0.3,6,90,0,0,BLACK); + spot3_1->setRotationPoint(0,0,0); + can.add(spot3_1); + RegularPolygon * spot3_2 = new RegularPolygon(0.6,1.01,0.6,0.3,6,90,0,0,BLACK); + spot3_2->setRotationPoint(0,0,0); + can.add(spot3_2); + RegularPolygon * spot3_3 = new RegularPolygon(-0.6,1.01,-0.6,0.3,6,90,0,0,BLACK); + spot3_3->setRotationPoint(0,0,0); + can.add(spot3_3); + + // RegularPolygon * spot4_1 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_1->setRotationPoint(0,0,0); + // can.add(spot4_1); + // RegularPolygon * spot4_2 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_2->setRotationPoint(0,0,0); + // can.add(spot4_2); + // RegularPolygon * spot4_3 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_3->setRotationPoint(0,0,0); + // can.add(spot4_3); + // RegularPolygon * spot4_4 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,90,0,BLACK); + // spot4_4->setRotationPoint(0,0,0); + // can.add(spot4_4); + + RegularPolygon * spot5_1 = new RegularPolygon(0,0,1.01,0.3,6,0,0,90,BLACK); + spot5_1->setRotationPoint(0,0,0); + can.add(spot5_1); + RegularPolygon * spot5_2 = new RegularPolygon(0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_2->setRotationPoint(0,0,0); + can.add(spot5_2); + RegularPolygon * spot5_3 = new RegularPolygon(-0.6,0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_3->setRotationPoint(0,0,0); + can.add(spot5_3); + RegularPolygon * spot5_4 = new RegularPolygon(0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_4->setRotationPoint(0,0,0); + can.add(spot5_4); + RegularPolygon * spot5_5 = new RegularPolygon(-0.6,-0.6,1.01,0.3,6,0,0,90,BLACK); + spot5_5->setRotationPoint(0,0,0); + can.add(spot5_5); + + RegularPolygon * spot6_1 = new RegularPolygon(-0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_1); + RegularPolygon * spot6_2 = new RegularPolygon(-0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_2); + RegularPolygon * spot6_3 = new RegularPolygon(-0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_3); + RegularPolygon * spot6_4 = new RegularPolygon(0.5,0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_4); + RegularPolygon * spot6_5 = new RegularPolygon(0.5,0,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_5); + RegularPolygon * spot6_6 = new RegularPolygon(0.5,-0.65,1.01,0.3,6,0,0,180,BLACK); + can.add(spot6_6); + spot6_1->setRotationPoint(0,0,0); + spot6_2->setRotationPoint(0,0,0); + spot6_3->setRotationPoint(0,0,0); + spot6_4->setRotationPoint(0,0,0); + spot6_5->setRotationPoint(0,0,0); + spot6_6->setRotationPoint(0,0,0); + + // die->setRoll(45); + // spot1->setRoll(45); + // spot2_1->setRoll(45-90); + // spot2_2->setRoll(45-90); + // spot3_1->setRoll(180); + // spot3_2->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot3_3->setRoll(180); + // spot4_1->setRoll(45); + // spot4_2->setRoll(45); + // spot4_3->setRoll(45); + // spot4_4->setRoll(45); + // spot5_1->setRoll(45+90); + // spot5_2->setRoll(45+90); + // spot5_3->setRoll(45+90); + // spot5_4->setRoll(45+90); + // spot5_5->setRoll(45+90); + // spot6_1->setRoll(45+180); + // spot6_2->setRoll(45+180); + // spot6_3->setRoll(45+180); + // spot6_4->setRoll(45+180); + // spot6_5->setRoll(45+180); + // spot6_6->setRoll(45+180); + + float rotation = 0; + while (can.isOpen()) { + can.sleep(); + // die->setRoll(rotation); + // spot1->setRoll(rotation); + // spot2_1->setRoll(rotation-90); + // spot2_2->setRoll(rotation-90); + // spot3_1->setPitch(rotation); + // spot3_2->setPitch(rotation); + // spot3_3->setPitch(rotation); + // spot4_1->setRoll(rotation); + // spot4_2->setRoll(rotation); + // spot4_3->setRoll(rotation); + // spot4_4->setRoll(rotation); + // spot5_1->setRoll(rotation+90); + // spot5_2->setRoll(rotation+90); + // spot5_3->setRoll(rotation+90); + // spot5_4->setRoll(rotation+90); + // spot5_5->setRoll(rotation+90); + // spot6_1->setRoll(rotation+180); + // spot6_2->setRoll(rotation+180); + // spot6_3->setRoll(rotation+180); + // spot6_4->setRoll(rotation+180); + // spot6_5->setRoll(rotation+180); + // spot6_6->setRoll(rotation+180); + + die->setPitch(rotation); + spot1->setPitch(rotation); + spot2_1->setPitch(rotation); + spot2_2->setPitch(rotation); + spot3_1->setPitch(rotation-90); + spot3_2->setPitch(rotation-90); + spot3_3->setPitch(rotation-90); + // spot4_1->setPitch(rotation+90); + // spot4_2->setPitch(rotation+90); + // spot4_3->setPitch(rotation+90); + // spot4_4->setPitch(rotation+90); + spot5_1->setPitch(rotation); + spot5_2->setPitch(rotation); + spot5_3->setPitch(rotation); + spot5_4->setPitch(rotation); + spot5_5->setPitch(rotation); + spot6_1->setPitch(rotation); + spot6_2->setPitch(rotation); + spot6_3->setPitch(rotation); + spot6_4->setPitch(rotation); + spot6_5->setPitch(rotation); + spot6_6->setPitch(rotation); + rotation += 1; + } + + delete die; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Dice Rolling"); + c.run(diceFunction); +} \ No newline at end of file diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile new file mode 100644 index 000000000..1b880fb14 --- /dev/null +++ b/src/tests/testDiorama/Makefile @@ -0,0 +1,63 @@ +# Makefile for testDiorama + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testDiorama + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testDiorama/testDiorama.cpp b/src/tests/testDiorama/testDiorama.cpp new file mode 100644 index 000000000..82214f2f6 --- /dev/null +++ b/src/tests/testDiorama/testDiorama.cpp @@ -0,0 +1,118 @@ +/* + * testDiorama.cpp + * + * Usage: ./testDiorama + */ + +#include +#include + +using namespace tsgl; + +void dioramaFunction(Canvas& can) { + Square * blankCanvas = new Square(180,0,135,270,0,0,0,WHITE); + // can.add(blankCanvas); + + Rectangle * emptyDioramaLeft = new Rectangle(-45,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaLeft); + Rectangle * emptyDioramaRight = new Rectangle(-315,0,0,270,270,0,90,0,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaRight); + Rectangle * emptyDioramaTop = new Rectangle(-180,135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaTop); + Rectangle * emptyDioramaBottom = new Rectangle(-180,-135,0,270,270,0,0,90,ColorFloat(1,1,1,0)); + // can.add(emptyDioramaBottom); + + Cuboid * trunk = new Cuboid(-200,-30,0,25,200,25,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunk); + + Ellipsoid * leaves = new Ellipsoid(-200,70,0,75,50,40,0,0,0,GREEN); + // can.add(leaves); + + Rectangle * trunkFlat = new Rectangle(160,-30,135,25,200,0,0,0,ColorFloat(.6,.3,0,1)); + // can.add(trunkFlat); + + Ellipse * leavesFlat = new Ellipse(160,70,135,75,50,0,0,0,ColorFloat(0,0.8,0,1)); + // can.add(leavesFlat); + + float counter = 0; + while (can.isOpen()) { + // can.sleepFor(0.5); + can.sleep(); + if (can.getFrameNumber() > 700 && counter < 1) { + can.add(blankCanvas); + counter++; + } + if(can.getFrameNumber() > 1700 && counter < 2) { + can.add(trunkFlat); + counter++; + } + if(can.getFrameNumber() > 1800 && counter < 3) { + can.add(leavesFlat); + counter++; + } + if(can.getFrameNumber() > 2300 && counter < 4) { + can.add(emptyDioramaLeft); + can.add(emptyDioramaRight); + can.add(emptyDioramaTop); + can.add(emptyDioramaBottom); + counter++; + } + if(can.getFrameNumber() > 3500 && counter < 5) { + can.add(trunk); + counter++; + } + if(can.getFrameNumber() > 3600 && counter < 6) { + can.add(leaves); + counter++; + } + if(can.getFrameNumber() > 4000 && counter < 7) { + if(emptyDioramaLeft->getWidth() > 15) { + emptyDioramaLeft->changeWidthBy(-270/20); + emptyDioramaRight->changeWidthBy(-270/20); + emptyDioramaTop->changeHeightBy(-270/20); + emptyDioramaBottom->changeHeightBy(-270/20); + emptyDioramaTop->changeZBy(135/20); + emptyDioramaBottom->changeZBy(135/20); + emptyDioramaLeft->changeZBy(135/20); + emptyDioramaRight->changeZBy(135/20); + trunk->changeLengthBy(-25/20); + trunk->changeZBy(135/20); + leaves->changeZRadiusBy(-40/20); + leaves->changeZBy(135/20); + } else { + emptyDioramaLeft->setWidth(1); + emptyDioramaRight->setWidth(1); + emptyDioramaTop->setHeight(1); + emptyDioramaBottom->setHeight(1); + emptyDioramaTop->setCenterZ(135); + emptyDioramaBottom->setCenterZ(135); + emptyDioramaLeft->setCenterZ(135); + emptyDioramaRight->setCenterZ(135); + trunk->setLength(1); + trunk->setCenterZ(135); + leaves->setZRadius(1); + leaves->setCenterZ(135); + counter++; + } + } + } + + delete blankCanvas; + delete emptyDioramaLeft; + delete emptyDioramaRight; + delete emptyDioramaTop; + delete emptyDioramaBottom; + delete leaves; + delete trunkFlat; + delete leavesFlat; + +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Diorama vs. Painting", WHITE); + c.run(dioramaFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile new file mode 100644 index 000000000..1e88f9d23 --- /dev/null +++ b/src/tests/testEllipse/Makefile @@ -0,0 +1,63 @@ +# Makefile for testEllipse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipse/testEllipse.cpp b/src/tests/testEllipse/testEllipse.cpp new file mode 100644 index 000000000..dacee93d4 --- /dev/null +++ b/src/tests/testEllipse/testEllipse.cpp @@ -0,0 +1,71 @@ +/* + * testEllipse.cpp + * + * Usage: ./testEllipse + */ + +#include +#include + +using namespace tsgl; + +void ellipseFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipse * ellipse = new Ellipse(0,0,0,100,200,0,0,0,colors); + // ellipse->setCenterX(200); + // ellipse->setRotationPoint(0,0,0); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", ellipse->getAlpha()); + // ellipse->setColor(colors); + // printf("%f\n", ellipse->getAlpha()); + can.add(ellipse); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // ellipse->setCenterX(sin(floatVal/90) * 100); + // ellipse->setCenterY(sin(floatVal/90) * 100); + // ellipse->setCenterZ(sin(floatVal/90) * 100); + // ellipse->setYaw(floatVal); + // ellipse->setPitch(floatVal); + // ellipse->setRoll(floatVal); + // ellipse->setXRadius(sin(floatVal/90) * 100 + 100); + // ellipse->setYRadius(sin(floatVal/90) * 100 + 200); + // if (ellipse->getXRadius() > 300 || ellipse->getXRadius() < 100) { + // delta *= -1; + // } + // ellipse->changeXRadiusBy(delta); + if (ellipse->getYRadius() > 300 || ellipse->getYRadius() < 100) { + delta *= -1; + } + ellipse->changeYRadiusBy(delta); + if (delta > 0) { + ellipse->setColor(colors); + } else { + ellipse->setColor(RED); + } + floatVal += 1; + } + + delete ellipse; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipse", BLACK); + c.run(ellipseFunction); +} \ No newline at end of file diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile new file mode 100644 index 000000000..2b2ce5104 --- /dev/null +++ b/src/tests/testEllipsoid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testEllipsoid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testEllipsoid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testEllipsoid/testEllipsoid.cpp b/src/tests/testEllipsoid/testEllipsoid.cpp new file mode 100644 index 000000000..69d279ebb --- /dev/null +++ b/src/tests/testEllipsoid/testEllipsoid.cpp @@ -0,0 +1,112 @@ +/* + * testEllipsoid.cpp + * + * Usage: ./testEllipsoid + */ + +#include +#include + +using namespace tsgl; + +void ellipsoidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Ellipsoid * testEllipsoid = new Ellipsoid(200.0, 0.0, 0.0, 200, 200, 200, 0.0, 0.0, 0.0, colors); + // testEllipsoid->setIsFilled(false); + Ellipsoid * testEllipsoid2 = new Ellipsoid(-200, 0.0, 0.0, 150, 200, 100, 0.0, 0.0, 0.0, RED); + testEllipsoid2->setOutlineColor(BLUE); + + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testEllipsoid->getAlpha()); + // testEllipsoid->setColor(colors); + // printf("%f\n", testEllipsoid->getAlpha()); + can.add(testEllipsoid); + can.add(testEllipsoid2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = true; + bool b2 = true; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&testEllipsoid, &testEllipsoid2, &b2]() { + testEllipsoid->setIsOutlined(b2); + testEllipsoid2->setIsOutlined(b2); + b2 = !b2; + }); + + // testEllipsoid->setXRadius(150); + // testEllipsoid->setYRadius(150); + // testEllipsoid->setZRadius(150); + // testEllipsoid->changeXRadiusBy(140); + // testEllipsoid->changeYRadiusBy(140); + // testEllipsoid->changeZRadiusBy(140); + while (can.isOpen()) { + can.sleep(); + // testEllipsoid->setCenterX(sin(rotation)); + // testEllipsoid->setCenterY(cos(rotation)); + // testEllipsoid->setCenterZ(sin(rotation)); + // testEllipsoid->setYaw(rotation*45); + testEllipsoid->setPitch(rotation*45); + testEllipsoid2->setPitch(rotation*45); + // if(boolean) + // testEllipsoid->setRoll(rotation*45); + // testEllipsoid->setXRadius(cos(rotation) * 100 +101); + // testEllipsoid->setYRadius(sin(rotation) * 100 +201); + // testEllipsoid->setZRadius(sin(rotation) * 100 +301); + // if(testEllipsoid->getXRadius() >= 200) { + // delta = -5; + // } + // if(testEllipsoid->getXRadius() <= 5) { + // delta = 5; + // } + // testEllipsoid->changeXRadiusBy(delta); + + // if(testEllipsoid->getYRadius() >= 500) { + // delta = -5; + // } + // if(testEllipsoid->getYRadius() <= 300) { + // delta = 5; + // } + // testEllipsoid->changeYRadiusBy(delta); + + // if(testEllipsoid->getZRadius() >= 300) { + // delta = -5; + // } + // if(testEllipsoid->getZRadius() <= 100) { + // delta = 5; + // } + // testEllipsoid->changeZRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testEllipsoid->setColor(RED); + } else { + testEllipsoid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testEllipsoid; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Ellipsoid", BLACK); + c.run(ellipsoidFunction); +} \ No newline at end of file diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile new file mode 100644 index 000000000..94991da39 --- /dev/null +++ b/src/tests/testFunction/Makefile @@ -0,0 +1,63 @@ +# Makefile for testFunction + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testFunction + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testFunction/testFunction.cpp b/src/tests/testFunction/testFunction.cpp new file mode 100644 index 000000000..a3511f8e6 --- /dev/null +++ b/src/tests/testFunction/testFunction.cpp @@ -0,0 +1,51 @@ +/* + * testFunction.cpp + * + * Usage: ./testFunction + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws the outputs of some functions using CartesianCanvas. + * \details + * - Draw axes through the origin, with spacing 1.0 between x ticks and 5.0 between y ticks. + * - Initialize a CosineFunction, and draw it using the currently rendered area of the CartesianCanvas. + * - Initialize a PowerFunction with argument 2 (square), and draw it using + * the currently rendered area of the CartesianCanvas. + * - Declare a new function that computes some bizarre polynomial. + * - Initialize the new function, and draw it using the currently rendered area of the CartesianCanvas. + * . + * \param can Reference to the CartesianCanvas being drawn to. + */ +void functionFunction(CartesianCanvas& can) { + can.drawAxes(0, 0, 1, 5); + + CosineFunction function1; + can.drawFunction(function1,FRAME/5); + + PowerFunction function2(2); + can.drawFunction(function2,FRAME/5); + + class myFunction : public Function { + public: + long double valueAt(long double x) const { + return 5 * pow(x, 4) + 2 * pow(x, 3) + x + 15; + } + }; + + myFunction function3; + can.drawFunction(function3,FRAME/5); +} + +//Takes command line arguments for the window width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 1000; //If not, set the width and height to a default value + Cart c(-1, -1, w, h, -5,-5,5,50, "Function Plotting", WHITE); + c.run(functionFunction); +} diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile new file mode 100644 index 000000000..072c3514f --- /dev/null +++ b/src/tests/testGetPixels/Makefile @@ -0,0 +1,63 @@ +# Makefile for testAlphaRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testAlphaRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGetPixels/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp new file mode 100644 index 000000000..a3b2e55e9 --- /dev/null +++ b/src/tests/testGetPixels/testGetPixels.cpp @@ -0,0 +1,62 @@ +/* + * testGetPixels.cpp + * + * Usage: ./testGetPixels + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Grabs the pixels from an image on the Canvas and plays with them. + * \details + * - Set a predetermined number of threads and store it in: \b THREADS. + * - Store the Canvas' dimensions for easy use. + * - Draw an image on the initially blank Canvas, stretched to fill it. + * - Set up a parallel OMP block with \b THREADS threads. + * - Set up the internal timer of the Canvas to expire every 1/100th of a second. + * - Determine a block size for each thread based on the Canvas' height and the number + * of spawned threads. + * - Determine a starting row for each thread based on \b blocksize and the thread's id. + * - While the Canvas is open: + * - For each row: + * - For each column: + * - Over each old pixel, draw a new pixel with each of the RGB components incremented + * and wrapped. + * . + * . + * - Sleep until the Canvas is ready to draw again. + * - Print the time between sleeps of the Canvas' internal timer. + * . + * . + * + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void getPixelsFunction(Canvas& can, int threads) { + unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); + can.drawImage("../assets/pics/test.png", 0, 0, width, height); + can.sleepFor(0.5f); + #pragma omp parallel num_threads(threads) + { + unsigned blocksize = (double)height / omp_get_num_threads(); + unsigned row = blocksize * omp_get_thread_num(); + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (unsigned y = row; y < row + blocksize; y++) { + for (unsigned x = 0; x < width; x++) { + ColorInt c = can.getPoint(x,y); + can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); + } + } + } + } +} + +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + Canvas c(-1, -1, 800, 600, "Pixel Shifter", .01); + c.run(getPixelsFunction,t); +} diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile new file mode 100644 index 000000000..cdc77e86f --- /dev/null +++ b/src/tests/testGradientWheel/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGradientWheel + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGradientWheel + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGradientWheel/testGradientWheel.cpp b/src/tests/testGradientWheel/testGradientWheel.cpp new file mode 100644 index 000000000..9e590ab01 --- /dev/null +++ b/src/tests/testGradientWheel/testGradientWheel.cpp @@ -0,0 +1,65 @@ +/* + * testGradientWheel.cpp + * + * Usage: ./testGradientWheel + */ + +#include +#include +#include "Util.h" + +using namespace tsgl; + +/*! + * \brief Draws a gradient color wheel using OMP with multiple threads per processor and TSGL's colored polygons. + * \details Same principle as colorWheelFunction(). Since colored polygons take arrays as parameters + * to allow for arbitrary-length polygons, there are some key differences: + * - Colors, x and y coordinates are declared within the \#pragma omp block so they can be + * declared as an array. + * - At the end, drawColoredPolygon() is called on a polygon with 3 vertices, with arrays for the + * x coordinates, y coordinates, and color. + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void gradientWheelFunction(Canvas& can, int threads) { + const int CW = can.getWindowWidth() / 2, // Half the window's width + CH = can.getWindowHeight() / 2; // Half the window's height + const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel + ARCLENGTH = 2 * PI / NUM_COLORS; // Gap between wedges + #pragma omp parallel num_threads(threads) + { + threads = omp_get_num_threads(); // Actual number of threads + int tid = omp_get_thread_num(); // Thread ID + int delta = (NUM_COLORS / threads); // Distance between threads to compute + float shading = 1 - (float)tid / threads; // Shading based on thread ID + ColorFloat color[3]; // RGB color to build + int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices + while (can.isOpen()) { + can.sleep(); + start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment + end = ((start+delta) % NUM_COLORS); + color[0] = ColorHSV(start / (float)NUM_COLORS * 6, 0.0f, shading, 1.0f); + color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); + color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); + + xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen + xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle + yy[1] = CH + RADIUS * cos(ARCLENGTH * start); + xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); + yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); + + can.drawTriangleStrip(3, xx, yy, color, true); + } + } +} + +//Takes command line arguments for the width and height of the window +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid + w = h = 960; // If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : 256; + Canvas c(-1, -1, w, h, "Gradient Color Wheel", BLACK); + c.run(gradientWheelFunction,t); +} diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile new file mode 100644 index 000000000..72b5e97cf --- /dev/null +++ b/src/tests/testGraydient/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGraydient + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGraydient + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGraydient/testGraydient.cpp b/src/tests/testGraydient/testGraydient.cpp new file mode 100644 index 000000000..4d3a2af77 --- /dev/null +++ b/src/tests/testGraydient/testGraydient.cpp @@ -0,0 +1,52 @@ +/* + * testGraydient.cpp + * + * Usage: ./testGraydient + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command-line argument for the + * number of threads to use. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed as a command-line argument. + * - The outer for loop is set up in a striping pattern, and the inner for loop runs from 0 to the Canvas height. + * - If the Canvas is not open anymore, break out of the function. + * - The color ( \b color ) is set to a shade of gray based on its distance from the top left of the canvas. + * - The point is drawn to the Canvas. + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void graydientFunction(Canvas& can, int threads) { + #pragma omp parallel num_threads(threads) + { + for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { + if (!can.isOpen()) break; + for (int j = 0; j < can.getWindowHeight(); j++) { + int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); + can.drawPoint(i, j, ColorInt(color, color, color)); + } + can.sleep(); + } + } +} + +//Takes in the window width and height as command-line arguments for the Canvas +//as well as for the number of threads to use +//( see http://www.cplusplus.com/articles/DEN36Up4/ ) +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) // Checked the passed width and height if they are valid + w = h = 960; // If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Black-white Gradient"); + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + c.run(graydientFunction,t); +} diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile new file mode 100644 index 000000000..6ef2c993b --- /dev/null +++ b/src/tests/testGreyscale/Makefile @@ -0,0 +1,63 @@ +# Makefile for testGreyscale + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testGreyscale + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testGreyscale/testGreyscale.cpp b/src/tests/testGreyscale/testGreyscale.cpp new file mode 100644 index 000000000..f62b7cfbc --- /dev/null +++ b/src/tests/testGreyscale/testGreyscale.cpp @@ -0,0 +1,86 @@ +/* + * testGreyScale.cpp + * + * Usage: ./testGreyScale + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Grabs the pixels from an image on the Canvas and converts them to grayscale. + * \details + * - Predetermine the number of threads and line thickness and store them in variables. + * - Check if the passed parameter for the number of threads is valid: + * - If its a negative value, change the sign to be positive. + * - If its greater than 30, assign 30 to the number of threads to use. + * - Else, assign the passed parameter to the number of threads to use. + * . + * - Set up the internal timer of the Canvas to expire every ( \b FRAME * 2 ) seconds. + * - Store the Canvas' dimensions for ease of use. + * - Stretch a fancy image over the Canvas. + * - Tell the internal timer to manually sleep for a quarter of a second (to assure the draw buffer is filled). + * - Initialize a pointer to the Canvas' screen buffer. + * - Set up a parallel OMP block with \b threads threads. + * - Get the actual number of spawned threads and store it in: \b nthreads. + * - Compute the \b blocksize based on the Canvas height and \b nthreads. + * - Compute the current thread's row based on \b blocksize and the thread's id. + * - Generate a nice color based on the thread's id. + * - Set a grayscale color variable to 0. + * - For each row: + * - For each column: + * - Get the pixel color of a point of the Canvas. + * - Set a gray color variable to the average of the RGB components. + * - Draw the grayed point over the old point, and increment the index by one pixel. + * . + * - Break if the Canvas was closed. + * - Sleep until the Canvas is ready to render again. + * . + * - Once a thread is finished grayscaling, draw a box around its rendered area using + * the predetermined high contrast color. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void greyScaleFunction(Canvas& can, int numberOfThreads) { + int threads = numberOfThreads; + clamp(threads,1,30); + const unsigned thickness = 3; + const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); + can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); + can.sleepFor(0.25f); + #pragma omp parallel num_threads(threads) + { + int nthreads = omp_get_num_threads(); + unsigned int blocksize = WH / nthreads; + unsigned int row = blocksize * omp_get_thread_num(); + ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); + for (unsigned int y = row; y < row + blocksize; y++) { + for (unsigned int x = 0; x < WW; x++) { + ColorInt pixelColor = can.getPoint(x, y); + int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; + can.drawPoint(x, y, ColorInt(gray, gray, gray)); + } + if (! can.isOpen()) break; + can.sleep(); + } + for (unsigned int i = 0; i < thickness; i++) { + can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); + // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); + } + } +} + +//Takes command line arguments for the width and height of the window +//as well as for the number of threads to use +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, w, h, "Image Greyscaling"); + int numberOfThreads = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Number of threads + c.run(greyScaleFunction,numberOfThreads); +} diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile new file mode 100644 index 000000000..cc93c6633 --- /dev/null +++ b/src/tests/testHighData/Makefile @@ -0,0 +1,63 @@ +# Makefile for testHighData + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testHighData + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testHighData/testHighData.cpp b/src/tests/testHighData/testHighData.cpp new file mode 100644 index 000000000..43ce27f05 --- /dev/null +++ b/src/tests/testHighData/testHighData.cpp @@ -0,0 +1,54 @@ +/* + * testHighData.cpp + * + * Usage: ./testHighData + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a large number of pixels on a Canvas at a high framerate. + * \details Very basic stress test for the Canvas' drawPoint() function. + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - Set Local variables to track the internal timer's repetitions, and the Canvas' dimensions. + * - While the Canvas is open: + * - Set \b reps to the timer's current number of repetitions. + * - Compute the blue component of the current color based on reps. + * - Attempt to draw every pixel with the current 1.0,1.0,blue. + * - Sleep the timer until the Canvas is ready to draw again. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void highData(Canvas& can, unsigned threads) { + const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values + const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); + #pragma omp parallel num_threads(threads) + { + float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); + int offset = (MAX_COLOR*tid)/nthreads; + unsigned bstart = tid*(width/nthreads); + unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; + ColorHSV tcol= Colors::highContrastColor(tid); + while (can.isOpen()) { + tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); + for (unsigned i = bstart; i <= bend; i++) + for (unsigned int j = 0; j < height; j++) + can.drawPoint(i, j, tcol); + can.handleIO(); + } + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = 1.2*Canvas::getDisplayHeight(), h = 0.75*w; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Pixel Drawing Load Test"); + c.run(highData,t); +} diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile new file mode 100644 index 000000000..9a4b4e9de --- /dev/null +++ b/src/tests/testImage/Makefile @@ -0,0 +1,63 @@ +# Makefile for testImage + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImage + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImage/testImage.cpp b/src/tests/testImage/testImage.cpp new file mode 100644 index 000000000..3de6187c7 --- /dev/null +++ b/src/tests/testImage/testImage.cpp @@ -0,0 +1,101 @@ +/* + * testImage.cpp + * + * Usage: ./testImage + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a Canvas. + * \details Very basic test function showcasing image drawing capabilities. + * - The first 6 images are drawn opaque. + * - The 7th image is drawn across the entire Canvas with alpha transparency. + * . + * \param can Reference to the Canvas being drawn to. + */ +void imageFunction(Canvas& can) { + int ww = can.getWindowWidth()/3, hh = can.getWindowHeight()/2; + // Square * s = new Square(5,0,0,50,0,0,0,RED); + // can.add(s); + + // Pyramid * p = new Pyramid(-5,0,0,5,100,50,0,0,0,BLUE); + // can.add(p); + + // Image * image = new Image(0,0,0,"./assets/pics/Messier51.jpg", 4,3, 0,0,0); + // can.add(image); + + Image * image = new Image(-ww,0.5 * hh,0,"./assets/pics/ball.png", ww,hh, 0,0,0); + can.add(image); + Image * image2 = new Image(0,0.5 * hh,0,"./assets/pics/ship.bmp", ww,hh, 0,0,0); + can.add(image2); + Image * image3 = new Image(ww,0.5 * hh,0,"./assets/pics/shiprgb.bmp", ww,hh, 0,0,0); + can.add(image3); + Image * image4 = new Image(-ww,-0.5 * hh,0,"./assets/pics/sky_main.jpg", ww,hh, 0,0,0); + can.add(image4); + Image * image5 = new Image(0,-0.5 * hh,0,"./assets/pics/colorfulKeyboard.jpg", ww,hh, 0,0,0); + can.add(image5); + Image * image6 = new Image(ww,-0.5 * hh,0,"./assets/pics/cow.jpg", ww,hh, 0,0,0); + can.add(image6); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&image6]() { + image6->changeFile("./assets/pics/colorfulKeyboard.jpg"); + }); + + // image->setHeight((GLfloat)image->getPixelHeight()); + // image->setWidth((GLfloat)image->getPixelWidth()); + + float floatVal = 0.0f; + GLfloat delta = 5; + bool ss = false; + while (can.isOpen()) { + can.sleep(); + image->setAlpha((sin(floatVal) + 1) / 2); + // image->setCenterX(sin(floatVal/90) * 100); + // image->setCenterY(sin(floatVal/90) * 100); + // image->setCenterZ(sin(floatVal/90) * 100); + // image->setYaw(floatVal); + image->setPitch(floatVal * 100); + // image->setRoll(floatVal); + // image->setWidth(sin(floatVal/90) * 100 + 400); + // image->setHeight(sin(floatVal/90) * 100 + 400); + // if (image->getWidth() > 500 || image->getWidth() < 300) { + // delta *= -1; + // } + // image->changeWidthBy(delta); + // if (image->getHeight() > 500 || image->getHeight() < 300) { + // delta *= -1; + // } + // image->changeHeightBy(delta); + // printf("%d\n", can.getFrameNumber()); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // ColorInt point = can.getPoint(can.getWindowWidth()/2,can.getWindowHeight()/2); + // printf("%d, %d, %d, %d\n", point.R, point.G, point.B, point.A); + floatVal += 0.01; + } + + // can.drawImage("../assets/pics/background.jpg", ww/2, 0, ww*2, hh*2, 0.25f); //Overlay + + delete image; + delete image2; + delete image3; + delete image4; + delete image5; + delete image6; +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2*Canvas::getDisplayHeight(); h = 0.5*w; + } + Canvas c(-1, -1, w, h ,"Images", WHITE); + c.run(imageFunction); +} diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile new file mode 100644 index 000000000..eddf3e4c3 --- /dev/null +++ b/src/tests/testImageCart/Makefile @@ -0,0 +1,63 @@ +# Makefile for testImageCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testImageCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testImageCart/testImageCart.cpp b/src/tests/testImageCart/testImageCart.cpp new file mode 100644 index 000000000..a7e4aead0 --- /dev/null +++ b/src/tests/testImageCart/testImageCart.cpp @@ -0,0 +1,37 @@ +/* + * testImageCart.cpp + * + * Usage: ./testImageCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws various images on a CartesianCanvas. + * \details Same as imageFunction, but on a CartesianCanvas. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + */ +void imageCartFunction(Cart& can) { + can.drawImage("../assets/pics/test.png", 0, 3, 2, 1.5); + can.drawImage("../assets/pics/ship.bmp", 2, 3, 2, 1.5); // possibly lost + can.drawImage("../assets/pics/shiprgb.bmp", 4, 3, 2, 1.5); // definitely lost + can.drawImage("../assets/pics/sky_main.jpg", 0, 1.5, 2, 1.5); + can.drawImage("../assets/pics/cow.jpg", 2, 1.5, 2, 1.5); + can.drawImage("../assets/pics/colorfulKeyboard.jpg", 4, 1.5, 2, 1.5); + + can.drawImage("../assets/pics/colorful-cars-circle.jpg", 1, 3, 4, 3, 0.25f); //Overlay +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.5*w; + if(w <= 0 || h <= 0) { //Check width and height validity + w = 1.2 * Canvas::getDisplayHeight(); + h = 0.5 * w; + } + Cart c(-1, -1, w, h, 0, 0, 6, 3, "Cartesian Images"); + c.run(imageCartFunction); +} diff --git a/src/tests/testInverter/ImageInverter.cpp b/src/tests/testInverter/ImageInverter.cpp new file mode 100644 index 000000000..f559065b1 --- /dev/null +++ b/src/tests/testInverter/ImageInverter.cpp @@ -0,0 +1,56 @@ +/* + * ImageInverter.cpp + */ + +#include "ImageInverter.h" + +ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsigned height) + : myCanvas1(0, 0, width, height, fileName), + myCanvas2(-1, -1, width, height, fileName), + myWidth(width), myHeight(height), myFileName(fileName) +{ + myCanvas1.start(); + myCanvas1.drawImage(fileName, 0, 0, width, height); + // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); + sleep(1); + myCanvas2.start(); +} + +void ImageInverter::run(unsigned numThreads) { + invertImage(numThreads); + stop(); +} + +void ImageInverter::invertImage(unsigned numThreads) { + ColorInt pixelColor; + // #pragma omp parallel for num_threads(numThreads) + const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); + #pragma omp parallel num_threads(numThreads) + { + int nthreads = omp_get_num_threads(); + unsigned int blocksize = WH / nthreads; + unsigned int row = blocksize * omp_get_thread_num(); + for (unsigned int x = row; x < row + blocksize; x++) { + for (unsigned int y = 0; y < WW; y++) { + pixelColor = myCanvas1.getPixel(x, y); + int invertedR = 255 - pixelColor.R; + int invertedG = 255 - pixelColor.G; + int invertedB = 255 - pixelColor.B; + myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); + } + myCanvas1.sleep(); + myCanvas2.sleep(); + } + } +} + +void ImageInverter::stop() { + myCanvas2.wait(); + myCanvas1.wait(); +} + +ImageInverter::~ImageInverter() { +// delete myCanvas1; +// delete myCanvas2; +// std::cout << "ImageInverter terminated normally.\n" << std::endl; +} diff --git a/src/tests/testInverter/ImageInverter.h b/src/tests/testInverter/ImageInverter.h new file mode 100644 index 000000000..6906b31b6 --- /dev/null +++ b/src/tests/testInverter/ImageInverter.h @@ -0,0 +1,79 @@ +/* + * ImageInverter.h declares the ImageInverter class. + */ + +#ifndef IMAGEINVERTER_H_ +#define IMAGEINVERTER_H_ + +#include // Canvas, ColorInt, etc. +#include + +#ifdef _WIN32 + #include +#else + #include // sleep() +#endif + +using namespace tsgl; + +class ImageInverter { +private: + Canvas myCanvas1; + Canvas myCanvas2; + int myWidth; + int myHeight; + std::string myFileName; + #ifdef _WIN32 + void sleep(unsigned seconds) { Sleep(seconds * 1000); } + #endif +protected: + + /* invertImage inverts the image using a given number of threads + * @param: numThreads, the number of threads to use + * when inverting the image (default 1). + * Postcondition: myCanvas2 contains an image that is the + * inverse of the image in myCanvas1. + */ + virtual void invertImage(unsigned numThreads = 1); + + /* helper method to keep Canvases up until the user + * clicks their window-frame's close button. + * + * Postcondition: myCanvas1 and myCanvas2 have been closed. + */ + virtual void stop(); + +public: + + /* explicit constructor + * @param fileName, a string. + * @param width, an unsigned. + * @param height, an unsigned. + * Precondition: fileName contains the name of a valid image file + * && width contains the number of columns in that image + * && height contains the number of rows in the image. + * Postcondition: myCanvas1 contains the image from fileName + * && myCanvas2 is ready for drawing its inverse + * && myWidth = width + * && myHeight = height. + */ + ImageInverter(const std::string& fileName, unsigned width, unsigned height); + + /* destructor + * Postcondition: myCanvas1 and myCanvas2 have been closed + * && myCanvas1 and myCanvas2 have been deallocated + * && glfwTerminate() has shut down GLFW + * && a termination message was written to the console. + */ + virtual ~ImageInverter(); + + /* method to coordinate the image inversion + * @param: numThreads, the number of threads to use + * when inverting the image (default 1). + * PostCondition: myCanvas2 contains the inverse + * of the image in myCanvas1. + */ + virtual void run(unsigned numThreads = 1); +}; + +#endif /* IMAGEINVERTER_H_ */ diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile new file mode 100644 index 000000000..27d4cd03e --- /dev/null +++ b/src/tests/testInverter/Makefile @@ -0,0 +1,63 @@ +# Makefile for testInverter + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testInverter + +# Object files +ODIR = obj +_OBJ = ImageInverter.o $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testInverter/testInverter.cpp b/src/tests/testInverter/testInverter.cpp new file mode 100644 index 000000000..370b4f62f --- /dev/null +++ b/src/tests/testInverter/testInverter.cpp @@ -0,0 +1,16 @@ +/* + * testInverter.cpp + * + * Usage: ./testInverter + */ + +#include +#include "ImageInverter/ImageInverter.h" + +using namespace tsgl; + +int main(int argc, char* argv[]) { + int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); + ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); + ii.run(numThreads); +} diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile new file mode 100644 index 000000000..48304e949 --- /dev/null +++ b/src/tests/testLineChain/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLineChain + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineChain + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineChain/testLineChain.cpp b/src/tests/testLineChain/testLineChain.cpp new file mode 100644 index 000000000..8a2b390ad --- /dev/null +++ b/src/tests/testLineChain/testLineChain.cpp @@ -0,0 +1,82 @@ +/* + * testLineChain.cpp + * + * Usage: ./testLineChain + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a spirograph on a given Canvas using the specified number of threads. + * \details + * - The number of iterations, center of the spirograph, distance between threads, and spin are stored in constants. + * - A parallel block is made and the process is forked using the passed number of threads: \b t. + * - The actual number of threads spawned is stored in the constant: \b NTHREADS. + * - The rate at which the spirograph fades is calculated and stored in: \b FADERATE. + * - The current thread's id is stored in: \b TID. + * - \b xOld and \b yOld represent the old x and y-coordinates of the line, + * \b xNew and \b yNew represent the new ones. + * - \b xNew is set to the width of the Canvas, \b yNew is set to the middle of the canvas. + * - Set a variable, \b next, which will be used to determine the next \b xNew and \b yNew and set \b s to \b next. + * - Get a color based off of the thread's id number. + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - While the canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - For 0 to the number of iterations per frame: + * - \b next is incremented by the spacing in between the threads, and \b s is incremented by the spin factor. + * - \b xOld and \b yOld are set to \b xNew and \b yNew. + * - The size of the line is determined by \b s. + * - \b xNew and \b yNew are calculated and set. + * - The line is drawn to the Canvas. + * . + * - If we are working with the main thread, draw a rectangle that is the size of the Canvas and has an alpha transparency + * of: \b FADERATE. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param t The number of threads to use in the function. + */ +void lineChainFunction(Canvas& can, int t) { + const int IPF = 3; + const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; + const float ARC = 2.3f, SPIN = 0.01f; + #pragma omp parallel num_threads(t) + { + const float NTHREADS = omp_get_num_threads(); + const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; + const int TID = omp_get_thread_num(); + int xOld, yOld, xNew = CWW*2, yNew = CWH; + float next = (ARC*TID)/NTHREADS, s = next; + ColorFloat c = Colors::highContrastColor(TID); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = 0; i < IPF; ++i) { + next += ARC; s += SPIN; + xOld = xNew; yOld = yNew; + float size = cos(s); + xNew = CWW + CWW*size*cos(next); + yNew = CWH + CWH*size*sin(next); + can.drawLine(xOld, yOld, xNew, yNew, c); + } + if (TID == 0) + can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); + #pragma omp barrier + } + } +} + +//Takes command line arguments for the window width and height as well as for the number of threads +//to use in the function +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 900; //If not, set the width and height to a default value + unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use + if (t == 0) + t = omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Spirograph", BLACK); + c.run(lineChainFunction,t); +} diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile new file mode 100644 index 000000000..8f2cb68e6 --- /dev/null +++ b/src/tests/testLineFan/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLineFan + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLineFan + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLineFan/testLineFan.cpp b/src/tests/testLineFan/testLineFan.cpp new file mode 100644 index 000000000..74aaf0d4a --- /dev/null +++ b/src/tests/testLineFan/testLineFan.cpp @@ -0,0 +1,66 @@ +/* + * testLineFan.cpp + * + * Usage: ./testLineFan + */ + +#include +#include +#include "Util.h" + +using namespace tsgl; + +/*! + * \brief Draws a fan of randomly colored lines at the target framerate and a dynamic number of threads using OMP. + * \details + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - The spacing in between the arcs of the fan is stored in the constant: \b ARC . + * - While the canvas is open: + * - The number of threads to use is recalculated, and the process is forked based off of the passed number of threads: \b t. + * - The internal timer sleeps on each thread until the next frame is ready to be drawn. + * - An offset is calculated based on the thread's ID and a predefined arc-length. + * - An angle is then calculated using the offset and the Canvas' current lifespan ( as calculated by \b can.getReps() ). + * - The vertices of the lines to be drawn are chosen using the sines and cosines of the predetermined angle. + * - A random color is chosen. + * - The line is draw to the Canvas. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param t The number of threads to use in the function. + */ +void lineFanFunction(Canvas& can, int t) { + const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan + while (can.isOpen()) { + #pragma omp parallel num_threads(t) + { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + int a, b, c, d, red, green, blue; + double angle, offset = omp_get_thread_num() * ARC; + angle = offset + can.getReps() * RAD; + a = can.getWindowWidth() / 2 * (1 + sin(angle)); + b = can.getWindowHeight() / 2 * (1 + cos(angle)); + c = can.getWindowWidth() / 2 * (1 - sin(angle)); + d = can.getWindowHeight() / 2 * (1 - cos(angle)); + red = (a + can.getReps()) % NUM_COLORS; + green = (b + can.getReps()) % NUM_COLORS; + blue = (a * b + can.getReps()) % NUM_COLORS; + can.drawLine(a, b, c, d, ColorInt(red, green, blue)); + } + } +} + +//Takes command-line arguments for the width and height of the screen as well as for the +//number of threads to use in the function +int main(int argc, char** argv) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w; + if (w <= 0 || h <= 0) { //Checked the passed width and height if they are valid + w = 1200; + h = 900; //If not, set the width and height to a default value + } + unsigned t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); //Get the number of threads to use + if (t == 0) + t = omp_get_num_procs(); + Canvas c(-1,-1,w,h,"Line Fan"); + c.run(lineFanFunction,t); +} diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile new file mode 100644 index 000000000..035a50499 --- /dev/null +++ b/src/tests/testLines/Makefile @@ -0,0 +1,63 @@ +# Makefile for testLines + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testLines + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp new file mode 100644 index 000000000..625f32b79 --- /dev/null +++ b/src/tests/testLines/testLines.cpp @@ -0,0 +1,67 @@ +/** + * testLines.cpp tests displaying the Line and Polyline classes. + */ +#include +using namespace tsgl; + +void lineFunction(Canvas& c) { + ColorFloat colors[] = { ColorFloat(1,0,0,1), ColorFloat(0,1,0,0.6), + ColorFloat(0,0,1,0.9), ColorFloat(1,0,1,0.5), + ColorFloat(1,1,0,0.8), ColorFloat(0,1,1,0.4), + ColorFloat(0,0,1,0.7) }; + Line * l = new Line(0,0,0,200,0,0,0,ColorFloat(1,0,0,0.5)); + + // l->setColor(RED); + l->setColor(colors); + + float vertices[] = { -150,-100,-100, + -100,100,0, + -50,-100,100, + 0,-100,-100, + 50,100,0, + 100,-100,100, + 150,-100,-100 }; + + Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); + + // printf("Line: %f\n", l->getAlpha()); + // printf("Pline: %f\n", p->getAlpha()); + + // p->setColor(BLUE); + p->setColor(colors); + c.add(l); + c.add(p); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while( c.isOpen() ) { + c.sleep(); + // l->setCenterX(sin(floatVal/90)); + // l->setCenterY(sin(floatVal/90)); + // l->setCenterZ(sin(floatVal/90)); + // l->setYaw(floatVal); + // l->setPitch(floatVal); + // l->setRoll(floatVal); + // l->setLength(sin(floatVal/90) + 2); + // if (l->getLength() > 3 || l->getLength() < 1) { + // delta *= -1; + // } + // l->changeLengthBy(delta); + // p->setCenterX(sin(floatVal/90)); + // p->setCenterY(sin(floatVal/90)); + // p->setCenterZ(sin(floatVal/90)); + // p->setYaw(floatVal); + // p->setPitch(floatVal); + p->setRoll(floatVal); + floatVal += 1; + } + + delete l; + delete p; +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Lines"); + c.run(lineFunction); +} \ No newline at end of file diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile new file mode 100644 index 000000000..404a455c4 --- /dev/null +++ b/src/tests/testMouse/Makefile @@ -0,0 +1,63 @@ +# Makefile for testMouse + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testMouse + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testMouse/testMouse.cpp b/src/tests/testMouse/testMouse.cpp new file mode 100644 index 000000000..e37e49c34 --- /dev/null +++ b/src/tests/testMouse/testMouse.cpp @@ -0,0 +1,103 @@ +/* + * testMouse.cpp + * + * Usage: ./testMouse + */ + +#include + +using namespace tsgl; + +inline float dist(float x1, float y1, float x2, float y2) { + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +inline float angle(float x1, float y1, float x2, float y2) { + return atan2(y1 - y2, x1 - x2); +} + +inline void rotate(float cx, float cy, int& xx, int& yy, float rot) { + float scale = cy/cx; + float stretchy = cy + yy/scale - cx; + float mydist = dist(xx,stretchy,cx,cy); + float newang = angle(xx,stretchy,cx,cy)+rot; + xx = cx + mydist*cos(newang); + yy = cy + mydist*sin(newang)*scale; +} + +/*! + * \brief Tiny little painting function for drawing with the mouse. + * \details + * - Initialize and unset a flag for whether the mouse is pressed. + * - Allocate some large arrays for x,y coordinates and colors. + * - Set an array index variable to 0. + * - Declare variables for last x and y coordinates. + * - Bind the spacebar on-press event to clearing the Canvas. + * - Bind the left mouse on-press event to setting the lastX, lastY, and first x,y array + * coordinate to the mouse's current position, and the first color to a random color; also, + * set the array index to 1, and set the mouseDown flag. + * - Bind the left mouse on-release event to draw a Concave & Convex polygon with the built-up vertices, + * and to unset the mouseDown flag. + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - While the Canvas is open: + * - If the mouse is down: + * - Draw a line from the mouse's last coordinates to the current ones. + * - Set the coordinates at position \b index to the mouse's current position. + * - Set the corresponding color randomly. + * - Increment the index. + * . + * - Sleep the timer until the Canvas is ready to draw again. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param threads Number of threads to use. + */ +void mouseFunction(Canvas& can, int threads) { + const int CX = can.getWindowWidth() / 2, CY = can.getWindowHeight() / 2; + int x[3], y[3], index = 0; + bool mouseDown = false; + ColorFloat color[3]; + + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { + can.clearProcedural(); + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&mouseDown, &can, &index, &x, &y, &color]() { + x[0] = can.getMouseX(); + y[0] = can.getMouseY(); + color[0] = Colors::randomColor(1.0f); + index = 0; + mouseDown = true; + }); + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_RELEASE, [&mouseDown, &can, &index, &x, &y, &color]() { + mouseDown = false; + }); + + while (can.isOpen()) { + if (mouseDown) { + color[1] = color[2]; + color[2] = Colors::randomColor(1.0f); + x[1] = x[2]; y[1] = y[2]; + x[2] = can.getMouseX(); y[2] = can.getMouseY(); + if (++index > 2) + #pragma omp parallel num_threads (threads) + { + float tdelta = (2*PI*omp_get_thread_num())/omp_get_num_threads(); + int myx[3], myy[3]; + for (int i = 0; i < 3; ++i) { + myx[i] = x[i]; myy[i] = y[i]; + rotate(CX,CY,myx[i],myy[i],tdelta); + } + can.drawConvexPolygon(3,myx,myy,color,true); + } + } + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : -1; + int h = (argc > 2) ? atoi(argv[2]) : w; + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Draw With Your Mouse!", WHITE); + c.run(mouseFunction,t); +} diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile new file mode 100644 index 000000000..d89316619 --- /dev/null +++ b/src/tests/testPixels/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPixels + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPixels + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp new file mode 100644 index 000000000..c4b05bbef --- /dev/null +++ b/src/tests/testPixels/testPixels.cpp @@ -0,0 +1,103 @@ +/* + * testColorPoints.cpp + * + * Usage: ./testColorPoints + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a neat pattern of points to a Background using OMP and takes in a command line + * argument for the number of threads to use. Also tests both get- and draw- Pixel() functionality. + * \details + * - A parallel block is set up with \#pragma omp parallel using the number of threads passed. + * - The actual number of threads created is stored in: \b nthreads . + * - The number of lines per thread is calculated and stored in: \b myPart . + * - The starting position of each given thread is calculated and stored in: \b myStart . + * - The outer for loop is set up in a block pattern, and the inner for loop runs from 0 to the Canvas width. + * - The color for a thread is calculated. + * - If the point's coordinate is even: + * - Draw a point on the Canvas in the thread's color. + * - Else: + * - Draw the point normally. + * . + * - The function breaks from the outer for loop if the Canvas is closed. + * . + * - Sleep the internal timer of the Canvas until the next draw cycle. + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Number of threads to use. + */ +void colorPointsFunction(Canvas& can, int numberOfThreads) { + // Background * background = new Background(0,0,0,can.getWindowWidth(), can.getWindowHeight(), 0,0,0,RED); + // can.setBackground(background); + Background * background = can.getBackground(); + + /* this is the part of the test for drawPixel */ + #pragma omp parallel num_threads(numberOfThreads) + { + int nthreads = omp_get_num_threads(); //Actual number of threads to use + // note: allocating rows pixels to threads like this is only perfect if can.getWindowHeight() % # of threads = 0. + // but I'm too lazy to make it work perfectly always, since it's "good enough" and this is really just a drawPixel test. + int myPart = can.getWindowHeight() / nthreads; + int myStart = myPart * omp_get_thread_num(); + for (int i = myStart; i < myStart + myPart; i++) { + for (int j = 0; j < can.getWindowWidth(); j++) { + // int id = omp_get_thread_num(); + if (i % 2 == 0) { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, BLACK); + } else { + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(i % 255, j % 255, (i*j) % 255)); + } + } + if (!can.isOpen()) break; + } + } + + /* end drawPixel. while loop only contains can.sleep() */ + + /* the getPixel portion of the test */ + // bool print = false; + // int mouseX = 0; + // int mouseY = 0; + + // background->drawSquare(-100,100,0,100,0,0,0,RED); + // background->drawSquare(-100,-100,0,100,0,0,0,GREEN); + // background->drawSquare(100,100,0,100,0,0,0,BLUE); + // background->drawSquare(100,-100,0,100,0,0,0,ORANGE); + + // can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&print] () { + // print = true; + // }); + + // ColorInt c; + /* end getPixel(). uncomment entirety of while loop besides can.sleep */ + + while (can.isOpen()) { + can.sleep(); + // mouseX = can.getMouseX(); + // mouseY = can.getMouseY(); + // if (print) { + // background->drawPixel(mouseY, mouseX, RED); + // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. + // printf("%d, %d - ", mouseY, mouseX); + // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); + // print = false; + // } + } +} + +//Takes in command line arguments for the window width and height as well +//as for the number of threads to use +int main(int argc, char* argv[]) { + int h = (argc > 2) ? atoi(argv[2]) : 0.8*Canvas::getDisplayHeight(); + int w = (argc > 1) ? atoi(argv[1]) : h * 1.5; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + int t = (argc > 3) ? atoi(argv[3]) : omp_get_num_procs(); + Canvas c(-1, -1, w, h, "Dithered Points", BLACK); + c.run(colorPointsFunction,t); +} diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile new file mode 100644 index 000000000..7da1a87b9 --- /dev/null +++ b/src/tests/testPrism/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPrism + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPrism + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPrism/testPrism.cpp b/src/tests/testPrism/testPrism.cpp new file mode 100644 index 000000000..3be365eff --- /dev/null +++ b/src/tests/testPrism/testPrism.cpp @@ -0,0 +1,84 @@ +/* + * testPrism.cpp + * + * Usage: ./testPrism + */ + +#include +#include + +using namespace tsgl; + +void prismFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Prism * testPrism = new Prism(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Prism * testPrism2 = new Prism(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Prism * testPrism3 = new Prism(300, 0.0, 0.0, 8, 100, 100, 0.0, 0.0, 45.0, colors); + + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPrism2->getAlpha()); + // testPrism2->setColor(colors); + // printf("%f\n", testPrism2->getAlpha()); + can.add(testPrism); + can.add(testPrism2); + can.add(testPrism3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPrism->setCenterX(sin(rotation)*200); + // testPrism->setCenterY(cos(rotation)*200); + // testPrism->setCenterZ(sin(rotation)*100); + // testPrism->setYaw(rotation*45); + testPrism->setPitch(rotation*45); + // testPrism->setRoll(rotation*45); + // testPrism->setHeight(sin(rotation)*100+101); + // testPrism->setRadius(sin(rotation)*100+101); + // if(testPrism->getHeight() >= 200) { + // delta = -5; + // } + // if(testPrism->getHeight() <= 5) { + // delta = 5; + // } + // testPrism->changeHeightBy(delta); + // if(testPrism->getRadius() >= 200) { + // delta = -5; + // } + // if(testPrism->getRadius() <= 5) { + // delta = 5; + // } + // testPrism->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testPrism->setColor(RED); + } else { + testPrism->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPrism; + delete testPrism2; + delete testPrism3; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Prism", BLACK); + c.run(prismFunction); +} \ No newline at end of file diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile new file mode 100644 index 000000000..0373a8e25 --- /dev/null +++ b/src/tests/testProcedural/Makefile @@ -0,0 +1,63 @@ +# Makefile for testProcedural + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProcedural + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProcedural/testProcedural.cpp b/src/tests/testProcedural/testProcedural.cpp new file mode 100644 index 000000000..2fe19cfc3 --- /dev/null +++ b/src/tests/testProcedural/testProcedural.cpp @@ -0,0 +1,125 @@ +/* + * testBackground.cpp tests the core functions of TSGL::Background + * + * Usage: ./testBackground + */ + +#include + +using namespace tsgl; + +void testSuite1(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawSquare(-400, 225, 0, 100, 0,0,0, RED); + bg->drawSquare(-400, 100, 0, 100, 0,0,0, colors); + bg->drawCircle(-400, -100, 0, 50, 0,0,0, RED); + bg->drawCircle(-400, -225, 0, 50, 0,0,0, colors); + bg->drawEllipse(-225, 225, 0, 75,50, 0,0,0, RED); + bg->drawEllipse(-225, 100, 0, 75,50, 0,0,0, colors); + bg->drawRectangle(-225, -100, 0, 150,100, 0,0,0, RED); + bg->drawRectangle(-225, -225, 0, 150,100, 0,0,0, colors); + bg->drawImage(0,225,0,"./assets/pics/launch.bmp",100,100,0,0,0); + bg->drawText(0,100,0,L"ü^xdog","./assets/freefont/FreeMono.ttf",50,0,0,0,RED); + bg->drawRegularPolygon(0,-100,0,50,5,0,0,0,RED); + bg->drawRegularPolygon(0,-225,0,50,7,0,0,0,colors); + bg->drawTriangle(225,275,0,275,175,0,175,175,0,0,0,0,RED); + bg->drawTriangle(225,50,0,275,150,0,175,150,0,0,0,0,colors); + float x1[4] = { 160, 225, 225, 290 }; + float y1[4] = {-100, -50,-150,-100 }; + float z1[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-100,0,4,x1,y1,z1,0,0,0,RED); + float x2[4] = { 160, 225, 225, 290 }; + float y2[4] = {-225,-175,-275,-225 }; + float z2[4] = { 0, 0, 0, 0 }; + bg->drawTriangleStrip(225,-225,0,4,x2,y2,z2,0,0,0,colors); + bg->drawArrow(400,225,0,100,10,45,0,0,RED,true); + bg->drawArrow(400,100,0,100,10,-45,0,0,colors); + bg->drawLine(400,-50,0,100,20,0,0,RED); + bg->drawLine(400,-150,0,100,-20,0,0,colors); + float vertices1[12] = { 350,-175,0, + 350,-200,0, + 450,-250,0, + 450,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices1,0,0,0,RED); + float vertices2[12] = { 450,-175,0, + 450,-200,0, + 350,-250,0, + 350,-275,0 }; + bg->drawPolyline(400,-225,0,4,vertices2,0,0,0,colors); +} + +void testSuite2(Background * bg) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + bg->clear(); + bg->drawStar(-400,225,0,50,5,0,0,0,RED,false); + bg->drawStar(-400,100,0,50,7,0,0,0,colors,false); + float x1[6] = { -450,-400,-375,-350,-400,-450 }; + float y1[6] = { -50, -50, -60,-150,-150,-100 }; + // renders incorrectly + bg->drawConcavePolygon(-400,-100,0,6,x1,y1,0,0,0,RED); + float x2[6] = { -450,-400,-375,-350,-400,-450 }; + float y2[6] = { -175,-175,-185,-275,-275,-225 }; + // renders correctly, due to shifted vertices + bg->drawConcavePolygon(-400,-225,0,6,x2,y2,0,0,0,colors); + float x3[6] = { -275,-175,-200,-175,-275,-250 }; + float y3[6] = { 275, 275, 225, 175, 175, 225 }; + bg->drawConvexPolygon(-400,225,0,6,x3,y3,0,0,0,RED); + float x4[6] = { -250,-275,-175,-200,-175,-275 }; + float y4[6] = { 100, 150, 150, 100, 50, 50 }; + bg->drawConvexPolygon(-400,100,0,6,x4,y4,0,0,0,colors); + + +} + +void proceduralFunction(Canvas& can) { + Background * bg = can.getBackground(); + // float x1[6] = { -275,-175,-200,-175,-275,-250 }; + // float y1[6] = { 275, 275, 225, 175, 175, 225 }; + // ConcavePolygon * c = new ConcavePolygon(0,0,0,6,x1,y1,0,0,0,RED); + // can.add(c); + + // Star * s = new Star(0,0,0,50,7,0,0,0,RED,false); + // can.add(s); + + // can.bindToButton(TSGL_RIGHT, TSGL_PRESS, [&c]() { + // c->changeXBy(10); + // }); + + bool flip = true; + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg, &flip]() { + if (flip) { + testSuite1(bg); + } else { + testSuite2(bg); + } + flip = !flip; + }); + + while (can.isOpen()) { + can.sleep(); + } +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.9*Canvas::getDisplayWidth(); + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Procedural Background", BLACK); + c.run(proceduralFunction); +} \ No newline at end of file diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile new file mode 100644 index 000000000..8f0f83322 --- /dev/null +++ b/src/tests/testProgressBar/Makefile @@ -0,0 +1,63 @@ +# Makefile for testProgressBar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProgressBar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProgressBar/testProgressBar.cpp b/src/tests/testProgressBar/testProgressBar.cpp new file mode 100644 index 000000000..fc7e8bd98 --- /dev/null +++ b/src/tests/testProgressBar/testProgressBar.cpp @@ -0,0 +1,58 @@ +/* + * testProgressBar.cpp + * + * Usage: ./testProgressBar + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws a diagonal black-to-white gradient using OMP and takes in a command line argument for the + * number of threads to use. + * \details + * - Compute and store the necessary information in order to draw the ProgressBar object + * (x-coordinate, y-coordinate, width, height, minimum, maximum, and the number of segments). + * - Create the ProgressBar object with the information calculated in the previous step. + * - Set the progress of drawing the ProgressBar object and store it in: \b progress. + * - While the Canvas is open: + * - Sleep the Canvas' internal timer until the next draw cycle. + * - Increment the progress so far. + * - For 0 to the number of segments: + * - Update the ProgressBar object. + * . + * - Draw the ProgressBar onto the Canvas. + * . + * . + * \param can Reference to the Canvas being drawn to. + */ +void progressBarFunction(Canvas& can, int numThreads) { + const int X = 100, Y = X, W = can.getWindowWidth()-X*2, H = 20, MIN = 0, MAX = 1000, SEGS = numThreads; + ProgressBar pb(X,Y,W,H,MIN,MAX,SEGS); + int progress = 0; + for (int i = 0; i < SEGS; ++i) + can.drawText(to_string(i),pb.getSegX(i)+8,pb.getSegY()-8,32,BLACK); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + ++progress; + for (int i = 0; i < SEGS; ++i) + pb.update(progress+i*(MAX/SEGS),i); + can.drawProgress(&pb); + } +} + +//Takes in the number of threads to use as a command line argument for the Canvas, defaulting to 8. +//( see http://www.cplusplus.com/articles/DEN36Up4/ ) +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : 8; + int w; + int h; + if (t <= 0 || 10 < t) //Checked the passed threadNumber if it is valid + t = 8; //If not, set numThreads to a default value + w = (t+2)*100; + h = 200; + Canvas c(-1, -1, w, h, "Progress Bar Example"); + c.run(progressBarFunction, t); +} diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile new file mode 100644 index 000000000..68e0bf69a --- /dev/null +++ b/src/tests/testProjectiles/Makefile @@ -0,0 +1,63 @@ +# Makefile for Projectiles + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testProjectiles + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testProjectiles/testProjectiles.cpp b/src/tests/testProjectiles/testProjectiles.cpp new file mode 100644 index 000000000..1b3c0dd35 --- /dev/null +++ b/src/tests/testProjectiles/testProjectiles.cpp @@ -0,0 +1,121 @@ +/* + * testProjectiles.cpp + * + * Usage: ./testProjectiles + */ + +#include "tsgl.h" + +using namespace tsgl; + +/*! + * \brief Target practice mini-game! + * \details Creates the target practice mini-game in this way: + * - Get coordinates for the target based off of the window size. + * - Set a coordinate changer for the target's x coordinate (so that it moves from left to right on the screen). + * - Get the center of the Canvas. + * - Get the number of targets (10). + * - Get the score counter. + * - Get the colors for the target (outer, middle, and bulls-eye center). + * - Bind the mouse so that when one clicks and hits the target in the middle then + * the score counter goes up. + * - While the Canvas is still open: + * - Sleep the internal timer of the Canvas until the next drawing loop is ready to be drawn. + * - Increment the target's x-coordinate by the coordinate changer. + * - Move the target up vertically by coordinate changer for its y-coordinate. + * - Draw the actual target. + * - If the target hits the middle of the screen: + * - Invert the y change so that the target moves downward. + * . + * - If the target goes off screen to the right: + * - Decrement the number of targets left. + * - Reset the targetX, targetY, and the coordinate changer for y. + * . + * - If we hit a target in the middle: + * - Increment the score. + * - Change the hit to false; + * - Move the target off of the screen. + * . + * - If the number of targets is less than 5: + * - Speed up the movement of the remaining targets. + * . + * - If the number of targets left is 0: + * - Print out the score, clear the Canvas one last time, and get out of the drawing loop. + * . + * . + * . + * \param can Reference to the Canvas being drawn on. + */ +void projectileFunction(Canvas& can) { + const int WINDOW_W = can.getWindowWidth(); + int targetX = 0, targetY = WINDOW_W / 2, coordinateChangerY = 1, coordinateChangerX = 3; //Used to control target motion + int centerX = WINDOW_W / 2;// centerY = WINDOW_H / 2; //Center of screen + int numberOfTargets = 10; //Number of targets + bool hit = false; //Determine if the target has been hit + int score = 0; //Score + ColorInt blueTarget(0, 0, 255); + ColorInt redTarget(255, 0, 0); //Color for targets + ColorInt yellowTarget(255, 255, 0); + //binding to left mouse button + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&hit, &can, &targetX, &targetY]() { + if((can.getMouseX() <= targetX && can.getMouseY() <= targetY) || can.getMouseY() == targetY) { + hit = true; //We hit the target + } + }); + + //Create circles of target and add to Canvas + Circle * blueCircle = new Circle(targetX, targetY, 50, BLUE); //Outer circle + Circle * redCircle = new Circle(targetX, targetY, 30, RED); //Middle + Circle * yellowCircle = new Circle(targetX, targetY, 10, YELLOW); //Inner + can.add(blueCircle); can.add(redCircle); can.add(yellowCircle); + + //Draw loop + while(can.isOpen()) { + can.sleep(); + can.clearProcedural(); + + targetX += coordinateChangerX; //Horizontal movement + targetY -= coordinateChangerY; //Vertical movement + + if(hit) { //If we hit a target.... + score++; + targetX = WINDOW_W + 60; + hit = false; + } + if(targetX >= centerX) { //If it hits the middle of the screen, invert the vertical direction + coordinateChangerY = -1; + } + if(targetX > WINDOW_W + 60) { //If the target is off the screen + numberOfTargets--; //Decrement the number of targets left + targetX = 0; //Reset the target and inverter + targetY = 200; + coordinateChangerY = 1; + } + if(numberOfTargets <= 5) { //Mix it up if there are only five targets left (speed up the targets) + coordinateChangerX = 6; + } + //Move each circle to the target's location + blueCircle->setCenter(targetX, targetY); + redCircle->setCenter(targetX, targetY); + yellowCircle->setCenter(targetX, targetY); + if(numberOfTargets == 0) { //End game + std::cout << "Your score: " << score << std::endl; + can.remove(redCircle); + can.remove(blueCircle); + can.remove(yellowCircle); + numberOfTargets--; + } + } + + delete redCircle; + delete blueCircle; + delete yellowCircle; +} + +//Takes command-line arguments for the width and height +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + Canvas c(-1, -1, w, h, "Click the Target!", BLACK); //Can change the size of the window + c.run(projectileFunction); +} diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile new file mode 100644 index 000000000..c4721dd36 --- /dev/null +++ b/src/tests/testPyramid/Makefile @@ -0,0 +1,63 @@ +# Makefile for testPyramid + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testPyramid + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testPyramid/testPyramid.cpp b/src/tests/testPyramid/testPyramid.cpp new file mode 100644 index 000000000..fdbf30f6a --- /dev/null +++ b/src/tests/testPyramid/testPyramid.cpp @@ -0,0 +1,78 @@ +/* + * testPyramid.cpp + * + * Usage: ./testPyramid + */ + +#include +#include + +using namespace tsgl; + +void pyramidFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Pyramid * testPyramid = new Pyramid(0.0, 0.0, 0.0, 3, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Pyramid * testPyramid2 = new Pyramid(-300, 0.0, 0.0, 5, 100, 100, 0.0, 0.0, 45.0, colors); + Pyramid * testPyramid3 = new Pyramid(300, 0.0, 0.0, 10, 100, 100, 0.0, 0.0, 45.0, RED); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testPyramid2->getAlpha()); + // testPyramid2->setColor(colors); + // printf("%f\n", testPyramid2->getAlpha()); + can.add(testPyramid); + can.add(testPyramid2); + can.add(testPyramid3); + float rotation = 0.0f; + GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testPyramid->setCenterX(sin(rotation)*200); + // testPyramid->setCenterY(cos(rotation)*200); + // testPyramid->setCenterZ(sin(rotation)*100); + // testPyramid->setYaw(rotation*45); + testPyramid->setPitch(rotation*45); + testPyramid2->setPitch(rotation*45); + testPyramid3->setPitch(rotation*45); + // testPyramid->setRoll(sin(rotation*45)*100+101); + // testPyramid->setHeight(sin(rotation)*100+101); + // testPyramid->setRadius(sin(rotation)*100+101); + // if(testPyramid->getHeight() >= 200) { + // delta = -5; + // } + // if(testPyramid->getHeight() <= 5) { + // delta = 5; + // } + // testPyramid->changeHeightBy(delta); + // if(testPyramid->getRadius() >= 200) { + // delta = -5; + // } + // if(testPyramid->getRadius() <= 5) { + // delta = 5; + // } + // testPyramid->changeRadiusBy(delta); + if (rotation*45 >= 360) { + if (boolean) { + testPyramid->setColor(RED); + } else { + testPyramid->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testPyramid; + delete testPyramid2; + delete testPyramid3; +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Basic Pyramid", BLACK); + c.run(pyramidFunction); +} \ No newline at end of file diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile new file mode 100644 index 000000000..d5cb2797a --- /dev/null +++ b/src/tests/test_specs/Makefile @@ -0,0 +1,63 @@ +# Makefile for test_specs + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = test_specs + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/test_specs/test_specs.cpp b/src/tests/test_specs/test_specs.cpp new file mode 100644 index 000000000..367badcb1 --- /dev/null +++ b/src/tests/test_specs/test_specs.cpp @@ -0,0 +1,31 @@ +#include "tsgl.h" + +int main(int argc, char* argv[]) { + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL); + if (!window) { + fprintf(stderr, "GLFW window creation failed."); + exit(100); + } + glfwMakeContextCurrent(window); + const GLubyte* gfxVendor = glGetString(GL_VENDOR); + std::string gfx(gfxVendor, gfxVendor + strlen((char*)gfxVendor)); + + FT_Library flib = NULL; + FT_Init_FreeType(&flib); + FT_Int fmaj = 0, fmin = 0, fpatch = 0; + FT_Library_Version(flib,&fmaj,&fmin,&fpatch); + + printf("Vendor: %s %s\n", gfx.c_str(), glGetString(GL_RENDERER)); + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + printf("GLFW version: %s\n", glfwGetVersionString()); + printf("GLEW version: %s\n", glewGetString(GLEW_VERSION)); + printf("Freetype version: %d.%d.%d\n", (int)fmaj,(int)fmin,(int)fpatch); + + glfwTerminate(); +} From a413f79c095d0c03f11aab572e1e9d1834725649 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:06:45 -0400 Subject: [PATCH 076/105] Add updated tests --- src/tests/Makefile | 82 ++++++++++++++++++ src/tests/testRectangle/Makefile | 63 ++++++++++++++ src/tests/testRectangle/testRectangle.cpp | 68 +++++++++++++++ src/tests/testRegularPolygon/Makefile | 63 ++++++++++++++ .../testRegularPolygon/testRegularPolygon.cpp | 63 ++++++++++++++ src/tests/testScreenshot/Makefile | 63 ++++++++++++++ src/tests/testScreenshot/testScreenshot.cpp | 54 ++++++++++++ src/tests/testSpectrogram/Makefile | 63 ++++++++++++++ src/tests/testSpectrogram/testSpectrogram.cpp | 85 +++++++++++++++++++ src/tests/testSpectrum/Makefile | 63 ++++++++++++++ src/tests/testSpectrum/testSpectrum.cpp | 61 +++++++++++++ src/tests/testSphere/Makefile | 63 ++++++++++++++ src/tests/testSphere/testSphere.cpp | 80 +++++++++++++++++ src/tests/testSquare/Makefile | 63 ++++++++++++++ src/tests/testSquare/testSquare.cpp | 66 ++++++++++++++ src/tests/testStar/Makefile | 63 ++++++++++++++ src/tests/testStar/testStar.cpp | 52 ++++++++++++ src/tests/testText/Makefile | 63 ++++++++++++++ src/tests/testText/testText.cpp | 78 +++++++++++++++++ src/tests/testTextCart/Makefile | 63 ++++++++++++++ src/tests/testTextCart/testTextCart.cpp | 41 +++++++++ src/tests/testTextTwo/Makefile | 63 ++++++++++++++ src/tests/testTextTwo/testTextTwo.cpp | 41 +++++++++ src/tests/testTransparency/Makefile | 63 ++++++++++++++ .../testTransparency/testTransparency.cpp | 31 +++++++ src/tests/testTriangle/Makefile | 63 ++++++++++++++ src/tests/testTriangle/testTriangle.cpp | 59 +++++++++++++ src/tests/testTriangleStrip/Makefile | 63 ++++++++++++++ .../testTriangleStrip/testTriangleStrip.cpp | 60 +++++++++++++ src/tests/testUnits/Makefile | 63 ++++++++++++++ src/tests/testUnits/testUnits.cpp | 27 ++++++ 31 files changed, 1893 insertions(+) create mode 100644 src/tests/Makefile create mode 100644 src/tests/testRectangle/Makefile create mode 100644 src/tests/testRectangle/testRectangle.cpp create mode 100644 src/tests/testRegularPolygon/Makefile create mode 100644 src/tests/testRegularPolygon/testRegularPolygon.cpp create mode 100644 src/tests/testScreenshot/Makefile create mode 100644 src/tests/testScreenshot/testScreenshot.cpp create mode 100644 src/tests/testSpectrogram/Makefile create mode 100644 src/tests/testSpectrogram/testSpectrogram.cpp create mode 100644 src/tests/testSpectrum/Makefile create mode 100644 src/tests/testSpectrum/testSpectrum.cpp create mode 100644 src/tests/testSphere/Makefile create mode 100644 src/tests/testSphere/testSphere.cpp create mode 100644 src/tests/testSquare/Makefile create mode 100644 src/tests/testSquare/testSquare.cpp create mode 100644 src/tests/testStar/Makefile create mode 100644 src/tests/testStar/testStar.cpp create mode 100644 src/tests/testText/Makefile create mode 100644 src/tests/testText/testText.cpp create mode 100644 src/tests/testTextCart/Makefile create mode 100644 src/tests/testTextCart/testTextCart.cpp create mode 100644 src/tests/testTextTwo/Makefile create mode 100644 src/tests/testTextTwo/testTextTwo.cpp create mode 100644 src/tests/testTransparency/Makefile create mode 100644 src/tests/testTransparency/testTransparency.cpp create mode 100644 src/tests/testTriangle/Makefile create mode 100644 src/tests/testTriangle/testTriangle.cpp create mode 100644 src/tests/testTriangleStrip/Makefile create mode 100644 src/tests/testTriangleStrip/testTriangleStrip.cpp create mode 100644 src/tests/testUnits/Makefile create mode 100644 src/tests/testUnits/testUnits.cpp diff --git a/src/tests/Makefile b/src/tests/Makefile new file mode 100644 index 000000000..183246145 --- /dev/null +++ b/src/tests/Makefile @@ -0,0 +1,82 @@ +# Master Makefile for Tests + +# ***************************************************** + +# SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the tests +SUBDIRS_TO_BUILD := test_specs \ + test2Dvs3D \ + test3DRotation \ + testAlphaRectangle \ + testArrows \ + testBackground \ + testCircle \ + testConcavePolygon \ + testCone \ + testConvexPolygon \ + testCube \ + testCuboid \ + testCylinder \ + testDice \ + testDiorama \ + testEllipse \ + testEllipsoid \ + testImage \ + testLines \ + testPrism \ + testProcedural \ + testPyramid \ + testRectangle \ + testRegularPolygon \ + testSphere \ + testSquare \ + testStar \ + testText \ + testTransparency \ + testTriangle \ + testTriangleStrip \ +# testAura \ +# testBlurImage \ +# testCalcPi \ +# testColorWheel \ +# testConstructors \ +# testCosineIntegral \ +# testFunction \ +# testGetPixels \ +# testGradientWheel \ +# testGraydient \ +# testGreyscale \ +# testHighData \ +# testImageCart \ +# testInverter \ +# testLineChain \ +# testLineFan \ +# testMouse \ +# testPixels \ +# testProgressBar \ +# testProjectiles \ +# testScreenshot \ +# testSpectrogram \ +# testSpectrum \ +# testTextCart \ +# testTextTwo \ +# testUnits \ + +SUBDIRS_TO_CLEAN := $(subst test,..., $(SUBDIRS_TO_BUILD)) # Used to clean the tests + + +all: $(SUBDIRS_TO_BUILD) + +$(SUBDIRS_TO_BUILD): + @echo "" + @tput setaf 3; + @echo "+++++++++++++++++ Generating Binaries for$(subst /., , $@) +++++++++++++++++" + @tput sgr0; + @echo "" + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS_TO_BUILD) clean $(SUBDIRS_TO_CLEAN) + +clean: $(SUBDIRS_TO_CLEAN) + +$(SUBDIRS_TO_CLEAN): + cd $(subst ...,test,$@) && $(MAKE) clean \ No newline at end of file diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile new file mode 100644 index 000000000..5e0cf7fe5 --- /dev/null +++ b/src/tests/testRectangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testRectangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRectangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRectangle/testRectangle.cpp b/src/tests/testRectangle/testRectangle.cpp new file mode 100644 index 000000000..c83e94fa6 --- /dev/null +++ b/src/tests/testRectangle/testRectangle.cpp @@ -0,0 +1,68 @@ +/* + * testRectangle.cpp + * + * Usage: ./testRectangle + */ + +#include +#include + +using namespace tsgl; + +void rectangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,0.5), + ColorFloat(0,1,0,0.6), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Rectangle * rectangle = new Rectangle(0,0,0,100,200,0,0,0,colors/* ColorFloat(1,0,0,1) */); + // rectangle->setCenterX(200); + // rectangle->setRotationPoint(0,0,0); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rectangle->getAlpha()); + // rectangle->setColor(colors); + // printf("%f\n", rectangle->getAlpha()); + can.add(rectangle); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // rectangle->setCenterX(sin(floatVal/90)*100); + // rectangle->setCenterY(sin(floatVal/90)*100); + // rectangle->setCenterZ(sin(floatVal/90)*100); + // rectangle->setYaw(floatVal); + // rectangle->setPitch(floatVal); + // rectangle->setRoll(floatVal); + // rectangle->setWidth(sin(floatVal/90) *100 + 100); + // rectangle->setHeight(sin(floatVal/90) *100 + 200); + // if (rectangle->getWidth() > 200 || rectangle->getWidth() < 100) { + // delta *= -1; + // } + // rectangle->changeWidthBy(delta); + // if (rectangle->getHeight() > 300 || rectangle->getHeight() < 100) { + // delta *= -1; + // } + // rectangle->changeHeightBy(delta); + // if (delta > 0) { + // rectangle->setColor(colors); + // } else { + // rectangle->setColor(RED); + // } + floatVal += 1; + } + + delete rectangle; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Rectangle", BLACK); + c.run(rectangleFunction); +} \ No newline at end of file diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile new file mode 100644 index 000000000..9383cba89 --- /dev/null +++ b/src/tests/testRegularPolygon/Makefile @@ -0,0 +1,63 @@ +# Makefile for testRegularPolygon + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testRegularPolygon + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testRegularPolygon/testRegularPolygon.cpp b/src/tests/testRegularPolygon/testRegularPolygon.cpp new file mode 100644 index 000000000..9a4dd7ea9 --- /dev/null +++ b/src/tests/testRegularPolygon/testRegularPolygon.cpp @@ -0,0 +1,63 @@ +/* + * testRegularPolygon.cpp + * + * Usage: ./testRegularPolygon + */ + +#include +#include + +using namespace tsgl; + +void rpFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + RegularPolygon * rp = new RegularPolygon(0,0,0,100,7,0,0,0,colors); + // rp->setCenterX(200); + // rp->setRotationPoint(0,0,0); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", rp->getAlpha()); + // rp->setColor(colors); + // printf("%f\n", rp->getAlpha()); + can.add(rp); + float floatVal = 0.0f; + GLfloat delta = 5; + while (can.isOpen()) { + can.sleep(); + // rp->setCenterX(sin(floatVal/90)*100); + // rp->setCenterY(sin(floatVal/90)*100); + // rp->setCenterZ(sin(floatVal/90)*100); + // rp->setYaw(floatVal); + // rp->setPitch(floatVal); + // rp->setRoll(floatVal); + // rp->setRadius(sin(floatVal/90)*100 + 300); + if (rp->getRadius() > 300 || rp->getRadius() < 100) { + delta *= -1; + } + rp->changeRadiusBy(delta); + if (delta > 0) { + rp->setColor(colors); + } else { + rp->setColor(RED); + } + floatVal += 1; + } + + delete rp; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic RegularPolygon", BLACK); + c.run(rpFunction); +} \ No newline at end of file diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile new file mode 100644 index 000000000..bfc7c5018 --- /dev/null +++ b/src/tests/testScreenshot/Makefile @@ -0,0 +1,63 @@ +# Makefile for testScreenshot + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testScreenshot + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testScreenshot/testScreenshot.cpp b/src/tests/testScreenshot/testScreenshot.cpp new file mode 100644 index 000000000..96ce86a03 --- /dev/null +++ b/src/tests/testScreenshot/testScreenshot.cpp @@ -0,0 +1,54 @@ +/* + * testScreenshot.cpp + * + * Usage: ./testScreenshot + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws a bunch of triangles and outputs each frame to an image. + * \details + * - Declare and initialize variables to keep track of each of three vertices for a triangle. + * - Set the Canvas to record screenshots for 30 seconds (1800 frames). + * - Set up the internal timer of the Canvas to expire every \b FRAME seconds. + * - While the Canvas is open: + * - Sleep the internal timer until the Canvas is ready to draw. + * - Set the old coordinates to last frame's middle ones. + * - Set the middle coordinates to last frame's new ones. + * - Set the new coordinates to a random position on the Canvas. + * - Draw a triangle on the canvas with the given coordinates and a random color. + * . + * . + * \note The details of the recordForNumFrames() function are handled automatically in Canvas, and + * are by default written to the i frames/ directory. + * \param can Reference to the Canvas being drawn to. + */ +void screenShotFunction(Cart& can) { + int xNew = can.getWindowWidth() / 2, yNew = can.getWindowHeight() / 2, xMid = xNew, yMid = yNew, xOld, yOld; + can.recordForNumFrames(FPS * 30); + while (can.isOpen()) { // Checks to see if the window has been closed + can.sleep(); + xOld = xMid; + yOld = yMid; + xMid = xNew; + yMid = yNew; + xNew = rand() % can.getWindowWidth(); + yNew = rand() % can.getWindowHeight(); + can.drawTriangle(xOld, yOld, xMid, yMid, xNew, yNew, Colors::randomColor(), true); + } +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 800; //Width and height + int h = (argc > 2) ? atoi(argv[2]) : 600; + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 800; + h = 600; + } + Cart c(-1, -1, w, h, 0, 0, 800, 600,"Screenshot Test"); + c.run(screenShotFunction); +} diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile new file mode 100644 index 000000000..dfaa0fba6 --- /dev/null +++ b/src/tests/testSpectrogram/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSpectrogram + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrogram + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrogram/testSpectrogram.cpp b/src/tests/testSpectrogram/testSpectrogram.cpp new file mode 100644 index 000000000..99eb133ae --- /dev/null +++ b/src/tests/testSpectrogram/testSpectrogram.cpp @@ -0,0 +1,85 @@ +/* + * testSpectrogram.cpp + * + * Usage: ./testSpectrogram + */ + +#include + +#include +using namespace tsgl; + +/*! + * \brief Displays a spectrogram. + * \details Shows a spectrogram for the colors of a chosen photo. + * - The window width and height are stored for ease of use. + * - The image is drawn onto the Canvas. + * - A Spectrogram object is created which will display the spectrogram. + * - Sleep the Canvas for 1/10th of a second. + * - Have a counter that keeps track of the number of pixels that we have checked (for their color). + * - A parallel block is created and the process is forked. + * - The thread id and the actual number of threads spawned are stored. + * - Start and stopping points for the thread are calculated and stored. + * - For the starting point to the ending point of rendering: + * - If the Canvas is open: + * - Sleep the internal timer until the next draw cycle. + * - For 0 to the width of the Canvas: + * - Get a hue color based off of the current pixel. + * - Check for a weird case where we can end up with a NaN error (Not a Number). + * - Draw the point onto the Canvas. + * . + * - Update the number of pixels checked in an parallel atomic block (to avoid conflicts). + * - Draw the results on the Spectrogram object. + * . + * . + * - Have the Canvas sleep for: FRAME seconds. + * - Draw the chosen image onto the Canvas. + * - Close the Spectrogram object. + * . + * \param can Reference to the Canvas object to draw to. + * \param fname The name of the file to get the image from. + */ +void spectrogramFunction(Canvas& can, std::string fname) { + const int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); + can.drawImage(fname, 0, 0, cww, cwh); + Spectrogram sp(VERTICAL,500); + can.sleepFor(0.1f); +// can.recordForNumFrames(FPS); + unsigned numChecked = 0; + #pragma omp parallel num_threads(omp_get_num_procs()) + { + int tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); + int blockSize = cwh / nthreads; + int start = tid * blockSize; + int end = (tid == (nthreads-1)) ? cwh : (tid+1) * blockSize; + for (int j = start; j < end; ++j) { + if (can.isOpen()) { + can.sleep(); + ColorHSV hsv; + for (int i = 0; i < cww; ++i) { + hsv = can.getPoint(i,j); + if (hsv.H == hsv.H) { //Check for NAN + sp.updateLocked(MAX_COLOR*hsv.H/6,1.0f,0.8f); + sp.updateCritical(MAX_COLOR*hsv.H/6,1.0f,0.8f); + } + can.drawPoint(i,j,ColorHSV(0.0f,0.0f,hsv.V)); + } + #pragma omp atomic + ++numChecked; + sp.draw((float)(1.0f*numChecked)/cwh); + } + } + } + // can.sleepFor(FRAME); + can.drawImage(fname, 0, 0, cww, cwh); + sp.finish(); +} + +//Takes command-line arguments for the file name of the picture to use in the spectrogram function +int main(int argc, char* argv[]) { + std::string fname = argc > 1 ? argv[1] : "../assets/pics/colorful_cars.jpg"; + int w, h; + TextureHandler::getDimensions(fname,w,h); + Canvas c(-1, Canvas::getDisplayHeight()-h, w, h ,"Spectrogram"); + c.run(spectrogramFunction, fname); +} diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile new file mode 100644 index 000000000..760443e7b --- /dev/null +++ b/src/tests/testSpectrum/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSpectrum + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSpectrum + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSpectrum/testSpectrum.cpp b/src/tests/testSpectrum/testSpectrum.cpp new file mode 100644 index 000000000..63fb5f125 --- /dev/null +++ b/src/tests/testSpectrum/testSpectrum.cpp @@ -0,0 +1,61 @@ +/* + * testSpectrum.cpp + * + * Usage: ./testSpectrum + */ + +#include +#include + +using namespace tsgl; + +/*! + * \brief Draws the full spectrum across the x, y, and time dimensions at the given framerate + * and a static number of threads using OMP and takes in a command line argument for the number of threads to use. + * \details + * - The internal timer of the Canvas is set up to go off every \b FRAME seconds ( \b FRAME == 1 / \b FPS ). + * - A parallel block is set up with OMP, using one thread per processor. + * - The actual number of threads spawned is stored in: \b nthreads. + * - Check if the argument for the number of threads is valid: + * - If it is less than or equal to 0, use the number of threads that we can use with OMP. + * - If it is greater than the number of threads that we can use, use only the number of threads that we can use with OMP. + * - Else, its valid and use that many threads. + * . + * - While the canvas is open: + * - The internal timer sleeps until the next frame is ready to be drawn. + * - An outer for loop from 0 to 255 is set up in a per-thread striping pattern. + * - An inner for loop runs from 0 to the 255 normally. + * - Each point is drawn to the canvas, with x, y, and time representing red, green, and blue respectively. + * . + * . + * \param can Reference to the Canvas being drawn to. + * \param numberOfThreads Reference to the number of threads to use. + */ +void spectrumFunction(Canvas& can, int numberOfThreads) { + #pragma omp parallel num_threads(omp_get_num_procs()) + { + int holder = omp_get_num_threads(); //Temp variable + int nthreads = 0; //Actual number of threads + if (numberOfThreads <= 0) { //Check if the argument for the number of threads is valid + nthreads = holder; //If not, use the number of threads that we can use with OMP + } else if(numberOfThreads > holder) { + nthreads = holder; + } else { + nthreads = numberOfThreads; //Else, use the argument as the number of threads + } + while (can.isOpen()) { + can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class + for (int i = omp_get_thread_num(); i < NUM_COLORS; i += nthreads) + for (int j = 0; j < NUM_COLORS; j++) + can.drawPoint(i, j, ColorInt(i, j, can.getReps() % NUM_COLORS)); + } + } +} + +//Takes command-line arguments for the number of threads to use +int main(int argc, char* argv[]) { + int t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); //Number of threads to use + Canvas c(-1,-1,255,255,"The Color Spectrum"); + c.run(spectrumFunction, t); +} + diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile new file mode 100644 index 000000000..d7a7189d6 --- /dev/null +++ b/src/tests/testSphere/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSphere + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSphere + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSphere/testSphere.cpp b/src/tests/testSphere/testSphere.cpp new file mode 100644 index 000000000..3d602168a --- /dev/null +++ b/src/tests/testSphere/testSphere.cpp @@ -0,0 +1,80 @@ +/* + * testSphere.cpp + * + * Usage: ./testSphere + */ + +#include +#include + +using namespace tsgl; + +void sphereFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Sphere * testSphere = new Sphere(225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, colors); + Sphere * testSphere2 = new Sphere(-225.0, 0.0, 0.0, 200, 0.0, 0.0, 0.0, RED); + testSphere->setIsOutlined(true); + testSphere2->setIsOutlined(true); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(ColorFloat(1,0,0,0.9)); + // printf("%f\n", testSphere->getAlpha()); + // testSphere->setColor(colors); + // printf("%f\n", testSphere->getAlpha()); + can.add(testSphere); + can.add(testSphere2); + float rotation = 0.0f; + // GLfloat delta = 5; + bool boolean = true; + while (can.isOpen()) { + can.sleep(); + // testSphere->setCenterX(sin(rotation) * 100); + // testSphere->setCenterY(cos(rotation) * 100); + // testSphere->setCenterZ(sin(rotation) * 100); + // testSphere->setYaw(rotation*45); + // testSphere->setPitch(rotation*45); + testSphere->setRoll(rotation*45); + // testSphere->setRadius(cos(rotation) * 100 +101); + // if(testSphere->getRadius() >= 200) { + // delta = -5; + // } + // if(testSphere->getRadius() <= 500) { + // delta = 5; + // } + // testSphere->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + // printf("%f\n", rotation*45); + if (rotation*45 >= 360) { + if (boolean) { + testSphere->setColor(RED); + } else { + testSphere->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + + rotation+=0.01; + } + + delete testSphere; + delete testSphere2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Sphere", BLACK); + c.run(sphereFunction); +} \ No newline at end of file diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile new file mode 100644 index 000000000..339f7d968 --- /dev/null +++ b/src/tests/testSquare/Makefile @@ -0,0 +1,63 @@ +# Makefile for testSquare + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testSquare + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testSquare/testSquare.cpp b/src/tests/testSquare/testSquare.cpp new file mode 100644 index 000000000..56eaf740a --- /dev/null +++ b/src/tests/testSquare/testSquare.cpp @@ -0,0 +1,66 @@ +/* + * testSquare.cpp + * + * Usage: ./testSquare + */ + +#include +#include + +using namespace tsgl; + +void squareFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(1,0,0,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Square * square = new Square(0,0,0,200,0,0,0,colors); + Square * square2 = new Square(-250,0,0,200,0,0,0,RED); + // square->setCenterX(200); + // square->setRotationPoint(0,0,0); + can.add(square); + can.add(square2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + bool ss = false; + while (can.isOpen()) { + can.sleep(); + // square->setCenterX(sin(floatVal/90) * 100); + // square->setCenterY(sin(floatVal/90) * 100); + // square->setCenterZ(sin(floatVal/90) * 100); + // square->setYaw(floatVal); + // square->setPitch(floatVal); + // square->setRoll(floatVal); + // square->setSideLength(sin(floatVal/90) * 100 + 300); + // if (square->getSideLength() > 300 || square->getSideLength() < 100) { + // delta *= -1; + // } + // square->changeSideLengthBy(delta); + // if (delta > 0) { + // square->setColor(colors); + // } else { + // square->setColor(RED); + // } + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + floatVal += 1; + } + + delete square; + delete square2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Square", BLACK); + c.run(squareFunction); +} \ No newline at end of file diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile new file mode 100644 index 000000000..90f33c627 --- /dev/null +++ b/src/tests/testStar/Makefile @@ -0,0 +1,63 @@ +# Makefile for testStar + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testStar + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testStar/testStar.cpp b/src/tests/testStar/testStar.cpp new file mode 100644 index 000000000..14afe96c6 --- /dev/null +++ b/src/tests/testStar/testStar.cpp @@ -0,0 +1,52 @@ +/** + * testStar.cpp tests displaying the Star class + * Note: tests currently indicating that performance is awful on a Macbook Pro 2012. + */ +#include +using namespace tsgl; + +void starFunction(Canvas& c) { + ColorFloat * colors = new ColorFloat[400]; + colors[0] = ColorFloat(1,0,0,1); + for(int i = 1; i < 10; i ++) { + // colors[i] = ColorFloat(float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX)), float(rand())/float((RAND_MAX))); + colors[i] = ColorFloat(0,0,1,1); + } + + Star * s1 = new Star(0, 0, 0, 200, 5, 0,0,0, colors, true); + // s1->setColor(RED); + c.add(s1); + + float floatVal = 0.0f; + GLfloat delta = 5; + while (c.isOpen()) { + c.sleep(); + // s1->setCenterX(sin(floatVal/90) * 100); + // s1->setCenterY(sin(floatVal/90) * 100); + // s1->setCenterZ(sin(floatVal/90) * 100); + // s1->setYaw(floatVal); + // s1->setPitch(floatVal); + // s1->setRoll(floatVal); + // s1->setRadius(sin(floatVal/90) * 100 + 300); + if (s1->getRadius() > 300 || s1->getRadius() < 100) { + delta *= -1; + } + s1->changeRadiusBy(delta); + if (delta > 0) { + s1->setColor(colors); + } else { + s1->setColor(RED); + } + floatVal += 1; + } + + delete[] colors; + // delete s1; // not sure why this doesn't have to be deleted. But it doesn't. +} + +int main(int argc, char* argv[]) { + int w = 1000; + int h = 1000; + Canvas c(-1, -1, w, h, "Stars"); + c.run(starFunction); +} \ No newline at end of file diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile new file mode 100644 index 000000000..41fa2cd44 --- /dev/null +++ b/src/tests/testText/Makefile @@ -0,0 +1,63 @@ +# Makefile for testText + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testText + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testText/testText.cpp b/src/tests/testText/testText.cpp new file mode 100644 index 000000000..fc07072d1 --- /dev/null +++ b/src/tests/testText/testText.cpp @@ -0,0 +1,78 @@ +/* + * testText.cpp + * + * Usage: ./testSpectrum + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a Canvas. + * \details + * - We changed it so that now a default text font is loaded if one is not specified. + * - We draw a few lines of text in various colors using drawText(). + * . + * \param can Reference to the Canvas being drawn to. + * \param font The font of the text. + */ +void textFunction(Canvas& can, std::string font) { + // can.drawText("A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + // can.drawText("Something extraordinary happened.", 16, 150, 32, RED); + // can.drawText("Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + // can.drawText("Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + // 32, BLUE); + // can.drawText("Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + // can.drawText("And to that I say...oh well.", 16, 550, 32, WHITE); + Text * lowercase = new Text(0,100,0,L"abcdefghijklmnopqrstuvwxyz", font, 40, 0,0,0,WHITE); + can.add(lowercase); + Text * uppercase = new Text(0,50,0,L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", font, 40, 0,0,0,WHITE); + can.add(uppercase); + Text * random = new Text(0,-50,0,L"{:<>,./?+=+^üc", font, 40, 0,0,0,WHITE); + // Rectangle * rec = new Rectangle(0,-53,0,random->getWidth(),random->getHeight(),0,0,0,GRAY); + can.add(random); + // can.add(rec); + + can.bindToButton(TSGL_MOUSE_LEFT, TSGL_PRESS, [&random]() { + random->setText(L"Glorgaborg"); + // random->setColor(RED); + // random->setFont("./assets/freefont/FreeSerifItalic.ttf"); + // random->setFontSize(100); + }); + + bool ss = false; + float rotation = 0.0f; + while(can.isOpen()) { + can.sleep(); + // if (can.getFrameNumber() > 50 && !ss) { + // can.takeScreenShot(); + // ss = true; + // } + // random->setCenterX(sin(rotation)*200); + // random->setCenterY(cos(rotation)*200); + // random->setCenterZ(sin(rotation)*100); + // random->setYaw(rotation*45); + random->setPitch(rotation*45); + // random->setRoll(rotation*45); + rotation+=0.01; + } + delete lowercase; + delete uppercase; + delete random; + +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font +int main(int argc, char * argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 330.0f; + std::string font = (argc > 3) ? argv[3] : "./assets/freefont/FreeMono.ttf"; + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 1.2f*Canvas::getDisplayHeight(); + h = 0.75f*w; + } + Canvas c(-1, -1, w, h, "Text on a Canvas"); + c.run(textFunction, font); +} diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile new file mode 100644 index 000000000..5963dd8bb --- /dev/null +++ b/src/tests/testTextCart/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTextCart + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextCart + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextCart/testTextCart.cpp b/src/tests/testTextCart/testTextCart.cpp new file mode 100644 index 000000000..77f5956a7 --- /dev/null +++ b/src/tests/testTextCart/testTextCart.cpp @@ -0,0 +1,41 @@ +/* + * testTextCart.cpp + * + * Usage: ./testTextCart + */ + +#include + +using namespace tsgl; + +/*! + * \brief Draws some text on a CartesianCanvas. + * \details Same as textFunction, but with a CartesianCanvas and black text. + * \param can Reference to the CartesianCanvas being drawn to (Cart is a typedef for CartesianCanvas). + * \param font The font of the text. + */ +void textCartFunction(Cart& can, std::string font) { + can.setFont(font); + can.drawText(L"A long time ago, in a galaxy far, far away.", 1, 2, 32, BLACK); + can.drawText(L"Something extraordinary happened.", 1, 1.9, 32, BLACK); + can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 1, 1.8, 32, BLACK); + can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 1, 1.7, + 32, BLACK); + can.drawText(L"Of *what* exactly that extraordinary event was.", 1, 1.6, 32, BLACK); + can.drawText(L"And to that I say...oh well.", 1, 1.5, 32, BLACK); +} + +//Takes command-line arguments for the width and height of the screen +//as well as for the font file for the text +int main(int argc, char * argv[]) { + //Width and height + int w = (argc > 1) ? atoi(argv[1]) : 1.2*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75*w - 200.0f; + std::string font = argv[3]; //Font + if(w <= 0 || h <= 0) { //Check validity of width and height + w = 1.2 * Canvas::getDisplayHeight(); + h = 0.75 * w; + } + Cart c(-1, -1, w, h, 0, 0, 4, 3, "Text on a Cartesian Canvas"); + c.run(textCartFunction, font); +} diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile new file mode 100644 index 000000000..a230e8978 --- /dev/null +++ b/src/tests/testTextTwo/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTextTwo + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTextTwo + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTextTwo/testTextTwo.cpp b/src/tests/testTextTwo/testTextTwo.cpp new file mode 100644 index 000000000..b6ef8060e --- /dev/null +++ b/src/tests/testTextTwo/testTextTwo.cpp @@ -0,0 +1,41 @@ +/* + * testTextTwo.cpp + * + * Usage: ./testTextTwo + */ + +#include + +using namespace tsgl; + +/** + * \brief Tests to see if text is still drawn if a font is not specified. + * \details Same as textFunction, but with the setFont line deleted. + * \param can Reference to the Canvas being drawn to. + */ +void textFunctionTwo(Canvas& can) { + ColorFloat RED = ColorFloat(1.0, 0.0, 0.0, 1.0); + ColorFloat GREEN = ColorFloat(0.0, 1.0, 0.0, 1.0); + ColorFloat BLUE = ColorFloat(0.0, 0.0, 1.0, 1.0); + + can.drawText(L"A long time ago, in a galaxy far, far away.", 16, 50, 32, BLACK); + can.drawText(L"Something extraordinary happened.", 16, 150, 32, RED); + can.drawText(L"Something far more extraordinary than anything mankind has ever seen.", 16, 250, 32, GREEN); + can.drawText(L"Unfortunately, as nobody was around to witness the event, we are largely ignorant", 16, 350, + 32, BLUE); + can.drawText(L"Of *what* exactly that extraordinary event was.", 16, 450, 32, GRAY); + can.drawText(L"And to that I say...oh well.", 16, 550, 32, WHITE); +} + +//Takes command-line arguments for the width and height of the screen +int main(int argc, char * argv[]) { + //Width and height + int w = (argc > 1) ? atoi(argv[1]) : 1.2f*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : 0.75f*w - 300.0f; + if(w <= 0 || h <= 0) { //Check the validity of the width and height + w = 1.2f*Canvas::getDisplayHeight(); + h = 0.75f*w; + } + Canvas c(-1, -1, w, h, "More Text on a Canvas"); + c.run(textFunctionTwo); +} diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile new file mode 100644 index 000000000..44792324d --- /dev/null +++ b/src/tests/testTransparency/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTransparency + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTransparency + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTransparency/testTransparency.cpp b/src/tests/testTransparency/testTransparency.cpp new file mode 100644 index 000000000..efb7867d3 --- /dev/null +++ b/src/tests/testTransparency/testTransparency.cpp @@ -0,0 +1,31 @@ +/* + * testTransparency.cpp + * + * Usage: ./testTransparency + */ + +#include +#include + +using namespace tsgl; + +void transparencyFunction(Canvas& can) { + Rectangle * rec = new Rectangle(0,0,-100,600,50,0,0,0,WHITE ); + Cube * cube = new Cube(0,0,0,100,0,45,45,ColorFloat(0,0,1,0.2)); + Cube * cube2 = new Cube(0,0,150,50,0,45,45,ColorFloat(1,0,0,0.2)); + can.add(cube2); + can.add(cube); + can.add(rec); + + float rotation = 0.0f; + while (can.isOpen()) { + can.sleep(); + cube2->setCenterZ(150 * cos(rotation)); + rotation += 0.1; + } +} + +int main(int argc, char* argv[]) { + Canvas c(-1, -1, 1024, 620, "Transparency", BLACK); + c.run(transparencyFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile new file mode 100644 index 000000000..53cee6da5 --- /dev/null +++ b/src/tests/testTriangle/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTriangle + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangle + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangle/testTriangle.cpp b/src/tests/testTriangle/testTriangle.cpp new file mode 100644 index 000000000..f29e650cb --- /dev/null +++ b/src/tests/testTriangle/testTriangle.cpp @@ -0,0 +1,59 @@ +/* + * testTriangle.cpp + * + * Usage: ./testTriangle + */ + +#include +#include + +using namespace tsgl; + +void triangleFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + Triangle * triangle = new Triangle(-50,-50,0,0,50,0,50,-50,0,0,0,0,colors); + Triangle * triangle2 = new Triangle(-150, -200,0,-200,100,0,-100,0,0,0,0,0,RED); + // triangle->setCenterX(200); + // triangle->setRotationPoint(0,0,0); + can.add(triangle); + can.add(triangle2); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // triangle->setCenterX(sin(floatVal/90) * 100); + // triangle->setCenterY(sin(floatVal/90) * 100); + // triangle->setCenterZ(sin(floatVal/90) * 100); + // triangle->setYaw(floatVal); + // triangle->setPitch(floatVal); + // triangle->setRoll(floatVal); + if (floatVal < 200) { + triangle->setColor(colors); + } else { + triangle->setColor(RED); + if (floatVal > 400) { + floatVal = 0; + } + } + floatVal += 1; + } + + delete triangle; + delete triangle2; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Triangle", BLACK); + c.run(triangleFunction); +} \ No newline at end of file diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile new file mode 100644 index 000000000..e5f78015b --- /dev/null +++ b/src/tests/testTriangleStrip/Makefile @@ -0,0 +1,63 @@ +# Makefile for testTriangleStrip + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testTriangleStrip + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testTriangleStrip/testTriangleStrip.cpp b/src/tests/testTriangleStrip/testTriangleStrip.cpp new file mode 100644 index 000000000..dc281cd33 --- /dev/null +++ b/src/tests/testTriangleStrip/testTriangleStrip.cpp @@ -0,0 +1,60 @@ +/* + * testTriangleStrip.cpp + * + * Usage: ./testTriangleStrip + */ + +#include +#include + +using namespace tsgl; + +void triangleStripFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0,0,1,0.8), + ColorFloat(0,1,0,0.8), ColorFloat(0,1,1,0.8), ColorFloat(1,0,0,0.8), + ColorFloat(1,0,1,0.8), ColorFloat(1,1,0,0.8), ColorFloat(1,1,1,0.8), + ColorFloat(0.5,0.5,0.5,0.8), ColorFloat(0.5,0.5,1,0.8), + ColorFloat(0.5,1,0.5,0.8), ColorFloat(0.5,1,1,0.8), ColorFloat(1,0.5,0.5,0.8), + ColorFloat(1,0.5,1,0.8), ColorFloat(1,1,0.5,0.8), ColorFloat(0,0,0.5,0.8), + ColorFloat(0,0.5,0,0.8), ColorFloat(0,0.5,0.5,0.8), ColorFloat(0.5,0,0,0.8), + ColorFloat(0.5,0,0.5,0.8), ColorFloat(0.5,0.5,0,0.8), ColorFloat(0.5,0.5,0.5,0.8)}; + float x[] = { 0,-50,50,-50,50,0 }; + float y[] = { -100,-50,-50,50,50,100 }; + float z[] = { 0,50,50,50,50,0 }; + TriangleStrip * ts = new TriangleStrip(0,0,0,6,x,y,z,0,0,0,colors); + // ts->setIsOutlined(true); + // ts->setCenterX(2); + ts->setRotationPoint(0,0,0); + can.add(ts); + float floatVal = 0.0f; + GLfloat delta = 0.05; + while (can.isOpen()) { + can.sleep(); + // ts->setCenterX(sin(floatVal/90) * 100); + // ts->setCenterY(sin(floatVal/90) * 100); + // ts->setCenterZ(sin(floatVal/90) * 100); + // ts->setYaw(floatVal); + ts->setPitch(floatVal); + // ts->setRoll(floatVal); + // if (floatVal < 200) { + // ts->setColor(colors); + // } else { + // ts->setColor(RED); + // if (floatVal > 400) { + // floatVal = 0; + // } + // } + floatVal += 1; + } + + delete ts; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic TriangleStrip", BLACK); + c.run(triangleStripFunction); +} \ No newline at end of file diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile new file mode 100644 index 000000000..c0ec4da0b --- /dev/null +++ b/src/tests/testUnits/Makefile @@ -0,0 +1,63 @@ +# Makefile for testUnits + +# ***************************************************** +# Variables to control Makefile operation + +CXX = g++ +RM = rm -f -r + +# Directory this example is contained in +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) + +# Dependencies +_DEPS = \ + +# Main source file +TARGET = testUnits + +# Object files +ODIR = obj +_OBJ = $(TARGET).o +OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) + +# To create obj directory +dummy_build_folder := $(shell mkdir -p $(ODIR)) + +# Flags +NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ + -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +CXXFLAGS = -Wall -g\ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/usr/include \ + -I/usr/include/freetype2 \ + +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ + -L/usr/local/lib \ + + +# **************************************************** +# Targets needed to bring the executable up to date + +all: $(TARGET) + +$(ODIR)/%.o: %.cpp $(_DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) + +$(TARGET): $(OBJ) + $(CXX) -o $@ $^ $(LFLAGS) + +.PHONY: clean + +clean: + $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) + @echo "" + @tput setaf 5; + @echo "*************** All output files removed from $(DIR)! ***************" + @tput sgr0; + @echo "" \ No newline at end of file diff --git a/src/tests/testUnits/testUnits.cpp b/src/tests/testUnits/testUnits.cpp new file mode 100644 index 000000000..f62a3271a --- /dev/null +++ b/src/tests/testUnits/testUnits.cpp @@ -0,0 +1,27 @@ +/* + * testUnits.cpp + * + * Usage: ./testUnits + */ + +/* testUnits.cpp runs the unit tests for the TSGL library. */ + +#include "tsgl.h" + +using namespace tsgl; + +int main() { + //Quick note about the tests... + std::cout << "NOTE: " << std::endl; + TsglDebug("This color means either a set of tests is being initiated or tests have passed."); + TsglErr("This color means tests have failed."); + //Begin Unit testing + std::cout << "Begin unit testing...." << std::endl << std::endl; + Canvas::runTests(); // Canvas (Image test included) + TextureHandler::runTests(); // TextureHandler + ConcavePolygon::runTests(); // ConcavePolygon + ConvexPolygon::runTests(); // ConvexPolygon + CartesianCanvas::runTests(); // CartesianCanvas + std::cout << std::endl; + TsglDebug("All Unit Tests have completed!"); +} From 51f6f19ee0643301b1b24433e864dc717fcf9017 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:07:44 -0400 Subject: [PATCH 077/105] Delete readme.md --- src/tests/readme.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/tests/readme.md diff --git a/src/tests/readme.md b/src/tests/readme.md deleted file mode 100644 index 8b1378917..000000000 --- a/src/tests/readme.md +++ /dev/null @@ -1 +0,0 @@ - From 31403ab2bca960c313f146ed1b81cd6b3a02ae25 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:09:04 -0400 Subject: [PATCH 078/105] Add files via upload --- runexamples | 16 +++++++++++++--- runtests | 10 ++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/runexamples b/runexamples index bc53f64a1..fe4b52cc0 100644 --- a/runexamples +++ b/runexamples @@ -17,17 +17,27 @@ cd ../.. # CD back to main TSGL directory EXAMPLES_PATH=src/examples # RUN EXAMPLES +run ./$EXAMPLES_PATH/ArrayBubbleSort/testArrayBubbleSort +run ./$EXAMPLES_PATH/ArrayShakerSort/testArrayShakerSort run ./$EXAMPLES_PATH/Ballroom/testBallroom run ./$EXAMPLES_PATH/Clock/testClock +# run ./$EXAMPLES_PATH/Conway/testConway +run ./$EXAMPLES_PATH/CubeRun/testCubeRun run ./$EXAMPLES_PATH/DiningPhilosophers/testPhilosophers run ./$EXAMPLES_PATH/DiningPhilosophers3D/test3DPhilosophers +# run ./$EXAMPLES_PATH/Fireworks/testFireworks +# run ./$EXAMPLES_PATH/ForestFire/testForestFire +# run ./$EXAMPLES_PATH/Langton/testLangton +# run ./$EXAMPLES_PATH/Mandelbrot/testMandelbrot run ./$EXAMPLES_PATH/MergeSort/testMergeSort run ./$EXAMPLES_PATH/NewtonPendulum/testNewtonPendulum 900 400 11 # Width, Height, Number Of Balls run ./$EXAMPLES_PATH/Pong/testPong +# run ./$EXAMPLES_PATH/ProducerConsumer/testProducerConsumer +# run ./$EXAMPLES_PATH/ReaderWriter/testReaderWriter run ./$EXAMPLES_PATH/SeaUrchin/testSeaUrchin 16 # Threads run ./$EXAMPLES_PATH/ShakerSort/testShakerSort run ./$EXAMPLES_PATH/SolarSystem/testSolarSystem -run ./$EXAMPLES_PATH/ArrayBubbleSort/testArrayBubbleSort -run ./$EXAMPLES_PATH/ArrayShakerSort/testArrayShakerSort run ./$EXAMPLES_PATH/ThreadedArrayAddition/testThreadedArrayAddition -run ./$EXAMPLES_PATH/ThreadedArrayOperations/testThreadedArrayOperations \ No newline at end of file +run ./$EXAMPLES_PATH/ThreadedArrayBubbleSort/testThreadedArrayBubbleSort +run ./$EXAMPLES_PATH/ThreadedArrayOperations/testThreadedArrayOperations +run ./$EXAMPLES_PATH/ThreadedSolarSystem/testThreadedSolarSystem \ No newline at end of file diff --git a/runtests b/runtests index b437c153f..12f6cd88b 100755 --- a/runtests +++ b/runtests @@ -17,8 +17,12 @@ cd src/tests && make # CD into test directory and call test Makef cd ../.. # CD back to main TSGL directory # RUN TESTS +run ./$TESTS_PATH/test_specs/test_specs +run ./$TESTS_PATH/test2Dvs3D/test2Dvs3D run ./$TESTS_PATH/test3DRotation/test3DRotation +run ./$TESTS_PATH/testAlphaRectangle/testAlphaRectangle run ./$TESTS_PATH/testArrows/testArrows +run ./$TESTS_PATH/testBackground/testBackground run ./$TESTS_PATH/testCircle/testCircle run ./$TESTS_PATH/testConcavePolygon/testConcavePolygon run ./$TESTS_PATH/testCone/testCone @@ -26,14 +30,20 @@ run ./$TESTS_PATH/testConvexPolygon/testConvexPolygon run ./$TESTS_PATH/testCube/testCube run ./$TESTS_PATH/testCuboid/testCuboid run ./$TESTS_PATH/testCylinder/testCylinder +run ./$TESTS_PATH/testDice/testDice +run ./$TESTS_PATH/testDiorama/testDiorama run ./$TESTS_PATH/testEllipse/testEllipse run ./$TESTS_PATH/testEllipsoid/testEllipsoid +# run ./$TESTS_PATH/testGetPixels/testGetPixels run ./$TESTS_PATH/testImage/testImage 1200 600 #Width, Height run ./$TESTS_PATH/testLines/testLines run ./$TESTS_PATH/testPrism/testPrism +run ./$TESTS_PATH/testProcedural/testProcedural +# run ./$TESTS_PATH/testProgressBar/testProgressBar run ./$TESTS_PATH/testPyramid/testPyramid run ./$TESTS_PATH/testRectangle/testRectangle run ./$TESTS_PATH/testRegularPolygon/testRegularPolygon +# run ./$TESTS_PATH/testScreenshot/testScreenshot run ./$TESTS_PATH/testSphere/testSphere run ./$TESTS_PATH/testSquare/testSquare run ./$TESTS_PATH/testStar/testStar From 0cf5886f28acc1049f9ef4ff58a588337de80c50 Mon Sep 17 00:00:00 2001 From: zcdev6 <66261100+zcdev6@users.noreply.github.com> Date: Tue, 28 Jul 2020 12:51:44 -0400 Subject: [PATCH 079/105] Add files via upload --- src/TSGL/Arrow.cpp | 80 +- src/TSGL/Background.cpp | 868 +++++++++++++-- src/TSGL/Background.h | 125 ++- src/TSGL/Canvas.cpp | 2084 ++--------------------------------- src/TSGL/Canvas.h | 220 +--- src/TSGL/ConcavePolygon.cpp | 49 +- src/TSGL/ConvexPolygon.cpp | 8 +- src/TSGL/Drawable.h | 2 +- src/TSGL/Polyline.cpp | 4 +- src/TSGL/Shader.h | 156 +++ src/TSGL/TriangleStrip.cpp | 8 +- 11 files changed, 1229 insertions(+), 2375 deletions(-) create mode 100644 src/TSGL/Shader.h diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index b8eae72c9..3c9b1e143 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -29,36 +29,36 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw isDoubleArrow = doubleArrow; isOutlined = false; attribMutex.unlock(); - addVertex(-0.4, 0.4, 0, color); - addVertex(-0.4, 1, 0, color); + addVertex(-0.4, 0.2, 0, color); + addVertex(-0.4, 0.5, 0, color); addVertex(-0.5, 0, 0, color); - addVertex(-0.4, -1, 0, color); - addVertex(-0.4, -0.4, 0, color); + addVertex(-0.4, -0.5, 0, color); + addVertex(-0.4, -0.2, 0, color); - addOutlineVertex(-0.4, 0.4, 0, GRAY); - addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.4, 0.2, 0, GRAY); + addOutlineVertex(-0.4, 0.5, 0, GRAY); addOutlineVertex(-0.5, 0, 0, GRAY); - addOutlineVertex(-0.4, -1, 0, GRAY); - addOutlineVertex(-0.4, -0.4, 0, GRAY); + addOutlineVertex(-0.4, -0.5, 0, GRAY); + addOutlineVertex(-0.4, -0.2, 0, GRAY); if( isDoubleArrow ) { - addVertex(0.4, -0.4, 0, color); - addVertex(0.4, -1, 0, color); + addVertex(0.4, -0.2, 0, color); + addVertex(0.4, -0.5, 0, color); addVertex(0.5, 0, 0, color); - addVertex(0.4, 1, 0, color); - addVertex(0.4, 0.4, 0, color); + addVertex(0.4, 0.5, 0, color); + addVertex(0.4, 0.2, 0, color); - addOutlineVertex(0.4, -0.4, 0, GRAY); - addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.4, -0.2, 0, GRAY); + addOutlineVertex(0.4, -0.5, 0, GRAY); addOutlineVertex(0.5, 0, 0, GRAY); - addOutlineVertex(0.4, 1, 0, GRAY); - addOutlineVertex(0.4, 0.4, 0, GRAY); + addOutlineVertex(0.4, 0.5, 0, GRAY); + addOutlineVertex(0.4, 0.2, 0, GRAY); } else { - addVertex(0.5, -.4, 0, color); - addVertex(0.5, .4, 0, color); + addVertex(0.5, -.2, 0, color); + addVertex(0.5, .2, 0, color); - addOutlineVertex(0.5, -.4, 0, GRAY); - addOutlineVertex(0.5, .4, 0, GRAY); + addOutlineVertex(0.5, -.2, 0, GRAY); + addOutlineVertex(0.5, .2, 0, GRAY); } } @@ -89,36 +89,36 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw isDoubleArrow = doubleArrow; isOutlined = false; attribMutex.unlock(); - addVertex(-0.4, 0.4, 0, color[0]); - addVertex(-0.4, 1, 0, color[0]); + addVertex(-0.4, 0.2, 0, color[0]); + addVertex(-0.4, 0.5, 0, color[0]); addVertex(-0.5, 0, 0, color[0]); - addVertex(-0.4, -1, 0, color[0]); - addVertex(-0.4, -0.4, 0, color[0]); + addVertex(-0.4, -0.5, 0, color[0]); + addVertex(-0.4, -0.2, 0, color[0]); - addOutlineVertex(-0.4, 0.4, 0, GRAY); - addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.4, 0.2, 0, GRAY); + addOutlineVertex(-0.4, 0.5, 0, GRAY); addOutlineVertex(-0.5, 0, 0, GRAY); - addOutlineVertex(-0.4, -1, 0, GRAY); - addOutlineVertex(-0.4, -0.4, 0, GRAY); + addOutlineVertex(-0.4, -0.5, 0, GRAY); + addOutlineVertex(-0.4, -0.2, 0, GRAY); if( isDoubleArrow ) { - addVertex(0.4, -0.4, 0, color[1]); - addVertex(0.4, -1, 0, color[1]); + addVertex(0.4, -0.2, 0, color[1]); + addVertex(0.4, -0.5, 0, color[1]); addVertex(0.5, 0, 0, color[1]); - addVertex(0.4, 1, 0, color[1]); - addVertex(0.4, 0.4, 0, color[1]); + addVertex(0.4, 0.5, 0, color[1]); + addVertex(0.4, 0.2, 0, color[1]); - addOutlineVertex(0.4, -0.4, 0, GRAY); - addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.4, -0.2, 0, GRAY); + addOutlineVertex(0.4, -0.5, 0, GRAY); addOutlineVertex(0.5, 0, 0, GRAY); - addOutlineVertex(0.4, 1, 0, GRAY); - addOutlineVertex(0.4, 0.4, 0, GRAY); + addOutlineVertex(0.4, 0.5, 0, GRAY); + addOutlineVertex(0.4, 0.2, 0, GRAY); } else { - addVertex(0.5, -0.4, 0, color[1]); - addVertex(0.5, 0.4, 0, color[1]); + addVertex(0.5, -0.2, 0, color[1]); + addVertex(0.5, 0.2, 0, color[1]); - addOutlineVertex(0.5, -.4, 0, GRAY); - addOutlineVertex(0.5, .4, 0, GRAY); + addOutlineVertex(0.5, -.2, 0, GRAY); + addOutlineVertex(0.5, .2, 0, GRAY); } attribMutex.lock(); myAlpha = (color[0].A + color[1].A) / 2; diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp index 9d4ef5b44..505927bb2 100644 --- a/src/TSGL/Background.cpp +++ b/src/TSGL/Background.cpp @@ -5,82 +5,137 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Background. * \details Explicit constructor for a Background object. - * \param x The x coordinate of the center of the Background. - * \param y The y coordinate of the center of the Background. - * \param z The z coordinate of the center of the Background. * \param width Background's width in pixels. - * \param yaw The Background's yaw, in degrees. - * \param pitch The Background's pitch, in degrees. - * \param roll The Background's roll, in degrees. + * \param height Background's height in pixels. * \param c A ColorFloat for the Background's original color. * \warning An invariant is held where if width or height isn't positive then an error message is given. - * \return A new Background with a buffer for storing the specified numbered of vertices. + * \return A new Background to which Drawables and Pixels can be drawn procedurally. */ -Background::Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c) -: Drawable(x, y, z, yaw, pitch, roll) { +Background::Background(GLint width, GLint height, const ColorFloat &clearColor) { if (width <= 0 || height <= 0) { TsglDebug("Cannot have a Background with non-positive width or height."); } attribMutex.lock(); - shaderType = TEXTURE_SHADER_TYPE; - myXScale = myWidth = width; - myYScale = myHeight = height; + myWidth = width; + myHeight = height; + myDrawables = new Array(myWidth * myHeight * 2); + baseColor = clearColor; + toClear = false; + complete = false; + newPixelsDrawn = false; + readPixelBuffer = new uint8_t[myWidth * myHeight * 3]; + for (int i = 0; i < myWidth * myHeight * 3; ++i) { + readPixelBuffer[i] = 0; + } + pixelTextureBuffer = new uint8_t[myWidth * myHeight * 4]; + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + vertices = new GLfloat[30]; - vertices[0] = vertices[1] = vertices[6] = vertices[10] = vertices[16] = vertices[20] = -0.5; // x + y - vertices[5] = vertices[11] = vertices[15] = vertices[21] = vertices[25] = vertices[26] = 0.5; // x + y + vertices[0] = vertices[11] = vertices[21] = vertices[10] = vertices[26] = vertices[20] = -0.5; // x + y + vertices[5] = vertices[1] = vertices[15] = vertices[6] = vertices[25] = vertices[16] = 0.5; // x + y vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = 0; // z vertices[3] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[29] = 0.0; // texture coord x + y vertices[4] = vertices[8] = vertices[9] = vertices[18] = vertices[19] = vertices[28] = 1.0; // texture coord x + y + attribMutex.unlock(); +} - myDrawables = new Array(myWidth * myHeight * 2); +/*! \brief Assigns Drawable shaders and initializes framebuffers within the parameter window's context. + * \details Assigns shapeShader, textShader, textureShader to parameters and initializes two framebuffers: MSAA and non-MSAA. + * \param shapeS Pointer to a shader for Shape Drawables. + * \param textS Pointer to a shader for Text Drawables. + * \param textureS Pointer to a shader for texture rendering. + * \param window GLFWwindow * within whose context the framebuffers will be initialized. + */ +void Background::init(Shader * shapeS, Shader * textS, Shader * textureS, GLFWwindow * window) { + glfwMakeContextCurrent(window); + // configure MSAA framebuffer + // -------------------------- + glGenFramebuffers(1, &multisampledFBO); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + // create a multisampled color attachment texture + glGenTextures(1, &multisampledTexture); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, myWidth, myHeight, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); + // create multisampled renderbuffer object + glGenRenderbuffers(1, &RBO); + glBindRenderbuffer(GL_RENDERBUFFER, RBO); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); - myAlpha = 1.0; + // Create a second framebuffer, non-MSAA + // -------------------------- + intermediateFBO = 0; + glGenFramebuffers(1, &intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + glGenTextures(1, &intermediateTexture); + glBindTexture(GL_TEXTURE_2D, intermediateTexture); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, myWidth, myHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,intermediateTexture, 0); - // glBindFramebuffer(GL_FRAMEBUFFER, 0); + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); - init = true; + glClear(GL_COLOR_BUFFER_BIT); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // generate a texture for the pixels + // -------------------------- + glGenTextures(1, &pixelTexture); + glBindTexture(GL_TEXTURE_2D, pixelTexture); + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + + attribMutex.lock(); + shapeShader = shapeS; + textShader = textS; + textureShader = textureS; + complete = true; attribMutex.unlock(); + glfwMakeContextCurrent(0); } /*! * \brief Draw the Background. * \details This function actually draws the Background to the Canvas. + * \note On each draw cycle, first any Drawables that have been newly added to the Background will be rendered, and then any new calls to drawPixel will be processed. */ -void Background::draw(Shader * shader) { - if (!init) { - TsglDebug("Vertex buffer is not full."); +void Background::draw() { + if (!complete) { + TsglDebug("Shaders have not been defined for this background."); return; } - // gen framebuffer - glGenFramebuffers(1, &myFramebuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFramebuffer); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - glViewport(0,0,myWidth,myHeight); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + glEnable(GL_DEPTH_TEST); - // gen texture, attach to framebuffer - glGenTextures(1, &myTexture); - glBindTexture(GL_TEXTURE_2D, myTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, myWidth, myHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, myTexture, 0); - - // render buffer object - // glGenRenderbuffers(1, &myRenderbufferObject); - // glBindRenderbuffer(GL_RENDERBUFFER, myRenderbufferObject); - // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. - // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, myRenderbufferObject); // now actually attach it - - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("ERROR::FRAMEBUFFER:: Framebuffer is not complete!"); - glClearColor(1,0,0,1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) + if (toClear) { + attribMutex.lock(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + toClear = false; + attribMutex.unlock(); + } for (unsigned int i = 0; i < myDrawables->size(); i++) { @@ -96,47 +151,64 @@ void Background::draw(Shader * shader) { } } } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + // setting up texture shaders for both pixel drawing and post-blit render selectShaders(TEXTURE_SHADER_TYPE); glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); - model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); - model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); - model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); - model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); - model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); - - unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + model = glm::scale(model, glm::vec3(myWidth, myHeight, 1)); + + unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - glBindTexture(GL_TEXTURE_2D, myTexture); // use the color attachment texture as the texture of the quad plane + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + + // check for new pixels being drawn + pixelBufferMutex.lock(); + if (newPixelsDrawn) { + glBindTexture(GL_TEXTURE_2D, pixelTexture); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixelTextureBuffer); + glGenerateMipmap(GL_TEXTURE_2D); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); + + newPixelsDrawn = false; + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + } + pixelBufferMutex.unlock(); + + // blit MSAA framebuffer to non-MSAA framebuffer's texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, myWidth, myHeight, 0, 0, myWidth, myHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDisable(GL_DEPTH_TEST); + + // render non-MSAA framebuffer's texture to default framebuffer + glBindTexture(GL_TEXTURE_2D,intermediateTexture); glPixelStorei(GL_UNPACK_ALIGNMENT,4); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + /* next two lines are very essential */ + glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES,0,6); + glEnable(GL_DEPTH_TEST); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); // Flush buffer data to the actual draw buffer - - - glDeleteTextures(1, &myTexture); - glDeleteFramebuffers(1, &myFramebuffer); -} + glViewport(0,0,myWidth,myHeight); + glReadPixels(0, 0, myWidth, myHeight, GL_RGB, GL_UNSIGNED_BYTE, readPixelBuffer); - /*! - * \brief Gets the color of the pixel drawn on the current Background at the given row and column. - * \note (0,0) signifies the top-left of the Background's texture. - * \param row The row (y-position) of the pixel to grab. - * \param col The column (x-position) of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (col,row). - */ -ColorInt Background::getPixel(int row, int col) { - return ColorInt(0,0,0,255); + myDrawables->clear(); } /*! @@ -147,12 +219,25 @@ ColorInt Background::getPixel(int row, int col) { * \param col The column (x-position) of the pixel. * \param color The color of the point. */ -void Background::drawPixel(int row, int col, ColorInt c) { - attribMutex.lock(); - - attribMutex.unlock(); +void Background::drawPixel(int x, int y, ColorInt c) { + if (abs(x) > myWidth / 2 || abs(y) > myHeight / 2) { + TsglErr("Pixel x and y coordinates must be within Background dimensions."); + return; + } + pixelBufferMutex.lock(); + x += myWidth / 2; + y += myHeight / 2; + pixelTextureBuffer[(y * myWidth + x) * 4] = c.R; + pixelTextureBuffer[(y * myWidth + x) * 4 + 1] = c.G; + pixelTextureBuffer[(y * myWidth + x) * 4 + 2] = c.B; + pixelTextureBuffer[(y * myWidth + x) * 4 + 3] = c.A; + newPixelsDrawn = true; + pixelBufferMutex.unlock(); } +/*! \brief Activates the corresponding Shader for a given Drawable. + * \param sType Unsigned int with a corresponding value for each type of Shader. + */ void Background::selectShaders(unsigned int sType) { Shader * program = 0; if (sType == TEXT_SHADER_TYPE) { @@ -198,17 +283,618 @@ void Background::selectShaders(unsigned int sType) { glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); } -void Background::defineShaders(Shader * shapeS, Shader * textS, Shader * textureS) { +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color ColorFloat for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); attribMutex.lock(); - shapeShader = shapeS; - textShader = textS; - textureShader = textureS; + myDrawables->push(a); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color Array of ColorFloats for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(a); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color Array of ColorFloats for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color ColorFloat for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color ColorFloat for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color Array of ColorFloats for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color ColorFloat for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color Array of ColorFloats for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(c); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color ColorFloat for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(e); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color Array of ColorFloats for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(e); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws an Image to the Background. + * \details Initializes a new Image based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Image's center location. + * \param y The y coordinate of the Image's center location. + * \param z The z coordinate of the Image's center location. + * \param filename String containing the file location of the Image. + * \param yaw The Image's yaw rotation. + * \param pitch The Image's pitch rotation. + * \param roll The Image's roll rotation. + * \param alpha Alpha value for the Image's transparency. + */ +void Background::drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha) { + Image * i = new Image(x,y,z,filename,width,height,yaw,pitch,roll,alpha); + attribMutex.lock(); + myDrawables->push(i); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color ColorFloat for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + attribMutex.lock(); + myDrawables->push(l); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color Array of ColorFloats for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + attribMutex.lock(); + myDrawables->push(l); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color ColorFloat for the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + attribMutex.lock(); + myDrawables->push(p); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color Array of ColorFloats corresponding to the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + attribMutex.lock(); + myDrawables->push(p); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color ColorFloat for the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(r); attribMutex.unlock(); } -void Background::drawSquare(float z) { - Square * s = new Square(0,0,z,200,0,0,0,BLUE); +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(r); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color ColorFloat for the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(r); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color Array of ColorFloats corresponding to the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(r); + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color ColorFloat for the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + attribMutex.lock(); myDrawables->push(s); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color Array of ColorFloats corresponding to the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color ColorFloat for the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color Array of ColorFloats corresponding to the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws Text to the Background. + * \details Initializes a new Text based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Text's center location. + * \param y The y coordinate of the Text's center location. + * \param z The z coordinate of the Text's center location. + * \param text Wide string containing the characters to be rendered. + * \param fontFilename String containing the filename for the font with which the Text will be rendered. + * \param fontsize The Text's fontsize in pixels. + * \param yaw The Text's yaw rotation. + * \param pitch The Text's pitch rotation. + * \param roll The Text's roll rotation. + * \param color ColorFloat for the Text. + */ +void Background::drawText(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color) { + Text * t = new Text(x,y,z,text,fontFilename,fontsize,yaw,pitch,roll,color); + attribMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color ColorFloat for the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color ColorFloat for the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + attribMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color Array of ColorFloats corresponding to the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + attribMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + attribMutex.unlock(); +} + + /*! + * \brief Gets the color of the pixel drawn on the current Background at the given x and y. + * \note (0,0) signifies the center of the Background's texture. + * \param x The x-position of the pixel to grab. + * \param y The y-position of the pixel to grab. + * \return A ColorInt containing the color of the pixel at (col,row). + */ +ColorInt Background::getPixel(int row, int col) { + int yy = (myHeight-1) - row; + int off = 3 * (yy * myWidth + col); + return ColorInt(readPixelBuffer[off], readPixelBuffer[off + 1], readPixelBuffer[off + 2], 255); +} + +/*! \brief Mutator for the color used to clear the Background when clear() is called. + * \details Sets the clear color to the parameter ColorFloat. + * \param c ColorFloat assigned to the clear color of the Background. + */ +void Background::setClearColor(ColorFloat c) { + attribMutex.lock(); + baseColor = c; + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + attribMutex.unlock(); } /*! @@ -216,7 +902,15 @@ void Background::drawSquare(float z) { */ Background::~Background() { myDrawables->clear(); + delete [] readPixelBuffer; + delete [] pixelTextureBuffer; + delete [] vertices; delete myDrawables; + glDeleteTextures(1, &pixelTexture); + glDeleteTextures(1, &intermediateFBO); + glDeleteFramebuffers(1, &intermediateTexture); + glDeleteTextures(1, &multisampledTexture); + glDeleteFramebuffers(1, &multisampledFBO); } } \ No newline at end of file diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h index 2f9086369..6dcc1fc3f 100644 --- a/src/TSGL/Background.h +++ b/src/TSGL/Background.h @@ -1,5 +1,5 @@ /* - * Background.h extends Drawable and provides a class for drawing a background. + * Background.h extends Drawable and provides a class for drawing TSGL primitives procedurally onto a background. */ #ifndef BACKGROUND_H_ @@ -7,7 +7,21 @@ #include "Drawable.h" // For extending our Shape object #include "Array.h" // Our own array for buffering drawing operations +#include "Arrow.h" +#include "Circle.h" +#include "ConcavePolygon.h" +#include "ConvexPolygon.h" +#include "Ellipse.h" +#include "Image.h" +#include "Line.h" +#include "Polyline.h" +#include "Rectangle.h" +#include "RegularPolygon.h" #include "Square.h" +#include "Star.h" +#include "Text.h" +#include "Triangle.h" +#include "TriangleStrip.h" #include "Util.h" // Needed constants and has cmath for performing math operations namespace tsgl { @@ -16,20 +30,103 @@ namespace tsgl { * \brief Draw a Background for the Canvas with colored pixels. * \details Background is a class for holding colored pixel data. */ -class Background : public Drawable { +class Background { protected: GLint myWidth, myHeight; - GLuint myTexture; - GLuint myFramebuffer; - GLuint myRenderbufferObject; + + GLuint multisampledTexture, intermediateTexture; + GLuint multisampledFBO, intermediateFBO; + GLuint RBO; + Array * myDrawables; + Shader * textShader; Shader * shapeShader; Shader * textureShader; + + ColorFloat baseColor; + bool toClear; + + uint8_t* readPixelBuffer; + + std::mutex pixelBufferMutex; + GLuint pixelTexture; + uint8_t* pixelTextureBuffer; + bool newPixelsDrawn; + + bool complete; + std::mutex attribMutex; + GLfloat * vertices; + + virtual void selectShaders(unsigned int sType); public: - Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c = WHITE); + Background(GLint width, GLint height, const ColorFloat &c = WHITE); + + virtual void init(Shader * shapeS, Shader * textS, Shader * textureS, GLFWwindow * window); + + virtual bool isInitialized() { return complete; } + + virtual void clear() { toClear = true; } + + virtual void draw(); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false, bool outlined = false); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); - virtual void draw(Shader * shader); + virtual void drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha = 1.0f); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawPixel(int x, int y, ColorInt c); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja = false, bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja = false, bool outlined = false); + + virtual void drawText(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); /*! * \brief Accessor for the width of the Background. @@ -43,15 +140,15 @@ class Background : public Drawable { */ virtual GLint getHeight() { return myHeight; } - virtual ColorInt getPixel(int row, int col); + virtual ColorInt getPixel(int x, int y); - virtual void drawPixel(int row, int col, ColorInt c); - - virtual void selectShaders(unsigned int sType); - - virtual void defineShaders(Shader * shapeS, Shader * textS, Shader * textureS); + /*! + * \brief Accessor for color which is used to clear the Background when clear() is called. + * \details Returns a ColorInt corresponding to the clear color of the Background. + */ + virtual ColorFloat getClearColor() { return baseColor; } - virtual void drawSquare(float z); + virtual void setClearColor(ColorFloat c); virtual ~Background(); }; diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 5acadf9f0..0ad737947 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -82,7 +82,6 @@ static const GLchar* textureFragmentShader = "FragColor = texture(texture1, TexCoords) * vec4(1.0,1.0,1.0,alpha);" "}"; -int Canvas::drawBuffer = GL_FRONT_LEFT; bool Canvas::glfwIsReady = false; std::mutex Canvas::glfwMutex; GLFWvidmode const* Canvas::monInfo; @@ -98,7 +97,7 @@ unsigned Canvas::openCanvases = 0; * have a 4:3 aspect ratio. */ Canvas::Canvas(double timerLength) { - init(-1, -1, -1, -1, -1, "", timerLength); + init(-1, -1, -1, -1, -1, "", GRAY, timerLength); } /*! @@ -113,8 +112,8 @@ Canvas::Canvas(double timerLength) { * A value less than or equal to 0 sets it to automatic. * \return A new Canvas with the specified position, dimensions, title, and draw cycle length. */ -Canvas::Canvas(int x, int y, int width, int height, std::string title, double timerLength) { - init(x, y, width, height, width*height*2, title, timerLength); +Canvas::Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor, double timerLength) { + init(x, y, width, height, width*height*2, title, backgroundColor, timerLength); } /*! @@ -124,12 +123,11 @@ Canvas::Canvas(int x, int y, int width, int height, std::string title, double ti */ Canvas::~Canvas() { // Free our pointer memory - delete myDrawables; - delete drawableBuffer; - delete[] proceduralBuffer; delete drawTimer; - delete[] vertexData; delete [] screenBuffer; + if (defaultBackground) { + delete myBackground; + } if (--openCanvases == 0) { glfwIsReady = false; glfwTerminate(); // Terminate GLFW @@ -171,9 +169,9 @@ void Canvas::buttonCallback(GLFWwindow* window, int button, int action, int mods * \brief Clears the Canvas. * \details This function clears the screen to the color specified in setBackgroundColor(). */ -// void Canvas::clearProcedural() { -// drawRectangle(0,0,getWindowWidth(),getWindowHeight(),getBackgroundColor()); -// } +void Canvas::clearBackground() { + myBackground->clear(); +} /*! * \brief Closes the Canvas window. @@ -199,7 +197,6 @@ void Canvas::close() { void Canvas::add(Drawable * shapePtr) { objectMutex.lock(); objectBuffer.push_back(shapePtr); - objectBufferEmpty = false; objectMutex.unlock(); } @@ -245,15 +242,6 @@ void Canvas::draw() glfwGetFramebufferSize(window, &fbw, &fbh); int scaling = round((1.0f*fbw)/winWidth); - if (hasStereo) - Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); - else - Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); - - setBackgroundColor(bgcolor); //Set our initial clear / background color - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { drawTimer->sleep(true); @@ -261,7 +249,6 @@ void Canvas::draw() syncMutex.lock(); #ifdef __APPLE__ - // leftWindowIndex = 0; windowMutex.lock(); #endif glfwMakeContextCurrent(window); @@ -270,10 +257,14 @@ void Canvas::draw() if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; std::cout.flush(); - // set it up so draw calls write into the framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, multisampledFBO); - glEnable(GL_DEPTH_TEST); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + // clear default framebuffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // if background initialized draw it using its multisampled framebuffer + if (myBackground) + if (myBackground->isInitialized()) { + myBackground->draw(); + } // Scale to window size GLint windowWidth, windowHeight; @@ -282,12 +273,8 @@ void Canvas::draw() winWidth = windowWidth; winHeight = windowHeight; - // Draw stuff - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (objectBuffer.size() > 0) { - // sort between opaques and transparents and then sort by center z. not perfect, but pretty good. - // depth buffer takes care of the rest. + // sort between opaques and transparents and then sort by center z. depth buffer takes care of the rest. not perfect, but good. std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { if (a->getAlpha() == 1.0 && b->getAlpha() != 1.0) return true; @@ -309,53 +296,14 @@ void Canvas::draw() } } } - } else { - objectBufferEmpty = true; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); - glBlitFramebuffer(0, 0, winWidth, winHeight, 0, 0, winWidth, winHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - // actually render everything in the framebuffer to the screen - glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - glDisable(GL_DEPTH_TEST); - - selectShaders(TEXTURE_SHADER_TYPE); - - unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); - glUniform1f(alphaLoc, 1.0f); - - const float vertices[30] = { - -winWidth/2,-winHeight/2,0,0,0, - winWidth/2,-winHeight/2,0,1,0, - -winWidth/2, winHeight/2,0,0,1, - winWidth/2,-winHeight/2,0,1,0, - -winWidth/2, winHeight/2,0,0,1, - winWidth/2, winHeight/2,0,1,1 - }; - glBindTexture(GL_TEXTURE_2D,renderedTexture); - /* these 5 lines don't seem to do anything */ - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - /* next two lines are very essential */ - glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLES,0,6); - glFlush(); // Flush buffer data to the actual draw buffer - - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - - // set it up so TSGL reads from the framebuffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - // screenshots and testing - // read from the framebuffer into the screenbuffer - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); + // glFlush(); // this should hopefully fix the lines in screenshot() bug. If not here, one line up. if (toRecord > 0) { + // Update our screenBuffer copy with the default framebuffer + glViewport(0,0,winWidth*scaling,winHeight*scaling); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); screenShot(); --toRecord; } @@ -378,1281 +326,6 @@ void Canvas::draw() } } -/* void Canvas::draw() { - // Reset the window - glfwSetWindowShouldClose(window, GL_FALSE); - - // Get actual framebuffer size and adjust scaling accordingly - int fbw, fbh; - glfwGetFramebufferSize(window, &fbw, &fbh); - int scaling = round((1.0f*fbw)/winWidth); - - if (hasStereo) - Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); - else - Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); - - - setBackgroundColor(bgcolor); //Set our initial clear / background color - // glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - readyToDraw = true; - bool newThingDrawn = true; //Always draw the first frame - int frame = 0; - - // Start the drawing loop - for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { - drawTimer->sleep(true); - - syncMutex.lock(); - - int leftWindowIndex; - - #ifdef __APPLE__ - leftWindowIndex = 0; - windowMutex.lock(); - #else - leftWindowIndex = -1; - #endif - glfwMakeContextCurrent(window); // We're drawing to window as soon as it's created - - realFPS = round(1 / drawTimer->getTimeBetweenSleeps()); - if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; - std::cout.flush(); - - bufferMutex.lock(); // Time to flush our buffer - if (drawableBuffer->size() > 0) { // But only if there is anything to flush - newThingDrawn = true; - for (unsigned int i = 0; i < drawableBuffer->size(); i++) - myDrawables->push((*drawableBuffer)[i]); - drawableBuffer->shallowClear(); // We want to clear the buffer but not delete those objects as we still need to draw them - } - bufferMutex.unlock(); - - int pos = pointBufferPosition; - int posLast = pointLastPosition; - - if (loopAround || pos != posLast) - newThingDrawn = true; - - if (newThingDrawn || !objectBufferEmpty) { - - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - glViewport(0,0,winWidth,winHeight); - - if (frame == 0 || !objectBufferEmpty) { - glClear(GL_COLOR_BUFFER_BIT); - if(frame > 1) { - selectShaders(true); - loader.drawGLtextureFromBuffer(proceduralBuffer, leftWindowIndex, 0, winWidth, winHeight, GL_RGB); - selectShaders(false); - } - } - - if(frame > 0) { - unsigned int size = myDrawables->size(); - for (unsigned int i = 0; i < size; i++) { - Drawable* d = (*myDrawables)[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - selectShaders(true); - d->draw(); - selectShaders(false); - } - } - } - - if (loopAround) { - newThingDrawn = true; - int toend = myDrawables->capacity() - posLast; - glBufferData(GL_ARRAY_BUFFER, toend * 6 * sizeof(float), - &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, toend); - posLast = 0; - loopAround = false; - } - int pbsize = pos - posLast; - if (pbsize > 0) { - newThingDrawn = true; - glBufferData(GL_ARRAY_BUFFER, pbsize * 6 * sizeof(float), &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, pbsize); - } - pointLastPosition = pos; - } - - if(frame > 0) { - if(newThingDrawn) { - glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, proceduralBuffer); - } - // Reset drawn status for the next frame - newThingDrawn = false; - frame = 2; - } else { - frame = 1; - } - - if (objectBuffer.size() > 0) { - for (unsigned int i = 0; i < objectBuffer.size(); i++) { - Drawable* d = objectBuffer[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - selectShaders(true); - d->draw(); - selectShaders(false); - } - } - } - } else { - objectBufferEmpty = true; - } - } - - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - if(frame > 1) { - myDrawables->clear(); // Clear our buffer of shapes to be drawn - } - - // not sure what the point of this chunk is. - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // screenshots and testing - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); - if (toRecord > 0) { - screenShot(); - --toRecord; - } - - // very vital - glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - // apparently not very vital at all - glDrawBuffer(drawBuffer); - - selectShaders(true); - const float vertices[32] = { - 0, 0, 1,1,1,1,0,1, - winWidth,0, 1,1,1,1,1,1, - 0, winHeight,1,1,1,1,0,0, - winWidth,winHeight,1,1,1,1,1,0 - }; - glBindTexture(GL_TEXTURE_2D,renderedTexture); - // these 5 lines don't seem to do anything - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - // next two lines are very essential - glBufferData(GL_ARRAY_BUFFER,32*sizeof(float),vertices,GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP,0,4); - glFlush(); // Flush buffer data to the actual draw buffer - glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - - selectShaders(false); - - #ifndef __APPLE__ - glfwPollEvents(); // Handle any I/O - #endif - glfwGetCursorPos(window, &mouseX, &mouseY); - glfwMakeContextCurrent(NULL); // We're drawing to window as soon as it's created - #ifdef __APPLE__ - windowMutex.unlock(); - #endif - - syncMutex.unlock(); - - if (toClose) glfwSetWindowShouldClose(window, GL_TRUE); - } -} */ - -// /*! -// * \brief Draws a monocolored arrow. -// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status -// * \param x1 The x coordinate of the first endpoint. -// * \param y1 The y coordinate of the first endpoint. -// * \param x2 The x coordinate of the second endpoint. -// * \param y2 The y coordinate of the second endpoint. -// * \param color A single color for the arrow. -// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. -// */ -// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow) { -// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); -// drawDrawable(arrow); -// } - -// /*! -// * \brief Draws a multicolored arrow. -// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status -// * \param x1 The x coordinate of the first endpoint. -// * \param y1 The y coordinate of the first endpoint. -// * \param x2 The x coordinate of the second endpoint. -// * \param y2 The y coordinate of the second endpoint. -// * \param color An array of colors for the circle. -// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. -// */ -// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow) { -// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); -// drawDrawable(arrow); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined circle. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param color A single color for the circle. -// * \param filled Whether the circle should be filled -// * (set to true by default). -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color, bool filled) { -// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined circle. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param color An array of colors for the circle. -// * \param filled Whether the circle should be filled -// * (set to true by default). -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color[], bool filled) { -// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with different monocolored fill and outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor A single color for circle's fill vertices. -// * \param outlineColor A single color for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with multicolored fill and monocolored outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor An array of colors for circle's fill vertices. -// * \param outlineColor A single color for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with monocolored fill and multicolored outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor A single color for circle's fill vertices. -// * \param outlineColor An array of colors for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with different multicolored fill and outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor An array of colors for circle's fill vertices. -// * \param outlineColor An array of colors for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined concave polygon. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param color A single color for the said vertices. -// * \param filled Whether the ConcavePolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined concave polygon. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the ConcavePolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with different monocolored fill and outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with multicolored fill and monocolored outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with monocolored fill and multicolored outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with different multicolored fill and outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined convex polygon. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param color A single color for the said vertices. -// * \param filled Whether the ConvexPolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined convex polygon. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the ConvexPolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with different monocolored fill and outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with multicolored fill and monocolored outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with monocolored fill and multicolored outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with different multicolored fill and outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a Drawable object -// * \details This function pushes any Drawable object onto the drawable buffer -// * \param d The Drawable object to be drawn -// * \note protected method -// */ -// void Canvas::drawDrawable(Drawable* d) { -// if (!started) { -// TsglDebug("No drawing before Canvas is started! Ignoring draw request."); -// return; -// } -// while (!readyToDraw) -// sleep(); -// bufferMutex.lock(); -// drawableBuffer->push(d); // Push it onto our drawing buffer -// bufferMutex.unlock(); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined ellipse. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param color A single color for ellipse. -// * \param filled Whether the ellipse should be filled -// * (set to true by default). -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined ellipse. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param color An array of colors for ellipse. -// * \param filled Whether the ellipse should be filled -// * (set to true by default). -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with different monocolored fill and outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor A single color for ellipse's fill vertices. -// * \param outlineColor A single color for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with multicolored fill and monocolored outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor An array of colors for ellipse's fill vertices. -// * \param outlineColor A single color for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with monocolored fill and multicolored outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor A single color for ellipse's fill vertices. -// * \param outlineColor An array of colors for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with different multicolored fill and outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor An array of colors for ellipse's fill vertices. -// * \param outlineColor An array of colors for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws an image. -// * \details This function draws an Image with the given coordinates and dimensions. -// * \param filename The name of the file to load the image from. -// * \param x The x coordinate of the Image's left edge. -// * \param y The y coordinate of the Image's top edge. -// * \param width The width of the Image. -// * \param height The height of the Image. -// * \param alpha The alpha with which to draw the Image -// * \param rotation Rotation of the Image in radians clockwise. -// */ -// void Canvas::drawImage(std::string filename, int x, int y, int width, int height, float alpha, float rotation) { -// Image* im = new Image(filename, loader, x, y, width, height, alpha); // Creates the Image with the specified coordinates -// im->setRotation(rotation); -// drawDrawable(im); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored line. -// * \details This function draws a Line at the given coordinates with the given color. -// * \param x1 The x position of the start of the line. -// * \param y1 The y position of the start of the line. -// * \param x2 The x position of the end of the line. -// * \param y2 The y position of the end of the line. -// * \param color The color of the line -// * (set to BLACK by default). -// * \param rotation Rotation of the line in radians clockwise. -// */ -// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color, float rotation) { -// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color -// l->setRotation(rotation); -// drawDrawable(l); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored line. -// * \details This function draws a Line at the given coordinates with the given color. -// * \param x1 The x position of the start of the line. -// * \param y1 The y position of the start of the line. -// * \param x2 The x position of the end of the line. -// * \param y2 The y position of the end of the line. -// * \param color A color array for the line. -// * \param rotation Rotation of the line in radians clockwise. -// */ -// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation) { -// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color -// l->setRotation(rotation); -// drawDrawable(l); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a single pixel, specified in row,column format. -// * \details This function draws a pixel at the given screen coordinates with the given color. -// * \note (0,0) signifies the top-left of the screen when working with a Canvas object. -// * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. -// * \param row The row (y-position) of the pixel. -// * \param col The column (x-position) of the pixel. -// * \param color The color of the point (set to BLACK by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \see drawPoint() -// */ -// inline void Canvas::drawPixel(int row, int col, ColorFloat color) { -// drawPoint(col, row, color); -// } - -// /*! -// * \brief Draws a single pixel, specified in x,y format. -// * \details This function draws a pixel at the given Cartesian coordinates with the given color. -// * \note (0,0) signifies the left-top of the screen when working with a Canvas object. -// * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. -// * \param x The x position of the point. -// * \param y The y position of the point. -// * \param color The color of the point (set to BLACK by default). -// * \see drawPixel() -// */ -// void Canvas::drawPoint(int x, int y, ColorFloat color) { -// pointArrayMutex.lock(); -// if (pointBufferPosition >= myDrawables->capacity()) { -// loopAround = true; -// pointBufferPosition = 0; -// } -// int tempPos = pointBufferPosition * 6; -// pointBufferPosition++; - -// float atioff = atiCard ? 0.5f : 0.0f; -// vertexData[tempPos] = x; -// vertexData[tempPos + 1] = y+atioff; -// vertexData[tempPos + 2] = color.R; -// vertexData[tempPos + 3] = color.G; -// vertexData[tempPos + 4] = color.B; -// vertexData[tempPos + 5] = color.A; -// pointArrayMutex.unlock(); -// } - -// /*! -// * \brief Draws a monocolored series of connected lines. -// * \details This function draws Polyline at the given coordinates with the given color. -// * \param size The number of vertices of the polyline. -// * \param x An array of the x positions of the polyline's vertices. -// * \param y An array of the y positions of the polyline's vertices. -// * \param color A color for the Polyline. -// * \param rotation Rotation of the Polyline in radians clockwise. -// */ -// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation) { -// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored series of connected lines. -// * \details This function draws Polyline at the given coordinates with the given color. -// * \param size The number of vertices of the polyline. -// * \param x An array of the x positions of the polyline's vertices. -// * \param y An array of the y positions of the polyline's vertices. -// * \param color A color array for the Polyline. -// * \param rotation Rotation of the Polyline in radians clockwise. -// */ -// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation) { -// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a progress bar. -// * \details This function draws a previously created ProgressBar to the Canvas, as -// * specified in that ProgressBar's constructor. -// * \param p A pointer to a ProgressBar. -// * \note There is no equivalent function for CartesianCanvas. If you'd like to draw -// * a ProgressBar on a CartesianCanvas, you can still use this function, but you must -// * use absolute Canvas coordinates rather than the scaled CartesianCanvas coordinates. -// */ -// void Canvas::drawProgress(ProgressBar* p) { -// for (int i = 0; i < p->getSegs(); ++i) { -// drawDrawable(p->getRect(i)); -// drawDrawable(p->getBorder(i)); -// } -// } - -// /*! -// * \brief Draws a monocolored filled or outlined rectangle. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param color A single color for Rectangle. -// * \param filled Whether the Rectangle should be filled -// * (set to true by default). -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined rectangle. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param color An array of colors for Rectangle. -// * \param filled Whether the Rectangle should be filled -// * (set to true by default). -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with different monocolored fill and outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor A single color for Rectangle's fill vertices. -// * \param outlineColor A single color for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with multicolored fill and monocolored outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor An array of colors for Rectangle's fill vertices. -// * \param outlineColor A single color for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with monocolored fill and multicolored outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor A single color for Rectangle's fill vertices. -// * \param outlineColor An array of colors for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with different multicolored fill and outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor An array of colors for Rectangle's fill vertices. -// * \param outlineColor An array of colors for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined regular polygon. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param color A single color for RegularPolygon. -// * \param filled Whether the regular polygon should be filled -// * (set to true by default). -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color, bool filled, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined regular polygon. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and color -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param color An array of colors for RegularPolygon. -// * \param filled Whether the regular polygon should be filled -// * (set to true by default). -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with different monocolored fill and outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor A single color for RegularPolygon's fill vertices. -// * \param outlineColor A single color for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with multicolored fill and monocolored outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor An array of colors for RegularPolygon's fill vertices. -// * \param outlineColor A single color for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with monocolored fill and multicolored outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor A single color for RegularPolygon's fill vertices. -// * \param outlineColor An array of colors for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with different multicolored fill and outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor An array of colors for RegularPolygon's fill vertices. -// * \param outlineColor An array of colors for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined square. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param color A single color for Square. -// * \param filled Whether the Square should be filled -// * (set to true by default). -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled, float rotation) { -// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined Square. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param color An array of colors for Square. -// * \param filled Whether the Square should be filled -// * (set to true by default). -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled, float rotation) { -// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with different monocolored fill and outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor A single color for Square's fill vertices. -// * \param outlineColor A single color for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with multicolored fill and monocolored outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor An array of colors for Square's fill vertices. -// * \param outlineColor A single color for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with monocolored fill and multicolored outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor A single color for Square's fill vertices. -// * \param outlineColor An array of colors for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with different multicolored fill and outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor An array of colors for Square's fill vertices. -// * \param outlineColor An array of colors for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - - -// /*! -// * \brief Draws a monocolored filled or outlined star. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param color A single color or array of colors for the star vertices. -// * \param filled Whether the star should be filled -// * (set to true by default). -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color, bool filled, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, color, filled, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined star. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param color A single color or array of colors for the star vertices. -// * \param filled Whether the star should be filled -// * (set to true by default). -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color[], bool filled, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, color, filled, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with different monocolored fill and outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with multicolored fill and monocolored outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with monocolored fill and multicolored outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with different multicolored fill and outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - // /*! // * \brief Draw a string of text. // * \details This function draws a given string of Text at the given coordinates with the given color. @@ -1669,257 +342,24 @@ void Canvas::draw() // drawText(ws, x, y, size, color, fontFileName, rotation); // } -// /*! -// * \brief Draws a UTF8-encoded string of text. -// * \details This function draws a given string of UTF-8 encoded Text at the given coordinates with the given color. -// * \param text The UTF8-encoded string to draw. -// * \param x The x coordinate of the text's left bound. -// * \param y The y coordinate of the text's left bound. -// * \param size The size of the text in pixels. -// * \param color The color of the Text (set to BLACK by default). -// * \param rotation Rotation of the Text in radians clockwise. -// * \note Identical to the drawText(std::string, ...) aside from the first parameter. -// * \see drawText(std::string s, int x, int y, unsigned size, ColorFloat color = BLACK). -// */ -// void Canvas::drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color, std::string fontFileName, float rotation) { -// Text* t = new Text(text, x, y, size, color); // Creates the Point with the specified coordinates and color -// if(fontFileName != defaultFontFileName && fontFileName != "") { -// t->setFont(fontFileName); -// } else { -// if(defaultFontFileName != "") { -// t->setFont(defaultFontFileName); -// } -// } -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined triangle. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param color A single color for the Triangle vertices. -// * \param filled Whether the Triangle should be filled (set to true by default). -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined triangle. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param color An array of colors for the Triangle vertices. -// * \param filled Whether the Triangle should be filled (set to true by default). -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with different monocolored fill and outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor A single color for the Triangle's fill vertices. -// * \param outlineColor A single color for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with multicolored fill and monocolored outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor An array of colors for the Triangle's fill vertices. -// * \param outlineColor A single color for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with monocolored fill and multicolored outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor A single color for the Triangle's fill vertices. -// * \param outlineColor An array of colors for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with different multicolored fill and outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor An array of colors for the Triangle's fill vertices. -// * \param outlineColor An array of colors for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled or outlined monocolored triangle strip. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param color A single color for the vertices. -// * \param filled Whether the triangle strip should be filled (true) or not (false). -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled or outlined multicolored triangle strip. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the triangle strip should be filled (true) or not (false). -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with different monocolored fill and outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with multicolored fill and monocolored outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with monocolored fill and multicolored outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with different multicolored fill and outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - void Canvas::errorCallback(int error, const char* string) { fprintf(stderr, "%i: %s\n", error, string); } + /*! + * \brief Accessor for the current background. + * \return The Background that the Canvas draws when draw() is called. + */ +Background * Canvas::getBackground() { + return myBackground; +} + /*! * \brief Accessor for the current background color. * \return The color that the Canvas clears to when clear() is called. */ ColorFloat Canvas::getBackgroundColor() { - return bgcolor; + return myBackground->getClearColor(); } /*! @@ -1957,14 +397,6 @@ float Canvas::getFPS() { return realFPS; } - /*! - * \brief Accessor for window's closed status. - * \return Whether the window is still open (that is, the user has not closed it). - */ -bool Canvas::isOpen() { - return !isFinished; -} - /*! * \brief Accessor for the mouse's x-position. * \return The x coordinates of the mouse on the Canvas. @@ -1981,42 +413,6 @@ int Canvas::getMouseY() { return mouseY; } - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in row,column format. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas. - * \note getPixel() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param row The row (y-position) of the pixel to grab. - * \param col The column (x-position) of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (col,row). - */ -ColorInt Canvas::getPixel(int row, int col) { - return getPoint(col,row); -} - - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in x,y format. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas. - * \note getPoint() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param x The x position of the pixel to grab. - * \param y The y position of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (x, y). - */ -ColorInt Canvas::getPoint(int x, int y) { - int yy; - //if (atiCard) - // yy = (winHeight) - y; //glReadPixels starts from the bottom left, and we have no way to change that... - //else - yy = (winHeight-1) - y; - int off = 3 * (yy * winWidthPadded + x); - return ColorInt(screenBuffer[off], screenBuffer[off + 1], screenBuffer[off + 2], 255); -} - /*! * \brief Accessor for the number of theoretical draw cycles that have elapsed * \details This function returns the time elapsed since the Canvas has been opened divided @@ -2124,7 +520,7 @@ void Canvas::handleIO() { #endif } -void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string title, double timerLength) { +void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string title, ColorFloat backgroundColor, double timerLength) { ++openCanvases; if (ww == -1) @@ -2135,11 +531,10 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti winTitle = title; winWidth = ww, winHeight = hh; - aspect = (float) winWidth / winHeight; + // aspect = (float) winWidth / winHeight; keyDown = false; toClose = false; windowClosed = false; - readyToDraw = false; frameCounter = 0; syncMutexLocked = 0; syncMutexOwner = -1; @@ -2148,47 +543,36 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti if (padwidth > 0) padwidth = 4-padwidth; winWidthPadded = winWidth + padwidth; - bufferSize = 3 * (winWidthPadded+1) * winHeight; - proceduralBufferSize = 4 * winWidth * winHeight; - screenBuffer = new uint8_t[bufferSize]; - proceduralBuffer = new GLubyte[proceduralBufferSize]; - for (unsigned i = 0; i < bufferSize; ++i) { + screenBuffer = new uint8_t[3 * (winWidthPadded+1) * winHeight]; + for (int i = 0; i < 3 * (winWidthPadded+1) * winHeight; ++i) { screenBuffer[i] = 0; } - for (unsigned i = 0; i < proceduralBufferSize; i++) { - proceduralBuffer[i] = 255; - } started = false; // We haven't started the window yet monitorX = xx; monitorY = yy; - myDrawables = new Array(b); // Initialize myDrawables - drawableBuffer = new Array(b); - // objectBuffer = new Array(b); - vertexData = new float[6 * b]; // Buffer for vertexes for points showFPS = false; // Set debugging FPS to false isFinished = false; // We're not done rendering - pointBufferPosition = pointLastPosition = 0; - loopAround = false; toRecord = 0; - objectBufferEmpty = true; - bgcolor = GRAY; window = nullptr; + defaultBackground = true; + myBackground = nullptr; + drawTimer = new Timer((timerLength > 0.0f) ? timerLength : FRAME); for (int i = 0; i <= GLFW_KEY_LAST * 2 + 1; i++) boundKeys[i++] = nullptr; - defaultFontFileName = ""; - initGlfw(); #ifndef _WIN32 initWindow(); initGlew(); glfwMakeContextCurrent(NULL); // Reset the context #endif + initGl(); + initBackground(backgroundColor); } void Canvas::initGl() { @@ -2214,14 +598,6 @@ void Canvas::initGl() { toClose = true; }); - unsigned char stereo[1] = {5}, dbuff[1] = {5}; - int aux[1] = {5}; - glGetBooleanv(GL_STEREO,stereo); - glGetBooleanv(GL_DOUBLEBUFFER,dbuff); - glGetIntegerv(GL_AUX_BUFFERS,aux); - hasStereo = ((int)stereo[0] > 0); - hasBackbuffer = ((int)dbuff[0] > 0); - glfwMakeContextCurrent(NULL); // Reset the context } @@ -2257,6 +633,12 @@ void Canvas::initGlew() { glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); + textShader = new Shader(textVertexShader, textFragmentShader); + + shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); + + textureShader = new Shader(textureVertexShader, textureFragmentShader); + char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ char *res = realpath(".", buf); if (res) { @@ -2265,46 +647,6 @@ void Canvas::initGlew() { perror("realpath"); exit(EXIT_FAILURE); } - - textShader = new Shader(textVertexShader, textFragmentShader); - - shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); - - textureShader = new Shader(textureVertexShader, textureFragmentShader); - - // configure MSAA framebuffer - // -------------------------- - glGenFramebuffers(1, &multisampledFBO); - glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); - // create a multisampled color attachment texture - glGenTextures(1, &multisampledTexture); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, winWidth, winHeight, GL_TRUE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); - // create multisampled renderbuffer object - unsigned int rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, winWidth, winHeight); // use a single renderbuffer object for both a depth AND stencil buffer. - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it - - // Create a second framebuffer - intermediateFBO = 0; - glGenFramebuffers(1, &intermediateFBO); - glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); - // The texture we're going to render to - glGenTextures(1, &renderedTexture); - glBindTexture(GL_TEXTURE_2D, renderedTexture); - glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // Set "renderedTexture" as our colour attachement #0 - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,renderedTexture, 0); - - // Always check that our framebuffer is ok - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("FRAMEBUFFER CREATION FAILED"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); } void Canvas::initGlfw() { @@ -2315,6 +657,13 @@ void Canvas::initGlfw() { } } +void Canvas::initBackground(ColorFloat bgcolor) { + if (!myBackground) { + myBackground = new Background(winWidth, winHeight, bgcolor); + myBackground->init(shapeShader, textShader, textureShader, window); + } +} + void Canvas::initWindow() { glfwSetErrorCallback(errorCallback); @@ -2330,7 +679,7 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window - glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer + // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); @@ -2374,6 +723,14 @@ void Canvas::initWindow() { printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); } + /*! + * \brief Accessor for window's closed status. + * \return Whether the window is still open (that is, the user has not closed it). + */ +bool Canvas::isOpen() { + return !isFinished; +} + void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { buttonCallback(window, key, action, mods); } @@ -2573,6 +930,22 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { if (can->scrollFunction) can->scrollFunction(xpos, ypos); } + /*! + * \brief Mutator for the Canvas Background. + * \details This function sets the Background which Canvas will draw. + * \param background A pointer to the new Background value which will be assigned to myBackground. + * \param previouslySet Boolean indicating if background has been previously set for this Canvas. + */ +void Canvas::setBackground(Background * background, bool previouslySet) { + if (myBackground != background) { + defaultBackground = false; + myBackground = background; + if (!previouslySet) { + background->init(shapeShader, textShader, textureShader, window); + } + } +} + /*! * \brief Mutator for the background color. * \details This function sets the clear color for when Canvas::clear() is called. @@ -2580,29 +953,13 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { * \note The alpha channel of the color is ignored. */ void Canvas::setBackgroundColor(ColorFloat color) { - bgcolor = color; if (window != nullptr) { glfwMakeContextCurrent(window); - glClearColor(color.R,color.G,color.B,color.A); + myBackground->setClearColor(color); glfwMakeContextCurrent(NULL); } } -void Canvas::setDrawBuffer(int buffer) { - Canvas::drawBuffer = buffer; -} - - /*! - * \brief Mutator for the currently loaded font. - * \details This function sets the font with the specified filename into memory. - * Subsequent calls to drawText() will use this font to print. - * \param filename The filename of the font to load. - * \note Supports all font types that FreeType supports. - */ -void Canvas::setFont(std::string filename) { - defaultFontFileName = filename; -} - /*! * \brief Mutator for showing the FPS. * \param b Whether to print the FPS to stdout every draw cycle (for debugging purposes). @@ -2676,14 +1033,12 @@ int Canvas::start() { #ifdef __APPLE__ void* Canvas::startDrawing(void* cPtr) { Canvas* c = (Canvas*)cPtr; - c->initGl(); c->draw(); c->isFinished = true; pthread_exit(NULL); } #else void Canvas::startDrawing(Canvas *c) { - c->initGl(); c->draw(); c->isFinished = true; glfwDestroyWindow(c->window); @@ -2789,283 +1144,4 @@ int Canvas::wait() { return 0; } - -void Canvas::setBackground(Background * background) { - myBackground = background; - background->defineShaders(shapeShader, textShader, textureShader); -} - -//-----------------Unit testing------------------------------------------------------- - /*! - * \brief Runs unit tests for the Canvas. - */ -// void Canvas::runTests() { -// TsglDebug("Testing Canvas class..."); -// Canvas c1(0, 0, 500, 500, "", FRAME); -// c1.setBackgroundColor(WHITE); -// c1.start(); -// tsglAssert(testFilledDraw(c1), "Unit test for filled draw failed!"); -// tsglAssert(testLine(c1), "Unit test for line failed!"); -// // tsglAssert(testAccessors(c1), "Unit test for accessors failed!"); -// tsglAssert(testDrawImage(c1), "Unit test for drawing images failed!"); -// c1.stop(); -// TsglDebug("Unit tests for Canvas complete."); -// std::cout << std::endl; -// } - -// //Similar format is used for the remaining unit tests -// bool Canvas::testFilledDraw(Canvas& can) { -// int passed = 0; //Passed tests -// int failed = 0; //Failed tests -// ColorInt red(255, 0, 0); //Fill color -// can.drawCircle(250, 250, 50, red, true); //Draw filled shape -// can.sleepFor(1); - -// //Test 1: Get middle pixel and see if its red. -// if(can.getPixel(250, 250) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, middle pixel for testFilledDraw() failed!"); -// } - -// //Test 2: Get leftmost and rightmost pixel of the circle -// //Have to add or subtract 1 from the y so that you can get the correct pixel (center radius is 1. No 0 radius). -// if(can.getPixel(250, 201) == red && can.getPixel(250, 299) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 2, leftmost and rightmost pixel for testFilledDraw() failed!"); -// } - -// //Test 3: Outside pixels shouldn't equal inside pixels -// int test = 0; -// //Single pixel.... -// if(can.getPixel(1, 1) != red) { -// //Multiple pixels.... -// for(int i = 201; i <= 299; i++) { -// if(can.getPixel(1, i) != red) { -// test++; -// } -// } -// //Results of multiple pixels... -// if(test == 99) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 3, outside != inside, Multiple pixels for testFilledDraw() failed!"); -// } -// } else { -// failed++; -// TsglErr("Test 3, outside != inside, Single pixel for testFilledDraw() failed!"); -// } - -// //Test 4: A LOT of the pixels on the inside should be red -// int count = 0; -// for(int i = 201; i <= 299; i++) { -// if(can.getPixel(250, i) == red) { -// count++; -// } -// } - -// //Now check the count, should be 99 -// if(count == 99) { -// passed++; -// } else { -// failed++; -// std::cout << "Count: " << count << std::endl; -// TsglErr("Test 4, multiple pixels for testFilledDraw() failed!"); -// } - -// //Determine if we passed all four tests or not, Results: -// if(passed == 4 && failed == 0) { -// // can.clearProcedural(); -// TsglDebug("Unit test for drawing filled shapes passed!"); -// return true; -// } else { -// // can.clearProcedural(); -// TsglErr("This many passed for testFilledDraw(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testFilledDraw(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } - -// bool Canvas::testLine(Canvas & can) { -// int passed = 0; -// int failed = 0; -// can.drawLine(0, 0, 250, 250, BLACK); //Diagonal line -// can.drawLine(253, 253, 400, 253); //Straight line -// can.sleepFor(1); -// ColorInt black(0, 0, 0); -// //Test 1: Near the ending endpoint? (Diagonal) -// if(can.getPoint(249, 249) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, Near the ending endpoint? for testLine() failed!"); -// } - -// //Test 2: Somewhere in the middle? (Diagonal) -// if(can.getPoint(155, 155) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 2, Somewhere in the middle? for testLine() failed!"); -// } - -// //Test 3: Near the starting endpoint? (Diagonal) -// if(can.getPoint(15, 15) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 3, Near the starting endpoint? for testLine() failed!"); -// } - -// //Test 4: An entire line? (Straight) -// int count = 0; -// for(int i = 253; i <= 399; i++) { -// if(can.getPoint(i, 253) == black) { -// count++; -// } -// } - -// //Check the results of the Straight line test -// if(count == 147) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 4, An entire line? (Straight) for testLine() failed!"); -// } - -// //Results: -// if(passed == 4 && failed == 0) { -// // can.clearProcedural(); -// TsglDebug("Unit test for line passed!"); -// return true; -// } else { -// // can.clearProcedural(); -// TsglErr("This many passed testLine(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testLine(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } - -bool Canvas::testAccessors(Canvas& can) { - int passed = 0; - int failed = 0; - ColorFloat white = WHITE; //Have to set these to new variables so that I can compare them - ColorFloat black = BLACK; - - //Test 1: Background color - if(can.getBackgroundColor() == white) { - can.setBackgroundColor(BLACK); - if(can.getBackgroundColor() == black) { - passed++; - } else { - failed++; - TsglErr("Test 1, Background color for testAccessors() failed!"); - } - } - - //Test 2: Window width/height - //width - if(can.getWindowWidth() == 500) { - //height - if(can.getWindowHeight() == 500) { - passed++; - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (height)"); - } - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (width)"); - } - - //Test 3: Window x/y - //x - if(can.getWindowX() == 0) { - //y - if(can.getWindowY() == 0) { - passed++; - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (y)"); - } - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (x)"); - } - - //Test 4: Window open? - if(can.isOpen() == true) { - passed++; - } else { - failed++; - TsglErr("Test 4, Window open? for testAccessors() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - // can.clearProcedural(); - TsglDebug("Unit test for accessors/mutators passed!"); - return true; - } else { - // can.clearProcedural(); - TsglErr("This many passed for testAccessors(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testAccessors(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -// bool Canvas::testDrawImage(Canvas& can) { -// can.drawImage("../assets/pics/ff0000.png", 0, 0, 200, 200); -// can.sleepFor(1); -// int passed = 0; -// int failed = 0; -// ColorInt red(255, 0, 0); -// //Test 1: Single pixel -// if(can.getPoint(1, 1) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, Single pixel for testDrawImage() failed!"); -// } - -// //Test 2: Multiple pixels -// int count = 0; -// for(int i = 0; i < 200; i++) { -// if(can.getPoint(1, i) == red) { -// count++; -// } -// } - -// //Results of Test 2: -// if(count == 200) { -// passed++; -// } else { -// failed++; -// std::cout << "Count: " << count << std::endl; -// TsglErr("Test 2, Multiple pixels for testDrawImage() failed!"); -// } - -// //Results of entire Unit test:s -// if(passed == 2 && failed == 0) { -// TsglDebug("Unit test for drawing images passed!"); -// return true; -// } else { -// TsglErr("This many passed for testDrawImage(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testDrawImage(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } -//------------End Unit testing-------------------------------------------------------- } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 23ecba6e8..ee5edf6f1 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -41,7 +41,7 @@ #include "TextureHandler.h" // Currently used for screenshots, might change this #include "Util.h" // Needed constants and has cmath for performing math operations -#include "shader_s.h" +#include "Shader.h" #include #include #include @@ -90,48 +90,30 @@ class Canvas { typedef std::function doubleFunction; typedef std::function voidFunction; - float aspect; // Aspect ratio used for setting up the window - ColorFloat bgcolor; // Color of the Canvas' clearRectangle + // float aspect; // Aspect ratio used for setting up the window voidFunction boundKeys [(GLFW_KEY_LAST+1)*2]; // Array of function objects for key binding - std::mutex bufferMutex; // Mutex for locking the render buffer so that only one thread can read/write at a time - unsigned bufferSize; // Size of the screen buffer - std::string defaultFontFileName; + bool defaultBackground; // Boolean indicating whether myBackground has been set by an external source Timer* drawTimer; // Timer to regulate drawing frequency - GLuint multisampledFBO; // Multisampled target buffer for rendering to renderedTexture - GLuint intermediateFBO; // Intermediate framebuffer into which multisampledFBO will be blitted int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) - bool hasBackbuffer; // Whether or not the hardware supports double-buffering - bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice TextureHandler loader; // The TextureHandler that holds all our already loaded textures - bool loopAround; // Whether our point buffer has looped back to the beginning this int monitorX, monitorY; // Monitor position for upper left corner double mouseX, mouseY; // Location of the mouse once HandleIO() has been called - Array * myDrawables; // Our buffer of drawables to draw - std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame - bool objectBufferEmpty; // States whether the object buffer is empty/has been recently cleared + Background * myBackground; // Pointer to the Background drawn each frame + std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame std::mutex objectMutex; - Array * drawableBuffer; // Our buffer of drawables that the can be pushed to, and will later be flushed to the shapes array - std::mutex pointArrayMutex; // Mutex for the allPoints array - unsigned int pointBufferPosition, pointLastPosition; // Holds the position of the allPoints array - bool readyToDraw; // Whether a Canvas is ready to start drawing int realFPS; // Actual FPS of drawing - GLuint renderedTexture; // Texture to which we render to every frame. Attached to intermediateFBO - GLuint multisampledTexture; // Texture attached to the multisampled framebuffer #ifdef __APPLE__ pthread_t renderThread; // Thread dedicated to rendering the Canvas #else std::thread renderThread; // Thread dedicated to rendering the Canvas #endif uint8_t* screenBuffer; // Array that is a copy of the screen - GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window - unsigned proceduralBufferSize; doubleFunction scrollFunction; // Single function object for scrolling // Address of the vertex shader - Shader * textShader; - Shader * shapeShader; - Shader * textureShader; - std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time + Shader * textShader; // Shader for Text class + Shader * shapeShader; // Shader for Shape class + Shader * textureShader; // Shader for Background and Image classes bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread @@ -142,9 +124,8 @@ class Canvas { GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - GLuint VAO, // Address of GL's array buffer object - VBO; // Address of GL's vertex buffer object - float* vertexData; // The allPoints array + GLuint VAO, // Address of GL's vertex array object + VBO; // Address of GL's vertex buffer object GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not std::mutex windowMutex; // (OS X) Mutex for handling window contexts @@ -153,22 +134,20 @@ class Canvas { GLint winWidth; // Width of the Canvas' window GLint winWidthPadded; // Window width padded to a multiple of 4 (necessary for taking screenshots) - static int drawBuffer; // Buffer to use for drawing (set to GL_LEFT or GL_RIGHT) static bool glfwIsReady; // Whether or not we have info about our monitor static std::mutex glfwMutex; // Keeps GLFW createWindow from getting called at the same time in multiple threads static displayInfo monInfo; // Info about our display static unsigned openCanvases; // Total number of open Canvases - Background * myBackground; - static void buttonCallback(GLFWwindow* window, int key, int action, int mods); // GLFW callback for mouse buttons void draw(); // Draw loop for the Canvas static void errorCallback(int error, const char* string); // Display where an error is coming from void glDestroy(); // Destroys the GL and GLFW things that are specific for this canvas void init(int xx,int yy,int ww,int hh, - unsigned int b, std::string title, - double timerLength); // Method for initializing the canvas + unsigned int b, std::string title, + ColorFloat backgroundColor, double timerLength); // Method for initializing the canvas + void initBackground(ColorFloat bgcolor); // Initializes myBackground void initGl(); // Initializes the GL things specific to the Canvas void initGlew(); // Initialized the GLEW things specific to the Canvas static void initGlfw(); // Initalizes GLFW for all future canvases. @@ -185,12 +164,7 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void selectShaders(unsigned int choice); // Turn textures on or off - // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works - // static bool testLine(Canvas& can); // Unit tester for lines - static bool testAccessors(Canvas& can); // Unit tester for accessor methods - // static bool testDrawImage(Canvas& can); // Unit tester for drawing images (simultaneously a Unit test for Image) - + void selectShaders(unsigned int choice); // Select appropriate shader for type of Drawable protected: bool atiCard; // Whether the vendor of the graphics card is ATI void drawDrawable(Drawable* s); // Draw a drawable type @@ -198,7 +172,7 @@ class Canvas { Canvas(double timerLength = 0.0f); - Canvas(int x, int y, int width, int height, std::string title, double timerLength = 0.0f); + Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor = GRAY, double timerLength = 0.0f); virtual ~Canvas(); @@ -206,159 +180,15 @@ class Canvas { void bindToScroll(std::function function); - // void clearProcedural(); - - void close(); - void add(Drawable * shapePtr); - void remove(Drawable * shapePtr); - - void clearObjectBuffer(bool shouldFreeMemory = false); - - // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow = false); - - // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow = false); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat color, bool filled = true); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat color[], bool filled = true); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawImage(std::string filename, int x, int y, int width, int height, float alpha = 1.0f, float rotation = 0); - - // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color = BLACK, float rotation = 0); - - // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation = 0); - - // virtual void drawPixel(int row, int col, ColorFloat color = BLACK); - - // virtual void drawPoint(int x, int y, ColorFloat color = BLACK); - - // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation = 0); - - // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation = 0); - - // virtual void drawProgress(ProgressBar* p); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled = true, float rotation = 0); + void clearBackground(); - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color = BLACK, bool filled = true, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color, bool filled = true, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color[], bool filled = true, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - // virtual void drawText(std::string text, int x, int y, unsigned size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - // virtual void drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + void close(); - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + void clearObjectBuffer(bool shouldFreeMemory = false); - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + Background * getBackground(); ColorFloat getBackgroundColor(); @@ -370,8 +200,6 @@ class Canvas { float getFPS(); - bool isOpen(); - int getMouseX(); int getMouseY(); @@ -398,10 +226,14 @@ class Canvas { void handleIO(); + bool isOpen(); + void pauseDrawing(); void recordForNumFrames(unsigned int num_frames); + void remove(Drawable * shapePtr); + void reset(); void resumeDrawing(); @@ -426,6 +258,8 @@ class Canvas { virtual void run(void (*myFunction)(Canvas&, int, std::string, bool), int i, std::string s, bool b); + void setBackground(Background * background, bool previouslySet = false); + void setBackgroundColor(ColorFloat color); void setFont(std::string filename); @@ -445,10 +279,6 @@ class Canvas { void takeScreenShot(); int wait(); - - // static void runTests(); - - void setBackground(Background * background); }; } diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index 4e1d3128a..0e6fa4898 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -28,16 +28,16 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int /*! * \brief Explicitly constructs a new ConcavePolygon with monocolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param centerX The x coordinate of the ConcavePolygon's center. - * \param centerY The y coordinate of the ConcavePolygon's center. - * \param centerZ The z coordinate of the ConcavePolygon's center. - * \param numVertices The number of vertices that make up the ConcavePolygon. - * \param x An array of the ConcavePolygon's x vertices. - * \param y An array of the ConcavePolygon's y vertices. - * \param yaw The ConcavePolygon's yaw in 3D space. - * \param pitch The ConcavePolygon's pitch in 3D space. - * \param roll The ConcavePolygon's roll in 3D space. - * \param color A ColorFloat, the ConcavePolygon's fill color. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color A ColorFloat, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { @@ -51,25 +51,26 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } /*! * \brief Explicitly constructs a new ConcavePolygon with multicolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param centerX The x coordinate of the ConcavePolygon's center. - * \param centerY The y coordinate of the ConcavePolygon's center. - * \param centerZ The z coordinate of the ConcavePolygon's center. - * \param numVertices The number of vertices that make up the ConcavePolygon. - * \param x An array of the ConcavePolygon's x vertices. - * \param y An array of the ConcavePolygon's y vertices. - * \param yaw The ConcavePolygon's yaw in 3D space. - * \param pitch The ConcavePolygon's pitch in 3D space. - * \param roll The ConcavePolygon's roll in 3D space. - * \param color An array of ColorFloats, the ConcavePolygon's fill color. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); @@ -82,8 +83,8 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color[i]); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 8c1933f6a..36cf4a83d 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -50,8 +50,8 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } @@ -80,8 +80,8 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color[i]); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 3193f4efa..b4f437dde 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -6,7 +6,7 @@ #define DRAWABLE_H_ #include "Color.h" // Needed for color type -#include "shader_s.h" +#include "Shader.h" #include #include #include diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index a08e6e9fb..0d5d2b99d 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -49,7 +49,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color); } } @@ -77,7 +77,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color[i]); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color[i]); } } diff --git a/src/TSGL/Shader.h b/src/TSGL/Shader.h new file mode 100644 index 000000000..97631e3de --- /dev/null +++ b/src/TSGL/Shader.h @@ -0,0 +1,156 @@ +#ifndef SHADER_H +#define SHADER_H + +#include +#include + +#include +#include +#include +#include + +class Shader +{ +public: + unsigned int ID; + // constructor generates the shader on the fly + // ------------------------------------------------------------------------ + Shader(const char* vertexShader, const char* fragmentShader, const char* geometryShader = nullptr) + { + + GLenum err = glewInit(); + if (err != GLEW_OK) + exit(1); // or handle the error in a nicer way + if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. + exit(1); // or handle the error in a nicer way + // 2. compile shaders + unsigned int vertex, fragment; + // vertex shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vertexShader, NULL); + glCompileShader(vertex); + checkCompileErrors(vertex, "VERTEX"); + // fragment Shader + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fragmentShader, NULL); + glCompileShader(fragment); + checkCompileErrors(fragment, "FRAGMENT"); + // if geometry shader is given, compile geometry shader + unsigned int geometry; + + + if(geometryShader != nullptr) + { + geometry = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(geometry, 1, &geometryShader, NULL); + glCompileShader(geometry); + checkCompileErrors(geometry, "GEOMETRY"); + } + // shader Program + ID = glCreateProgram(); + glAttachShader(ID, vertex); + glAttachShader(ID, fragment); + if(geometryShader != nullptr) + glAttachShader(ID, geometry); + glLinkProgram(ID); + checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessery + glDeleteShader(vertex); + glDeleteShader(fragment); + if(geometryShader != nullptr) + glDeleteShader(geometry); + + } + // activate the shader + // ------------------------------------------------------------------------ + void use() + { + glUseProgram(ID); + } + // utility uniform functions + // ------------------------------------------------------------------------ + void setBool(const std::string &name, bool value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); + } + // ------------------------------------------------------------------------ + void setInt(const std::string &name, int value) const + { + glUniform1i(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setFloat(const std::string &name, float value) const + { + glUniform1f(glGetUniformLocation(ID, name.c_str()), value); + } + // ------------------------------------------------------------------------ + void setVec2(const std::string &name, const glm::vec2 &value) const + { + glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec2(const std::string &name, float x, float y) const + { + glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); + } + // ------------------------------------------------------------------------ + void setVec3(const std::string &name, const glm::vec3 &value) const + { + glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec3(const std::string &name, float x, float y, float z) const + { + glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); + } + // ------------------------------------------------------------------------ + void setVec4(const std::string &name, const glm::vec4 &value) const + { + glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); + } + void setVec4(const std::string &name, float x, float y, float z, float w) + { + glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); + } + // ------------------------------------------------------------------------ + void setMat2(const std::string &name, const glm::mat2 &mat) const + { + glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat3(const std::string &name, const glm::mat3 &mat) const + { + glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + // ------------------------------------------------------------------------ + void setMat4(const std::string &name, const glm::mat4 &mat) const + { + glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); + } + +private: + // utility function for checking shader compilation/linking errors. + // ------------------------------------------------------------------------ + void checkCompileErrors(GLuint shader, std::string type) + { + GLint success; + GLchar infoLog[1024]; + if(type != "PROGRAM") + { + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + else + { + glGetProgramiv(shader, GL_LINK_STATUS, &success); + if(!success) + { + glGetProgramInfoLog(shader, 1024, NULL, infoLog); + std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + } + } +}; +#endif \ No newline at end of file diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index 825d733f8..f0fb3bdcb 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -26,8 +26,8 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], z[i], color); - addOutlineVertex(x[i], y[i], z[i], GRAY); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } @@ -55,8 +55,8 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], z[i], color[i]); - addOutlineVertex(x[i], y[i], z[i], GRAY); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } } From d40ea782da2d42a2b7de1e8aa5db2546bc2f1900 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 29 Jul 2020 10:26:52 -0400 Subject: [PATCH 080/105] Update Makefiles for Mac + SPIA TSGL library files --- Makefile | 11 +- src/TSGL/Arrow.cpp | 80 +- src/TSGL/Background.cpp | 914 ++++++- src/TSGL/Background.h | 129 +- src/TSGL/Canvas.cpp | 2090 +---------------- src/TSGL/Canvas.h | 220 +- src/TSGL/ConcavePolygon.cpp | 49 +- src/TSGL/ConvexPolygon.cpp | 8 +- src/TSGL/Drawable.h | 2 +- src/TSGL/Polyline.cpp | 4 +- src/TSGL/{shader_s.h => Shader.h} | 0 src/TSGL/TriangleStrip.cpp | 8 +- src/examples/ArrayBubbleSort/Makefile | 19 +- src/examples/ArrayShakerSort/Makefile | 19 +- src/examples/Ballroom/Makefile | 19 +- src/examples/Ballroom/testBallroom.cpp | 2 +- src/examples/Clock/Makefile | 19 +- src/examples/Conway/Makefile | 19 +- src/examples/CubeRun/Makefile | 19 +- src/examples/DiningPhilosophers/Makefile | 19 +- src/examples/DiningPhilosophers3D/Makefile | 19 +- src/examples/Fireworks/Makefile | 19 +- src/examples/ForestFire/Makefile | 19 +- src/examples/Langton/Makefile | 19 +- src/examples/Mandelbrot/Makefile | 19 +- src/examples/MergeSort/Makefile | 19 +- src/examples/NewtonPendulum/Makefile | 19 +- src/examples/Pandemic/Makefile | 19 +- src/examples/ParallelPandemic/Makefile | 19 +- src/examples/Pong/Makefile | 19 +- src/examples/ProducerConsumer/Makefile | 19 +- src/examples/ReaderWriter/Makefile | 19 +- src/examples/SeaUrchin/Makefile | 19 +- src/examples/ShakerSort/Makefile | 19 +- src/examples/SolarSystem/Makefile | 19 +- src/examples/ThreadedArrayAddition/Makefile | 19 +- src/examples/ThreadedArrayBubbleSort/Makefile | 19 +- src/examples/ThreadedArrayOperations/Makefile | 19 +- src/examples/ThreadedSolarSystem/Makefile | 19 +- src/examples/Voronoi/Makefile | 19 +- src/tests/Makefile | 4 +- src/tests/test2Dvs3D/Makefile | 19 +- src/tests/test2Dvs3D/test2Dvs3D.cpp | 2 +- src/tests/test3DRotation/Makefile | 19 +- src/tests/testAlphaRectangle/Makefile | 19 +- src/tests/testArrows/Makefile | 19 +- src/tests/testAura/Makefile | 19 +- src/tests/testBackground/Makefile | 19 +- src/tests/testBlurImage/Makefile | 19 +- src/tests/testCalcPi/Makefile | 19 +- src/tests/testCircle/Makefile | 19 +- src/tests/testColorWheel/Makefile | 19 +- src/tests/testConcavePolygon/Makefile | 19 +- src/tests/testCone/Makefile | 19 +- src/tests/testConstructors/Makefile | 19 +- src/tests/testConvexPolygon/Makefile | 19 +- src/tests/testCosineIntegral/Makefile | 19 +- src/tests/testCube/Makefile | 19 +- src/tests/testCuboid/Makefile | 19 +- src/tests/testCylinder/Makefile | 19 +- src/tests/testDice/Makefile | 19 +- src/tests/testDiorama/Makefile | 19 +- src/tests/testEllipse/Makefile | 19 +- src/tests/testEllipsoid/Makefile | 19 +- src/tests/testFunction/Makefile | 19 +- src/tests/testGetPixels/Makefile | 19 +- src/tests/testGradientWheel/Makefile | 19 +- src/tests/testGraydient/Makefile | 19 +- src/tests/testGreyscale/Makefile | 19 +- src/tests/testHighData/Makefile | 19 +- src/tests/testImage/Makefile | 20 +- src/tests/testImageCart/Makefile | 19 +- src/tests/testInverter/Makefile | 19 +- src/tests/testLineChain/Makefile | 19 +- src/tests/testLineFan/Makefile | 20 +- src/tests/testLines/Makefile | 19 +- src/tests/testMouse/Makefile | 19 +- src/tests/testPixels/Makefile | 19 +- src/tests/testPrism/Makefile | 19 +- src/tests/testProcedural/Makefile | 19 +- src/tests/testProgressBar/Makefile | 19 +- src/tests/testProjectiles/Makefile | 19 +- src/tests/testPyramid/Makefile | 19 +- src/tests/testRectangle/Makefile | 19 +- src/tests/testRegularPolygon/Makefile | 19 +- src/tests/testScreenshot/Makefile | 19 +- src/tests/testSpectrogram/Makefile | 19 +- src/tests/testSpectrum/Makefile | 19 +- src/tests/testSphere/Makefile | 19 +- src/tests/testSquare/Makefile | 19 +- src/tests/testStar/Makefile | 19 +- src/tests/testText/Makefile | 19 +- src/tests/testTextCart/Makefile | 19 +- src/tests/testTextTwo/Makefile | 19 +- src/tests/testTransparency/Makefile | 19 +- src/tests/testTriangle/Makefile | 19 +- src/tests/testTriangleStrip/Makefile | 19 +- src/tests/testUnits/Makefile | 19 +- src/tests/test_specs/Makefile | 19 +- src/tests/test_specs/test_specs.cpp | 4 +- uninstall-mac | 5 +- 101 files changed, 2560 insertions(+), 2570 deletions(-) rename src/TSGL/{shader_s.h => Shader.h} (100%) diff --git a/Makefile b/Makefile index 8e245b684..eef1d9f87 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ endif ifeq ($(UNAME), Darwin) OS_LFLAGS := -framework Cocoa -framework OpenGl -framework IOKit -framework Corevideo OS_LDIRS := - OS_EXTRA_LIB := + OS_EXTRA_LIB := OS_GL := OS_OMP := -fopenmp -lomp OS_COMPILER := -std=c++0x @@ -116,11 +116,17 @@ docs: docs/html/index.html tutorial: tutorial/docs/html/index.html -cleanall: clean cleandocs +cleanall: clean cleantests cleanexamples cleandocs clean: $(RM) -r bin/* build/* lib/* tutorial/docs/html/* *~ *# *.tmp + $(MAKE) cleantests + $(MAKE) cleanexamples + +cleantests: (cd $(TESTS_PATH) && $(MAKE) clean) + +cleanexamples: (cd $(EXAMPLES_PATH) && $(MAKE) clean) cleandocs: @@ -155,6 +161,7 @@ install: install -m 0644 lib/libtsgl.a $(PREFIX)/lib install -m 0755 lib/libtsgl.so $(PREFIX)/lib cp -r src/TSGL $(PREFIX)/include + cp -r stb $(PREFIX)/include endif build/build: ${HEADERS} ${SOURCES} ${TESTS} diff --git a/src/TSGL/Arrow.cpp b/src/TSGL/Arrow.cpp index b8eae72c9..3c9b1e143 100644 --- a/src/TSGL/Arrow.cpp +++ b/src/TSGL/Arrow.cpp @@ -29,36 +29,36 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw isDoubleArrow = doubleArrow; isOutlined = false; attribMutex.unlock(); - addVertex(-0.4, 0.4, 0, color); - addVertex(-0.4, 1, 0, color); + addVertex(-0.4, 0.2, 0, color); + addVertex(-0.4, 0.5, 0, color); addVertex(-0.5, 0, 0, color); - addVertex(-0.4, -1, 0, color); - addVertex(-0.4, -0.4, 0, color); + addVertex(-0.4, -0.5, 0, color); + addVertex(-0.4, -0.2, 0, color); - addOutlineVertex(-0.4, 0.4, 0, GRAY); - addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.4, 0.2, 0, GRAY); + addOutlineVertex(-0.4, 0.5, 0, GRAY); addOutlineVertex(-0.5, 0, 0, GRAY); - addOutlineVertex(-0.4, -1, 0, GRAY); - addOutlineVertex(-0.4, -0.4, 0, GRAY); + addOutlineVertex(-0.4, -0.5, 0, GRAY); + addOutlineVertex(-0.4, -0.2, 0, GRAY); if( isDoubleArrow ) { - addVertex(0.4, -0.4, 0, color); - addVertex(0.4, -1, 0, color); + addVertex(0.4, -0.2, 0, color); + addVertex(0.4, -0.5, 0, color); addVertex(0.5, 0, 0, color); - addVertex(0.4, 1, 0, color); - addVertex(0.4, 0.4, 0, color); + addVertex(0.4, 0.5, 0, color); + addVertex(0.4, 0.2, 0, color); - addOutlineVertex(0.4, -0.4, 0, GRAY); - addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.4, -0.2, 0, GRAY); + addOutlineVertex(0.4, -0.5, 0, GRAY); addOutlineVertex(0.5, 0, 0, GRAY); - addOutlineVertex(0.4, 1, 0, GRAY); - addOutlineVertex(0.4, 0.4, 0, GRAY); + addOutlineVertex(0.4, 0.5, 0, GRAY); + addOutlineVertex(0.4, 0.2, 0, GRAY); } else { - addVertex(0.5, -.4, 0, color); - addVertex(0.5, .4, 0, color); + addVertex(0.5, -.2, 0, color); + addVertex(0.5, .2, 0, color); - addOutlineVertex(0.5, -.4, 0, GRAY); - addOutlineVertex(0.5, .4, 0, GRAY); + addOutlineVertex(0.5, -.2, 0, GRAY); + addOutlineVertex(0.5, .2, 0, GRAY); } } @@ -89,36 +89,36 @@ Arrow::Arrow(float x, float y, float z, GLfloat length, GLfloat width, float yaw isDoubleArrow = doubleArrow; isOutlined = false; attribMutex.unlock(); - addVertex(-0.4, 0.4, 0, color[0]); - addVertex(-0.4, 1, 0, color[0]); + addVertex(-0.4, 0.2, 0, color[0]); + addVertex(-0.4, 0.5, 0, color[0]); addVertex(-0.5, 0, 0, color[0]); - addVertex(-0.4, -1, 0, color[0]); - addVertex(-0.4, -0.4, 0, color[0]); + addVertex(-0.4, -0.5, 0, color[0]); + addVertex(-0.4, -0.2, 0, color[0]); - addOutlineVertex(-0.4, 0.4, 0, GRAY); - addOutlineVertex(-0.4, 1, 0, GRAY); + addOutlineVertex(-0.4, 0.2, 0, GRAY); + addOutlineVertex(-0.4, 0.5, 0, GRAY); addOutlineVertex(-0.5, 0, 0, GRAY); - addOutlineVertex(-0.4, -1, 0, GRAY); - addOutlineVertex(-0.4, -0.4, 0, GRAY); + addOutlineVertex(-0.4, -0.5, 0, GRAY); + addOutlineVertex(-0.4, -0.2, 0, GRAY); if( isDoubleArrow ) { - addVertex(0.4, -0.4, 0, color[1]); - addVertex(0.4, -1, 0, color[1]); + addVertex(0.4, -0.2, 0, color[1]); + addVertex(0.4, -0.5, 0, color[1]); addVertex(0.5, 0, 0, color[1]); - addVertex(0.4, 1, 0, color[1]); - addVertex(0.4, 0.4, 0, color[1]); + addVertex(0.4, 0.5, 0, color[1]); + addVertex(0.4, 0.2, 0, color[1]); - addOutlineVertex(0.4, -0.4, 0, GRAY); - addOutlineVertex(0.4, -1, 0, GRAY); + addOutlineVertex(0.4, -0.2, 0, GRAY); + addOutlineVertex(0.4, -0.5, 0, GRAY); addOutlineVertex(0.5, 0, 0, GRAY); - addOutlineVertex(0.4, 1, 0, GRAY); - addOutlineVertex(0.4, 0.4, 0, GRAY); + addOutlineVertex(0.4, 0.5, 0, GRAY); + addOutlineVertex(0.4, 0.2, 0, GRAY); } else { - addVertex(0.5, -0.4, 0, color[1]); - addVertex(0.5, 0.4, 0, color[1]); + addVertex(0.5, -0.2, 0, color[1]); + addVertex(0.5, 0.2, 0, color[1]); - addOutlineVertex(0.5, -.4, 0, GRAY); - addOutlineVertex(0.5, .4, 0, GRAY); + addOutlineVertex(0.5, -.2, 0, GRAY); + addOutlineVertex(0.5, .2, 0, GRAY); } attribMutex.lock(); myAlpha = (color[0].A + color[1].A) / 2; diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp index 9d4ef5b44..6fc963b23 100644 --- a/src/TSGL/Background.cpp +++ b/src/TSGL/Background.cpp @@ -5,83 +5,148 @@ namespace tsgl { /*! * \brief Explicitly constructs a new Background. * \details Explicit constructor for a Background object. - * \param x The x coordinate of the center of the Background. - * \param y The y coordinate of the center of the Background. - * \param z The z coordinate of the center of the Background. * \param width Background's width in pixels. - * \param yaw The Background's yaw, in degrees. - * \param pitch The Background's pitch, in degrees. - * \param roll The Background's roll, in degrees. + * \param height Background's height in pixels. * \param c A ColorFloat for the Background's original color. * \warning An invariant is held where if width or height isn't positive then an error message is given. - * \return A new Background with a buffer for storing the specified numbered of vertices. + * \return A new Background to which Drawables and Pixels can be drawn procedurally. */ -Background::Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c) -: Drawable(x, y, z, yaw, pitch, roll) { +Background::Background(GLint width, GLint height, const ColorFloat &clearColor) { if (width <= 0 || height <= 0) { TsglDebug("Cannot have a Background with non-positive width or height."); } attribMutex.lock(); - shaderType = TEXTURE_SHADER_TYPE; - myXScale = myWidth = width; - myYScale = myHeight = height; + myWidth = width; + myHeight = height; + myDrawables = new Array(myWidth * myHeight * 2); + baseColor = clearColor; + toClear = false; + complete = false; + newPixelsDrawn = false; + + int padwidth = myWidth % 4; + if (padwidth > 0) + padwidth = 4-padwidth; + myWidthPadded = myWidth + padwidth; + readPixelMutex.lock(); + readPixelBuffer = new uint8_t[myWidthPadded * myHeight * 3]; + for (int i = 0; i < myWidth * myHeight * 3; ++i) { + readPixelBuffer[i] = 0; + } + readPixelMutex.unlock(); + pixelBufferMutex.lock(); + pixelTextureBuffer = new uint8_t[myWidth * myHeight * 4]; + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + pixelBufferMutex.unlock(); + vertices = new GLfloat[30]; - vertices[0] = vertices[1] = vertices[6] = vertices[10] = vertices[16] = vertices[20] = -0.5; // x + y - vertices[5] = vertices[11] = vertices[15] = vertices[21] = vertices[25] = vertices[26] = 0.5; // x + y + vertices[0] = vertices[11] = vertices[21] = vertices[10] = vertices[26] = vertices[20] = -0.5; // x + y + vertices[5] = vertices[1] = vertices[15] = vertices[6] = vertices[25] = vertices[16] = 0.5; // x + y vertices[2] = vertices[7] = vertices[12] = vertices[17] = vertices[22] = vertices[27] = 0; // z vertices[3] = vertices[13] = vertices[14] = vertices[23] = vertices[24] = vertices[29] = 0.0; // texture coord x + y vertices[4] = vertices[8] = vertices[9] = vertices[18] = vertices[19] = vertices[28] = 1.0; // texture coord x + y + attribMutex.unlock(); +} - myDrawables = new Array(myWidth * myHeight * 2); +/*! \brief Assigns Drawable shaders and initializes framebuffers within the parameter window's context. + * \details Assigns shapeShader, textShader, textureShader to parameters and initializes two framebuffers: MSAA and non-MSAA. + * \param shapeS Pointer to a shader for Shape Drawables. + * \param textS Pointer to a shader for Text Drawables. + * \param textureS Pointer to a shader for texture rendering. + * \param window GLFWwindow * within whose context the framebuffers will be initialized. + */ +void Background::init(Shader * shapeS, Shader * textS, Shader * textureS, GLFWwindow * window) { + attribMutex.lock(); + glfwMakeContextCurrent(window); + // configure MSAA framebuffer + // -------------------------- + glGenFramebuffers(1, &multisampledFBO); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + // create a multisampled color attachment texture + glGenTextures(1, &multisampledTexture); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, myWidth, myHeight, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); + // create multisampled renderbuffer object + glGenRenderbuffers(1, &RBO); + glBindRenderbuffer(GL_RENDERBUFFER, RBO); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Create a second framebuffer, non-MSAA + // -------------------------- + intermediateFBO = 0; + glGenFramebuffers(1, &intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + glGenTextures(1, &intermediateTexture); + glBindTexture(GL_TEXTURE_2D, intermediateTexture); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, myWidth, myHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,intermediateTexture, 0); + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + TsglErr("FRAMEBUFFER CREATION FAILED"); + + glClear(GL_COLOR_BUFFER_BIT); - myAlpha = 1.0; + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // glBindFramebuffer(GL_FRAMEBUFFER, 0); + // generate a texture for the pixels + // -------------------------- + glGenTextures(1, &pixelTexture); + glBindTexture(GL_TEXTURE_2D, pixelTexture); + // Set texture parameters for wrapping. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - init = true; + // Set texture parameters for filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + + shapeShader = shapeS; + textShader = textS; + textureShader = textureS; + complete = true; attribMutex.unlock(); + glfwMakeContextCurrent(0); } /*! * \brief Draw the Background. * \details This function actually draws the Background to the Canvas. + * \note On each draw cycle, first any Drawables that have been newly added to the Background will be rendered, and then any new calls to drawPixel will be processed. */ -void Background::draw(Shader * shader) { - if (!init) { - TsglDebug("Vertex buffer is not full."); +void Background::draw() { + if (!complete) { + TsglDebug("Shaders have not been defined for this background."); return; } - // gen framebuffer - glGenFramebuffers(1, &myFramebuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFramebuffer); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); + glEnable(GL_DEPTH_TEST); - glViewport(0,0,myWidth,myHeight); - - // gen texture, attach to framebuffer - glGenTextures(1, &myTexture); - glBindTexture(GL_TEXTURE_2D, myTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, myWidth, myHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, myTexture, 0); - - // render buffer object - // glGenRenderbuffers(1, &myRenderbufferObject); - // glBindRenderbuffer(GL_RENDERBUFFER, myRenderbufferObject); - // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myWidth, myHeight); // use a single renderbuffer object for both a depth AND stencil buffer. - // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, myRenderbufferObject); // now actually attach it - - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("ERROR::FRAMEBUFFER:: Framebuffer is not complete!"); - glClearColor(1,0,0,1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) + if (toClear) { + attribMutex.lock(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + toClear = false; + attribMutex.unlock(); + } + drawableMutex.lock(); for (unsigned int i = 0; i < myDrawables->size(); i++) { Drawable* d = (*myDrawables)[i]; @@ -96,63 +161,71 @@ void Background::draw(Shader * shader) { } } } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + myDrawables->clear(); + drawableMutex.unlock(); + // setting up texture shaders for both pixel drawing and post-blit render selectShaders(TEXTURE_SHADER_TYPE); glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, glm::vec3(myRotationPointX, myRotationPointY, myRotationPointZ)); - model = glm::rotate(model, glm::radians(myCurrentYaw), glm::vec3(0.0f, 0.0f, 1.0f)); - model = glm::rotate(model, glm::radians(myCurrentPitch), glm::vec3(0.0f, 1.0f, 0.0f)); - model = glm::rotate(model, glm::radians(myCurrentRoll), glm::vec3(1.0f, 0.0f, 0.0f)); - model = glm::translate(model, glm::vec3(myCenterX - myRotationPointX, myCenterY - myRotationPointY, myCenterZ - myRotationPointZ)); - model = glm::scale(model, glm::vec3(myXScale, myYScale, myZScale)); - - unsigned int modelLoc = glGetUniformLocation(shader->ID, "model"); + model = glm::scale(model, glm::vec3(myWidth, myHeight, 1)); + + unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - glBindTexture(GL_TEXTURE_2D, myTexture); // use the color attachment texture as the texture of the quad plane - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); // Flush buffer data to the actual draw buffer + // check for new pixels being drawn + pixelBufferMutex.lock(); + if (newPixelsDrawn) { + glBindTexture(GL_TEXTURE_2D, pixelTexture); + + // actually generate the texture + mipmaps + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixelTextureBuffer); + glGenerateMipmap(GL_TEXTURE_2D); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 6); - glDeleteTextures(1, &myTexture); - glDeleteFramebuffers(1, &myFramebuffer); -} + newPixelsDrawn = false; + for (int i = 0; i < myWidth * myHeight * 4; ++i) { + pixelTextureBuffer[i] = 0; + } + } + pixelBufferMutex.unlock(); + + // blit MSAA framebuffer to non-MSAA framebuffer's texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); + glBlitFramebuffer(0, 0, myWidth, myHeight, 0, 0, myWidth, myHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - /*! - * \brief Gets the color of the pixel drawn on the current Background at the given row and column. - * \note (0,0) signifies the top-left of the Background's texture. - * \param row The row (y-position) of the pixel to grab. - * \param col The column (x-position) of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (col,row). - */ -ColorInt Background::getPixel(int row, int col) { - return ColorInt(0,0,0,255); -} + glDisable(GL_DEPTH_TEST); - /*! - * \brief Draws a single pixel, specified in row,column format. - * \details This function alters the value at the specified row, column offset within the Background's buffer variable. - * \note (0,0) signifies the top-left of the Background. - * \param row The row (y-position) of the pixel. - * \param col The column (x-position) of the pixel. - * \param color The color of the point. - */ -void Background::drawPixel(int row, int col, ColorInt c) { - attribMutex.lock(); + // render non-MSAA framebuffer's texture to default framebuffer + glBindTexture(GL_TEXTURE_2D,intermediateTexture); + glPixelStorei(GL_UNPACK_ALIGNMENT,4); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + /* next two lines are very essential */ + glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); + glDrawArrays(GL_TRIANGLES,0,6); + glEnable(GL_DEPTH_TEST); - attribMutex.unlock(); + glViewport(0,0,myWidth,myHeight); + readPixelMutex.lock(); + glReadPixels(0, 0, myWidthPadded, myHeight, GL_RGB, GL_UNSIGNED_BYTE, readPixelBuffer); + readPixelMutex.unlock(); } +/*! \brief Activates the corresponding Shader for a given Drawable. + * \param sType Unsigned int with a corresponding value for each type of Shader. + */ void Background::selectShaders(unsigned int sType) { Shader * program = 0; if (sType == TEXT_SHADER_TYPE) { @@ -198,17 +271,650 @@ void Background::selectShaders(unsigned int sType) { glUniformMatrix4fv(glGetUniformLocation(program->ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); } -void Background::defineShaders(Shader * shapeS, Shader * textS, Shader * textureS) { - attribMutex.lock(); - shapeShader = shapeS; - textShader = textS; - textureShader = textureS; - attribMutex.unlock(); +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color ColorFloat for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(a); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Arrow to the Background. + * \details Initializes a new Arrow based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Arrow's center location. + * \param y The y coordinate of the Arrow's center location. + * \param z The z coordinate of the Arrow's center location. + * \param length Length of the Arrow. + * \param width Width of the Arrow. + * \param yaw The Arrow's yaw rotation. + * \param pitch The Arrow's pitch rotation. + * \param roll The Arrow's roll rotation. + * \param color Array of ColorFloats for the Arrow's vertices. + * \param outlined Boolean indicating if the Arrow should be outlined or not, defaulting to not. + */ +void Background::drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow, bool outlined) { + Arrow * a = new Arrow(x,y,z,length,width,yaw,pitch,roll,color,doubleArrow); + a->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(a); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color Array of ColorFloats for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Circle to the Background. + * \details Initializes a new Circle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Circle's center location. + * \param y The y coordinate of the Circle's center location. + * \param z The z coordinate of the Circle's center location. + * \param radius Radius of the Circle. + * \param yaw The Circle's yaw rotation. + * \param pitch The Circle's pitch rotation. + * \param roll The Circle's roll rotation. + * \param color ColorFloat for the Circle's vertices. + * \param outlined Boolean indicating if the Circle should be outlined or not, defaulting to not. + */ +void Background::drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Circle * c = new Circle(x,y,z,radius,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color ColorFloat for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); } -void Background::drawSquare(float z) { - Square * s = new Square(0,0,z,200,0,0,0,BLUE); +/*!\brief Procedurally draws a ConcavePolygon to the Background. + * \details Initializes a new ConcavePolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConcavePolygon's center location. + * \param centerY The y coordinate of the ConcavePolygon's center location. + * \param centerZ The z coordinate of the ConcavePolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConcavePolygon. + * \param x Float array containing the ConcavePolygon's x vertices. + * \param y Float array containing the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw rotation. + * \param pitch The ConcavePolygon's pitch rotation. + * \param roll The ConcavePolygon's roll rotation. + * \param color Array of ColorFloats for the ConcavePolygon's vertices. + * \param outlined Boolean indicating if the ConcavePolygon should be outlined or not, defaulting to not. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. + */ +void Background::drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConcavePolygon * c = new ConcavePolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color ColorFloat for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a ConvexPolygon to the Background. + * \details Initializes a new ConvexPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the ConvexPolygon's center location. + * \param centerY The y coordinate of the ConvexPolygon's center location. + * \param centerZ The z coordinate of the ConvexPolygon's center location. + * \param numVertices The number of vertices to be drawn for the ConvexPolygon. + * \param x Float array containing the ConvexPolygon's x vertices. + * \param y Float array containing the ConvexPolygon's y vertices. + * \param yaw The ConvexPolygon's yaw rotation. + * \param pitch The ConvexPolygon's pitch rotation. + * \param roll The ConvexPolygon's roll rotation. + * \param color Array of ColorFloats for the ConvexPolygon's vertices. + * \param outlined Boolean indicating if the ConvexPolygon should be outlined or not, defaulting to not. + */ +void Background::drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + ConvexPolygon * c = new ConvexPolygon(centerX,centerY,centerZ,numVertices,x,y,yaw,pitch,roll,color); + c->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(c); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color ColorFloat for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(e); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Ellipse to the Background. + * \details Initializes a new Ellipse based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Ellipse's center location. + * \param y The y coordinate of the Ellipse's center location. + * \param z The z coordinate of the Ellipse's center location. + * \param xRadius Horizontal radius of the Ellipse. + * \param yRadius Vertical radius of the Ellipse. + * \param yaw The Ellipse's yaw rotation. + * \param pitch The Ellipse's pitch rotation. + * \param roll The Ellipse's roll rotation. + * \param color Array of ColorFloats for the Ellipse's vertices. + * \param outlined Boolean indicating if the Ellipse should be outlined or not, defaulting to not. + */ +void Background::drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Ellipse * e = new Ellipse(x,y,z,xRadius,yRadius,yaw,pitch,roll,color); + e->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(e); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws an Image to the Background. + * \details Initializes a new Image based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Image's center location. + * \param y The y coordinate of the Image's center location. + * \param z The z coordinate of the Image's center location. + * \param filename String containing the file location of the Image. + * \param yaw The Image's yaw rotation. + * \param pitch The Image's pitch rotation. + * \param roll The Image's roll rotation. + * \param alpha Alpha value for the Image's transparency. + */ +void Background::drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha) { + Image * i = new Image(x,y,z,filename,width,height,yaw,pitch,roll,alpha); + drawableMutex.lock(); + myDrawables->push(i); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color ColorFloat for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Line's center location. + * \param y The y coordinate of the Line's center location. + * \param z The z coordinate of the Line's center location. + * \param length Length of the Line. + * \param yaw The Line's yaw rotation. + * \param pitch The Line's pitch rotation. + * \param roll The Line's roll rotation. + * \param color Array of ColorFloats for the Line's vertices. + */ +void Background::drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]) { + Line * l = new Line(x,y,z,length,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + + /*! + * \brief Draws a single pixel, specified in x,y format. + * \details This function alters the value at the specified x, y offset within the Background's buffer variable. + * \note (0,0) signifies the center of the Background. + * \param x The x-position of the pixel. + * \param y The y-position of the pixel. + * \param color The color of the point. + */ +void Background::drawPixel(int x, int y, ColorInt c) { + if (abs(x) > (myWidth / 2) || abs(y) > (myHeight / 2)) { + TsglErr("Pixel x and y coordinates must be within Background dimensions."); + return; + } + pixelBufferMutex.lock(); + x += myWidth / 2; + y += myHeight / 2; + pixelTextureBuffer[(y * myWidth + x) * 4] = c.R; + pixelTextureBuffer[(y * myWidth + x) * 4 + 1] = c.G; + pixelTextureBuffer[(y * myWidth + x) * 4 + 2] = c.B; + pixelTextureBuffer[(y * myWidth + x) * 4 + 3] = c.A; + newPixelsDrawn = true; + pixelBufferMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color ColorFloat for the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(p); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Polyline to the Background. + * \details Initializes a new Polyline based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Polyline's center location. + * \param y The y coordinate of the Polyline's center location. + * \param z The z coordinate of the Polyline's center location. + * \param numVertices The number of vertices to be drawn for the Polyline. + * \param lineVertices Float array containing the Polyline's vertices (x1,y1,z1,x2,y2,z2,x3...). + * \param yaw The Polyline's yaw rotation. + * \param pitch The Polyline's pitch rotation. + * \param roll The Polyline's roll rotation. + * \param color Array of ColorFloats corresponding to the Polyline's vertices. + */ +void Background::drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]) { + Polyline * p = new Polyline(x,y,z,numVertices,lineVertices,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(p); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color ColorFloat for the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Rectangle to the Background. + * \details Initializes a new Rectangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Rectangle's center location. + * \param y The y coordinate of the Rectangle's center location. + * \param z The z coordinate of the Rectangle's center location. + * \param width Width of the Rectangle. + * \param height Height of the Rectangle. + * \param yaw The Rectangle's yaw rotation. + * \param pitch The Rectangle's pitch rotation. + * \param roll The Rectangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Rectangle's vertices. + * \param outlined Boolean indicating if the Rectangle should be outlined or not, defaulting to not. + */ +void Background::drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Rectangle * r = new Rectangle(x,y,z,width,height,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color ColorFloat for the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a RegularPolygon to the Background. + * \details Initializes a new RegularPolygon based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the RegularPolygon's center location. + * \param y The y coordinate of the RegularPolygon's center location. + * \param z The z coordinate of the RegularPolygon's center location. + * \param radius Distance from the RegularPolygon's center to each of its vertices. + * \param points Number of sides on the RegularPolygon. + * \param yaw The RegularPolygon's yaw rotation. + * \param pitch The RegularPolygon's pitch rotation. + * \param roll The RegularPolygon's roll rotation. + * \param color Array of ColorFloats corresponding to the RegularPolygon's vertices. + * \param outlined Boolean indicating if the RegularPolygon should be outlined or not, defaulting to not. + */ +void Background::drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + RegularPolygon * r = new RegularPolygon(x,y,z,radius,sides,yaw,pitch,roll,color); + r->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(r); + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color ColorFloat for the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Square to the Background. + * \details Initializes a new Square based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Square's center location. + * \param y The y coordinate of the Square's center location. + * \param z The z coordinate of the Square's center location. + * \param sidelength Length of each side of the Square. + * \param yaw The Square's yaw rotation. + * \param pitch The Square's pitch rotation. + * \param roll The Square's roll rotation. + * \param color Array of ColorFloats corresponding to the Square's vertices. + * \param outlined Boolean indicating if the Square should be outlined or not, defaulting to not. + */ +void Background::drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Square * s = new Square(x,y,z,sidelength,yaw,pitch,roll,color); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color ColorFloat for the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + drawableMutex.lock(); myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Star to the Background. + * \details Initializes a new Star based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Star's center location. + * \param y The y coordinate of the Star's center location. + * \param z The z coordinate of the Star's center location. + * \param radius Distance from the Star's center to each of its points. + * \param points Number of points on the Star. + * \param yaw The Star's yaw rotation. + * \param pitch The Star's pitch rotation. + * \param roll The Star's roll rotation. + * \param color Array of ColorFloats corresponding to the Star's vertices. + * \param ninja Boolean indicating if the Star should be mirror-symmetrical or just rotationally symmetrical. + * \param outlined Boolean indicating if the Star should be outlined or not, defaulting to not. + */ +void Background::drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja, bool outlined) { + Star * s = new Star(x,y,z,radius,points,yaw,pitch,roll,color,ninja); + s->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(s); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws Text to the Background. + * \details Initializes a new Text based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x The x coordinate of the Text's center location. + * \param y The y coordinate of the Text's center location. + * \param z The z coordinate of the Text's center location. + * \param text Wide string containing the characters to be rendered. + * \param fontFilename String containing the filename for the font with which the Text will be rendered. + * \param fontsize The Text's fontsize in pixels. + * \param yaw The Text's yaw rotation. + * \param pitch The Text's pitch rotation. + * \param roll The Text's roll rotation. + * \param color ColorFloat for the Text. + */ +void Background::drawText(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color) { + Text * t = new Text(x,y,z,text,fontFilename,fontsize,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color ColorFloat for the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a Triangle to the Background. + * \details Initializes a new Triangle based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the Triangle's first vertex location. + * \param y1 The y coordinate of the Triangle's first vertex location. + * \param z1 The z coordinate of the Triangle's first vertex location. + * \param x2 The x coordinate of the Triangle's second vertex location. + * \param y2 The y coordinate of the Triangle's second vertex location. + * \param z2 The z coordinate of the Triangle's second vertex location. + * \param x3 The x coordinate of the Triangle's third vertex location. + * \param y3 The y coordinate of the Triangle's third vertex location. + * \param z3 The z coordinate of the Triangle's third vertex location. + * \param yaw The Triangle's yaw rotation. + * \param pitch The Triangle's pitch rotation. + * \param roll The Triangle's roll rotation. + * \param color Array of ColorFloats corresponding to the Triangle's vertices. + * \param outlined Boolean indicating if the Triangle should be outlined or not, defaulting to not. + */ +void Background::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + Triangle * t = new Triangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color ColorFloat for the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + +/*!\brief Procedurally draws a TriangleStrip to the Background. + * \details Initializes a new TriangleStrip based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param centerX The x coordinate of the TriangleStrip's center location. + * \param centerY The y coordinate of the TriangleStrip's center location. + * \param centerZ The z coordinate of the TriangleStrip's center location. + * \param numVertices The number of vertices to be drawn for the TriangleStrip. + * \param x Float array containing the TriangleStrip's x vertices. + * \param y Float array containing the TriangleStrip's y vertices. + * \param z Float array containing the TriangleStrip's z vertices. + * \param yaw The TriangleStrip's yaw rotation. + * \param pitch The TriangleStrip's pitch rotation. + * \param roll The TriangleStrip's roll rotation. + * \param color Array of ColorFloats corresponding to the TriangleStrip's vertices. + * \param outlined Boolean indicating if the TriangleStrip should be outlined or not, defaulting to not. + */ +void Background::drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined) { + TriangleStrip * t = new TriangleStrip(centerX,centerY,centerZ,numVertices,x,y,z,yaw,pitch,roll,color); + t->setIsOutlined(outlined); + drawableMutex.lock(); + myDrawables->push(t); // Push it onto our drawing buffer + drawableMutex.unlock(); +} + + /*! + * \brief Gets the color of the pixel drawn on the current Background at the given x and y. + * \note (0,0) signifies the center of the Background's texture. + * \param x The x-position of the pixel to grab. + * \param y The y-position of the pixel to grab. + * \return A ColorInt containing the color of the pixel at (col,row). + */ +ColorInt Background::getPixel(int x, int y) { + if (abs(x) > (myWidth/2) || abs(y) > (myHeight/2)) { + TsglErr("Accessor x and y must be within Canvas parameters."); + return ColorInt(0,0,0,0); + } + readPixelMutex.lock(); + x += myWidth/2; + y += myHeight/2; + int off = 3 * (y * myWidthPadded + x); + ColorInt c = ColorInt(readPixelBuffer[off], readPixelBuffer[off + 1], readPixelBuffer[off + 2], 255); + readPixelMutex.unlock(); + return c; +} + +/*! \brief Mutator for the color used to clear the Background when clear() is called. + * \details Sets the clear color to the parameter ColorFloat. + * \param c ColorFloat assigned to the clear color of the Background. + */ +void Background::setClearColor(ColorFloat c) { + attribMutex.lock(); + baseColor = c; + glClearColor(baseColor.R, baseColor.G, baseColor.B, baseColor.A); + attribMutex.unlock(); } /*! @@ -216,7 +922,15 @@ void Background::drawSquare(float z) { */ Background::~Background() { myDrawables->clear(); + delete [] readPixelBuffer; + delete [] pixelTextureBuffer; + delete [] vertices; delete myDrawables; + glDeleteTextures(1, &pixelTexture); + glDeleteTextures(1, &intermediateFBO); + glDeleteFramebuffers(1, &intermediateTexture); + glDeleteTextures(1, &multisampledTexture); + glDeleteFramebuffers(1, &multisampledFBO); } } \ No newline at end of file diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h index 2f9086369..61435cc52 100644 --- a/src/TSGL/Background.h +++ b/src/TSGL/Background.h @@ -1,5 +1,5 @@ /* - * Background.h extends Drawable and provides a class for drawing a background. + * Background.h extends Drawable and provides a class for drawing TSGL primitives procedurally onto a background. */ #ifndef BACKGROUND_H_ @@ -7,7 +7,21 @@ #include "Drawable.h" // For extending our Shape object #include "Array.h" // Our own array for buffering drawing operations +#include "Arrow.h" +#include "Circle.h" +#include "ConcavePolygon.h" +#include "ConvexPolygon.h" +#include "Ellipse.h" +#include "Image.h" +#include "Line.h" +#include "Polyline.h" +#include "Rectangle.h" +#include "RegularPolygon.h" #include "Square.h" +#include "Star.h" +#include "Text.h" +#include "Triangle.h" +#include "TriangleStrip.h" #include "Util.h" // Needed constants and has cmath for performing math operations namespace tsgl { @@ -16,20 +30,105 @@ namespace tsgl { * \brief Draw a Background for the Canvas with colored pixels. * \details Background is a class for holding colored pixel data. */ -class Background : public Drawable { +class Background { protected: - GLint myWidth, myHeight; - GLuint myTexture; - GLuint myFramebuffer; - GLuint myRenderbufferObject; + GLint myWidth, myHeight, myWidthPadded; + + GLuint multisampledTexture, intermediateTexture; + GLuint multisampledFBO, intermediateFBO; + GLuint RBO; + Array * myDrawables; + Shader * textShader; Shader * shapeShader; Shader * textureShader; + + ColorFloat baseColor; + bool toClear; + + std::mutex readPixelMutex; + uint8_t* readPixelBuffer; + + std::mutex pixelBufferMutex; + GLuint pixelTexture; + uint8_t* pixelTextureBuffer; + bool newPixelsDrawn; + + bool complete; + std::mutex attribMutex; + std::mutex drawableMutex; + GLfloat * vertices; + + virtual void selectShaders(unsigned int sType); public: - Background(float x, float y, float z, GLint width, GLint height, float yaw, float pitch, float roll, const ColorFloat &c = WHITE); + Background(GLint width, GLint height, const ColorFloat &c = WHITE); + + virtual void init(Shader * shapeS, Shader * textS, Shader * textureS, GLFWwindow * window); + + virtual bool isInitialized() { return complete; } + + virtual void clear() { toClear = true; } + + virtual void draw(); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color, bool doubleArrow = false, bool outlined = false); + + virtual void drawArrow(float x, float y, float z, float length, float width, float yaw, float pitch, float roll, ColorFloat color[], bool doubleArrow = false, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawCircle(float x, float y, float z, float radius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawConvexPolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawEllipse(float x, float y, float z, float xRadius, float yRadius, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); - virtual void draw(Shader * shader); + virtual void drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha = 1.0f); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawPixel(int x, int y, ColorInt c); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawPolyline(float x, float y, float z, int numVertices, float lineVertices[], float yaw, float pitch, float roll, ColorFloat color[]); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRectangle(float x, float y, float z, float width, float height, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawRegularPolygon(float x, float y, float z, float radius, int sides, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawSquare(float x, float y, float z, float sidelength, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color, bool ninja = false, bool outlined = false); + + virtual void drawStar(float x, float y, float z, float radius, int points, float yaw, float pitch, float roll, ColorFloat color[], bool ninja = false, bool outlined = false); + + virtual void drawText(float x, float y, float z, std::wstring text, std::string fontFilename, unsigned int fontsize, float yaw, float pitch, float roll, const ColorFloat &color); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color, bool outlined = false); + + virtual void drawTriangleStrip(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float z[], float yaw, float pitch, float roll, ColorFloat color[], bool outlined = false); /*! * \brief Accessor for the width of the Background. @@ -43,15 +142,15 @@ class Background : public Drawable { */ virtual GLint getHeight() { return myHeight; } - virtual ColorInt getPixel(int row, int col); + virtual ColorInt getPixel(int x, int y); - virtual void drawPixel(int row, int col, ColorInt c); - - virtual void selectShaders(unsigned int sType); - - virtual void defineShaders(Shader * shapeS, Shader * textS, Shader * textureS); + /*! + * \brief Accessor for color which is used to clear the Background when clear() is called. + * \details Returns a ColorInt corresponding to the clear color of the Background. + */ + virtual ColorFloat getClearColor() { return baseColor; } - virtual void drawSquare(float z); + virtual void setClearColor(ColorFloat c); virtual ~Background(); }; diff --git a/src/TSGL/Canvas.cpp b/src/TSGL/Canvas.cpp index 5acadf9f0..14125610e 100644 --- a/src/TSGL/Canvas.cpp +++ b/src/TSGL/Canvas.cpp @@ -82,7 +82,6 @@ static const GLchar* textureFragmentShader = "FragColor = texture(texture1, TexCoords) * vec4(1.0,1.0,1.0,alpha);" "}"; -int Canvas::drawBuffer = GL_FRONT_LEFT; bool Canvas::glfwIsReady = false; std::mutex Canvas::glfwMutex; GLFWvidmode const* Canvas::monInfo; @@ -98,7 +97,7 @@ unsigned Canvas::openCanvases = 0; * have a 4:3 aspect ratio. */ Canvas::Canvas(double timerLength) { - init(-1, -1, -1, -1, -1, "", timerLength); + init(-1, -1, -1, -1, -1, "", GRAY, timerLength); } /*! @@ -113,8 +112,8 @@ Canvas::Canvas(double timerLength) { * A value less than or equal to 0 sets it to automatic. * \return A new Canvas with the specified position, dimensions, title, and draw cycle length. */ -Canvas::Canvas(int x, int y, int width, int height, std::string title, double timerLength) { - init(x, y, width, height, width*height*2, title, timerLength); +Canvas::Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor, double timerLength) { + init(x, y, width, height, width*height*2, title, backgroundColor, timerLength); } /*! @@ -124,12 +123,11 @@ Canvas::Canvas(int x, int y, int width, int height, std::string title, double ti */ Canvas::~Canvas() { // Free our pointer memory - delete myDrawables; - delete drawableBuffer; - delete[] proceduralBuffer; delete drawTimer; - delete[] vertexData; delete [] screenBuffer; + if (defaultBackground) { + delete myBackground; + } if (--openCanvases == 0) { glfwIsReady = false; glfwTerminate(); // Terminate GLFW @@ -171,9 +169,9 @@ void Canvas::buttonCallback(GLFWwindow* window, int button, int action, int mods * \brief Clears the Canvas. * \details This function clears the screen to the color specified in setBackgroundColor(). */ -// void Canvas::clearProcedural() { -// drawRectangle(0,0,getWindowWidth(),getWindowHeight(),getBackgroundColor()); -// } +void Canvas::clearBackground() { + myBackground->clear(); +} /*! * \brief Closes the Canvas window. @@ -199,7 +197,6 @@ void Canvas::close() { void Canvas::add(Drawable * shapePtr) { objectMutex.lock(); objectBuffer.push_back(shapePtr); - objectBufferEmpty = false; objectMutex.unlock(); } @@ -245,15 +242,6 @@ void Canvas::draw() glfwGetFramebufferSize(window, &fbw, &fbh); int scaling = round((1.0f*fbw)/winWidth); - if (hasStereo) - Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); - else - Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); - - setBackgroundColor(bgcolor); //Set our initial clear / background color - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { drawTimer->sleep(true); @@ -261,7 +249,6 @@ void Canvas::draw() syncMutex.lock(); #ifdef __APPLE__ - // leftWindowIndex = 0; windowMutex.lock(); #endif glfwMakeContextCurrent(window); @@ -270,10 +257,14 @@ void Canvas::draw() if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; std::cout.flush(); - // set it up so draw calls write into the framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, multisampledFBO); - glEnable(GL_DEPTH_TEST); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + // clear default framebuffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // if background initialized draw it using its multisampled framebuffer + if (myBackground) + if (myBackground->isInitialized()) { + myBackground->draw(); + } // Scale to window size GLint windowWidth, windowHeight; @@ -282,12 +273,8 @@ void Canvas::draw() winWidth = windowWidth; winHeight = windowHeight; - // Draw stuff - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (objectBuffer.size() > 0) { - // sort between opaques and transparents and then sort by center z. not perfect, but pretty good. - // depth buffer takes care of the rest. + // sort between opaques and transparents and then sort by center z. depth buffer takes care of the rest. not perfect, but good. std::stable_sort(objectBuffer.begin(), objectBuffer.end(), [](Drawable * a, Drawable * b)->bool { if (a->getAlpha() == 1.0 && b->getAlpha() != 1.0) return true; @@ -309,53 +296,14 @@ void Canvas::draw() } } } - } else { - objectBufferEmpty = true; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); - glBlitFramebuffer(0, 0, winWidth, winHeight, 0, 0, winWidth, winHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - // actually render everything in the framebuffer to the screen - glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - glDisable(GL_DEPTH_TEST); - - selectShaders(TEXTURE_SHADER_TYPE); - - unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); - glUniform1f(alphaLoc, 1.0f); - - const float vertices[30] = { - -winWidth/2,-winHeight/2,0,0,0, - winWidth/2,-winHeight/2,0,1,0, - -winWidth/2, winHeight/2,0,0,1, - winWidth/2,-winHeight/2,0,1,0, - -winWidth/2, winHeight/2,0,0,1, - winWidth/2, winHeight/2,0,1,1 - }; - glBindTexture(GL_TEXTURE_2D,renderedTexture); - /* these 5 lines don't seem to do anything */ - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - /* next two lines are very essential */ - glBufferData(GL_ARRAY_BUFFER,30*sizeof(float),vertices,GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLES,0,6); - glFlush(); // Flush buffer data to the actual draw buffer - - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - - // set it up so TSGL reads from the framebuffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - // screenshots and testing - // read from the framebuffer into the screenbuffer - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); if (toRecord > 0) { + // Update our screenBuffer copy with the default framebuffer + glViewport(0,0,winWidth*scaling,winHeight*scaling); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); + // glFlush(); // this should hopefully fix the lines in screenshot() bug. If not here, one line up. screenShot(); --toRecord; } @@ -378,1281 +326,6 @@ void Canvas::draw() } } -/* void Canvas::draw() { - // Reset the window - glfwSetWindowShouldClose(window, GL_FALSE); - - // Get actual framebuffer size and adjust scaling accordingly - int fbw, fbh; - glfwGetFramebufferSize(window, &fbw, &fbh); - int scaling = round((1.0f*fbw)/winWidth); - - if (hasStereo) - Canvas::setDrawBuffer(hasBackbuffer ? GL_FRONT_AND_BACK : GL_FRONT); - else - Canvas::setDrawBuffer(hasBackbuffer ? GL_LEFT : GL_FRONT_LEFT); - - - setBackgroundColor(bgcolor); //Set our initial clear / background color - // glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - readyToDraw = true; - bool newThingDrawn = true; //Always draw the first frame - int frame = 0; - - // Start the drawing loop - for (frameCounter = 0; !glfwWindowShouldClose(window); frameCounter++) { - drawTimer->sleep(true); - - syncMutex.lock(); - - int leftWindowIndex; - - #ifdef __APPLE__ - leftWindowIndex = 0; - windowMutex.lock(); - #else - leftWindowIndex = -1; - #endif - glfwMakeContextCurrent(window); // We're drawing to window as soon as it's created - - realFPS = round(1 / drawTimer->getTimeBetweenSleeps()); - if (showFPS) std::cout << realFPS << "/" << FPS << std::endl; - std::cout.flush(); - - bufferMutex.lock(); // Time to flush our buffer - if (drawableBuffer->size() > 0) { // But only if there is anything to flush - newThingDrawn = true; - for (unsigned int i = 0; i < drawableBuffer->size(); i++) - myDrawables->push((*drawableBuffer)[i]); - drawableBuffer->shallowClear(); // We want to clear the buffer but not delete those objects as we still need to draw them - } - bufferMutex.unlock(); - - int pos = pointBufferPosition; - int posLast = pointLastPosition; - - if (loopAround || pos != posLast) - newThingDrawn = true; - - if (newThingDrawn || !objectBufferEmpty) { - - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, frameBuffer); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - glViewport(0,0,winWidth,winHeight); - - if (frame == 0 || !objectBufferEmpty) { - glClear(GL_COLOR_BUFFER_BIT); - if(frame > 1) { - selectShaders(true); - loader.drawGLtextureFromBuffer(proceduralBuffer, leftWindowIndex, 0, winWidth, winHeight, GL_RGB); - selectShaders(false); - } - } - - if(frame > 0) { - unsigned int size = myDrawables->size(); - for (unsigned int i = 0; i < size; i++) { - Drawable* d = (*myDrawables)[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - selectShaders(true); - d->draw(); - selectShaders(false); - } - } - } - - if (loopAround) { - newThingDrawn = true; - int toend = myDrawables->capacity() - posLast; - glBufferData(GL_ARRAY_BUFFER, toend * 6 * sizeof(float), - &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, toend); - posLast = 0; - loopAround = false; - } - int pbsize = pos - posLast; - if (pbsize > 0) { - newThingDrawn = true; - glBufferData(GL_ARRAY_BUFFER, pbsize * 6 * sizeof(float), &vertexData[posLast * 6], GL_DYNAMIC_DRAW); - glDrawArrays(GL_POINTS, 0, pbsize); - } - pointLastPosition = pos; - } - - if(frame > 0) { - if(newThingDrawn) { - glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, proceduralBuffer); - } - // Reset drawn status for the next frame - newThingDrawn = false; - frame = 2; - } else { - frame = 1; - } - - if (objectBuffer.size() > 0) { - for (unsigned int i = 0; i < objectBuffer.size(); i++) { - Drawable* d = objectBuffer[i]; - if(d->isProcessed()) { - if (!d->getIsTextured()) { - d->draw(); - } else { - selectShaders(true); - d->draw(); - selectShaders(false); - } - } - } - } else { - objectBufferEmpty = true; - } - } - - // Update our screenBuffer copy with the screen - glViewport(0,0,winWidth*scaling,winHeight*scaling); - if(frame > 1) { - myDrawables->clear(); // Clear our buffer of shapes to be drawn - } - - // not sure what the point of this chunk is. - if (hasEXTFramebuffer) - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - else - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, frameBuffer); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // screenshots and testing - glReadPixels(0, 0, winWidthPadded, winHeight, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer); - if (toRecord > 0) { - screenShot(); - --toRecord; - } - - // very vital - glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); - // apparently not very vital at all - glDrawBuffer(drawBuffer); - - selectShaders(true); - const float vertices[32] = { - 0, 0, 1,1,1,1,0,1, - winWidth,0, 1,1,1,1,1,1, - 0, winHeight,1,1,1,1,0,0, - winWidth,winHeight,1,1,1,1,1,0 - }; - glBindTexture(GL_TEXTURE_2D,renderedTexture); - // these 5 lines don't seem to do anything - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - // next two lines are very essential - glBufferData(GL_ARRAY_BUFFER,32*sizeof(float),vertices,GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP,0,4); - glFlush(); // Flush buffer data to the actual draw buffer - glfwSwapBuffers(window); // Swap out GL's back buffer and actually draw to the window - - selectShaders(false); - - #ifndef __APPLE__ - glfwPollEvents(); // Handle any I/O - #endif - glfwGetCursorPos(window, &mouseX, &mouseY); - glfwMakeContextCurrent(NULL); // We're drawing to window as soon as it's created - #ifdef __APPLE__ - windowMutex.unlock(); - #endif - - syncMutex.unlock(); - - if (toClose) glfwSetWindowShouldClose(window, GL_TRUE); - } -} */ - -// /*! -// * \brief Draws a monocolored arrow. -// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status -// * \param x1 The x coordinate of the first endpoint. -// * \param y1 The y coordinate of the first endpoint. -// * \param x2 The x coordinate of the second endpoint. -// * \param y2 The y coordinate of the second endpoint. -// * \param color A single color for the arrow. -// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. -// */ -// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow) { -// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); -// drawDrawable(arrow); -// } - -// /*! -// * \brief Draws a multicolored arrow. -// * \details This function draws an arrow with the given endpoints, color, and doubleheaded status -// * \param x1 The x coordinate of the first endpoint. -// * \param y1 The y coordinate of the first endpoint. -// * \param x2 The x coordinate of the second endpoint. -// * \param y2 The y coordinate of the second endpoint. -// * \param color An array of colors for the circle. -// * \param doubleArrow Boolean value that determines if the first endpoint is also an arrowhead. -// */ -// void Canvas::drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow) { -// Arrow * arrow = new Arrow(x1, y1, x2, y2, color, doubleArrow); -// drawDrawable(arrow); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined circle. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param color A single color for the circle. -// * \param filled Whether the circle should be filled -// * (set to true by default). -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color, bool filled) { -// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined circle. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param color An array of colors for the circle. -// * \param filled Whether the circle should be filled -// * (set to true by default). -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat color[], bool filled) { -// Circle* c = new Circle(x, y, radius, color, filled); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with different monocolored fill and outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor A single color for circle's fill vertices. -// * \param outlineColor A single color for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with multicolored fill and monocolored outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor An array of colors for circle's fill vertices. -// * \param outlineColor A single color for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with monocolored fill and multicolored outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor A single color for circle's fill vertices. -// * \param outlineColor An array of colors for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined circle with different multicolored fill and outline. -// * \details This function draws a circle with the given center, radius, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the circle's center. -// * \param y The y coordinate of the circle's center. -// * \param radius The radius of the circle in pixels. -// * \param fillColor An array of colors for circle's fill vertices. -// * \param outlineColor An array of colors for circle's outline vertices. -// */ -// void Canvas::drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]) { -// Circle* c = new Circle(x, y, radius, fillColor, outlineColor); // Creates the Line with the specified coordinates and color -// drawDrawable(c); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined concave polygon. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param color A single color for the said vertices. -// * \param filled Whether the ConcavePolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined concave polygon. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the ConcavePolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with different monocolored fill and outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with multicolored fill and monocolored outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with monocolored fill and multicolored outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined concave polygon with different multicolored fill and outline. -// * \details This function draws a ConcavePolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of said vertices. -// * \param y An array of y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \warning This function is significantly slower than drawConvexPolygon(). It is not recommended -// * that you draw convex polygons with this function. -// * \see drawConvexPolygon(). -// */ -// void Canvas::drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// ConcavePolygon* p = new ConcavePolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined convex polygon. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param color A single color for the said vertices. -// * \param filled Whether the ConvexPolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined convex polygon. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the ConvexPolygon should be filled in or not -// * (set to true by default). -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with different monocolored fill and outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with multicolored fill and monocolored outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with monocolored fill and multicolored outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined convex polygon with different multicolored fill and outline. -// * \details This function draws a ConvexPolygon with the given vertex data, specified as the -// * outer perimeter of the polygon. -// * \param size The number of vertices in the polygon. -// * \param x An array of the x positions of said vertices. -// * \param y An array of the y positions of said vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the ConvexPolygon in radians clockwise. -// * \note The difference between a convex polygon and a concave polygon -// * is that a convex polygon has all interior angles less than -// * 180 degrees ( see http://www.mathopenref.com/polygonconvex.html ). -// */ -// void Canvas::drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// ConvexPolygon* p = new ConvexPolygon(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a Drawable object -// * \details This function pushes any Drawable object onto the drawable buffer -// * \param d The Drawable object to be drawn -// * \note protected method -// */ -// void Canvas::drawDrawable(Drawable* d) { -// if (!started) { -// TsglDebug("No drawing before Canvas is started! Ignoring draw request."); -// return; -// } -// while (!readyToDraw) -// sleep(); -// bufferMutex.lock(); -// drawableBuffer->push(d); // Push it onto our drawing buffer -// bufferMutex.unlock(); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined ellipse. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param color A single color for ellipse. -// * \param filled Whether the ellipse should be filled -// * (set to true by default). -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined ellipse. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), color, and fill status. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param color An array of colors for ellipse. -// * \param filled Whether the ellipse should be filled -// * (set to true by default). -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, color, filled); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with different monocolored fill and outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor A single color for ellipse's fill vertices. -// * \param outlineColor A single color for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with multicolored fill and monocolored outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor An array of colors for ellipse's fill vertices. -// * \param outlineColor A single color for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with monocolored fill and multicolored outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor A single color for ellipse's fill vertices. -// * \param outlineColor An array of colors for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws a filled and outlined ellipse with different multicolored fill and outline. -// * \details This function draws an ellipse with the given center, radii, resolution -// * (number of sides), colors. -// * \param x The x coordinate of the ellipse's center. -// * \param y The y coordinate of the ellipse's center. -// * \param xRadius The x radius of the ellipse in pixels. -// * \param yRadius The x radius of the ellipse in pixels. -// * \param sides The number of sides to use in the ellipse. -// * \param fillColor An array of colors for ellipse's fill vertices. -// * \param outlineColor An array of colors for ellipse's outline vertices. -// * \param rotation Rotation of the ellipse in radians clockwise. -// */ -// void Canvas::drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Ellipse * e = new Ellipse(x, y, xRadius, yRadius, fillColor, outlineColor); -// e->setRotation(rotation); -// drawDrawable(e); -// } - -// /*! -// * \brief Draws an image. -// * \details This function draws an Image with the given coordinates and dimensions. -// * \param filename The name of the file to load the image from. -// * \param x The x coordinate of the Image's left edge. -// * \param y The y coordinate of the Image's top edge. -// * \param width The width of the Image. -// * \param height The height of the Image. -// * \param alpha The alpha with which to draw the Image -// * \param rotation Rotation of the Image in radians clockwise. -// */ -// void Canvas::drawImage(std::string filename, int x, int y, int width, int height, float alpha, float rotation) { -// Image* im = new Image(filename, loader, x, y, width, height, alpha); // Creates the Image with the specified coordinates -// im->setRotation(rotation); -// drawDrawable(im); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored line. -// * \details This function draws a Line at the given coordinates with the given color. -// * \param x1 The x position of the start of the line. -// * \param y1 The y position of the start of the line. -// * \param x2 The x position of the end of the line. -// * \param y2 The y position of the end of the line. -// * \param color The color of the line -// * (set to BLACK by default). -// * \param rotation Rotation of the line in radians clockwise. -// */ -// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color, float rotation) { -// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color -// l->setRotation(rotation); -// drawDrawable(l); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored line. -// * \details This function draws a Line at the given coordinates with the given color. -// * \param x1 The x position of the start of the line. -// * \param y1 The y position of the start of the line. -// * \param x2 The x position of the end of the line. -// * \param y2 The y position of the end of the line. -// * \param color A color array for the line. -// * \param rotation Rotation of the line in radians clockwise. -// */ -// void Canvas::drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation) { -// Line* l = new Line(x1, y1, x2, y2, color); // Creates the Line with the specified coordinates and color -// l->setRotation(rotation); -// drawDrawable(l); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a single pixel, specified in row,column format. -// * \details This function draws a pixel at the given screen coordinates with the given color. -// * \note (0,0) signifies the top-left of the screen when working with a Canvas object. -// * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas object. -// * \param row The row (y-position) of the pixel. -// * \param col The column (x-position) of the pixel. -// * \param color The color of the point (set to BLACK by default). -// * \param rotation Rotation of the ConcavePolygon in radians clockwise. -// * \see drawPoint() -// */ -// inline void Canvas::drawPixel(int row, int col, ColorFloat color) { -// drawPoint(col, row, color); -// } - -// /*! -// * \brief Draws a single pixel, specified in x,y format. -// * \details This function draws a pixel at the given Cartesian coordinates with the given color. -// * \note (0,0) signifies the left-top of the screen when working with a Canvas object. -// * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas object. -// * \param x The x position of the point. -// * \param y The y position of the point. -// * \param color The color of the point (set to BLACK by default). -// * \see drawPixel() -// */ -// void Canvas::drawPoint(int x, int y, ColorFloat color) { -// pointArrayMutex.lock(); -// if (pointBufferPosition >= myDrawables->capacity()) { -// loopAround = true; -// pointBufferPosition = 0; -// } -// int tempPos = pointBufferPosition * 6; -// pointBufferPosition++; - -// float atioff = atiCard ? 0.5f : 0.0f; -// vertexData[tempPos] = x; -// vertexData[tempPos + 1] = y+atioff; -// vertexData[tempPos + 2] = color.R; -// vertexData[tempPos + 3] = color.G; -// vertexData[tempPos + 4] = color.B; -// vertexData[tempPos + 5] = color.A; -// pointArrayMutex.unlock(); -// } - -// /*! -// * \brief Draws a monocolored series of connected lines. -// * \details This function draws Polyline at the given coordinates with the given color. -// * \param size The number of vertices of the polyline. -// * \param x An array of the x positions of the polyline's vertices. -// * \param y An array of the y positions of the polyline's vertices. -// * \param color A color for the Polyline. -// * \param rotation Rotation of the Polyline in radians clockwise. -// */ -// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation) { -// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored series of connected lines. -// * \details This function draws Polyline at the given coordinates with the given color. -// * \param size The number of vertices of the polyline. -// * \param x An array of the x positions of the polyline's vertices. -// * \param y An array of the y positions of the polyline's vertices. -// * \param color A color array for the Polyline. -// * \param rotation Rotation of the Polyline in radians clockwise. -// */ -// void Canvas::drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation) { -// Polyline* p = new Polyline(size, x, y, color); // Creates the Line with the specified coordinates and color -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a progress bar. -// * \details This function draws a previously created ProgressBar to the Canvas, as -// * specified in that ProgressBar's constructor. -// * \param p A pointer to a ProgressBar. -// * \note There is no equivalent function for CartesianCanvas. If you'd like to draw -// * a ProgressBar on a CartesianCanvas, you can still use this function, but you must -// * use absolute Canvas coordinates rather than the scaled CartesianCanvas coordinates. -// */ -// void Canvas::drawProgress(ProgressBar* p) { -// for (int i = 0; i < p->getSegs(); ++i) { -// drawDrawable(p->getRect(i)); -// drawDrawable(p->getBorder(i)); -// } -// } - -// /*! -// * \brief Draws a monocolored filled or outlined rectangle. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param color A single color for Rectangle. -// * \param filled Whether the Rectangle should be filled -// * (set to true by default). -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined rectangle. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param color An array of colors for Rectangle. -// * \param filled Whether the Rectangle should be filled -// * (set to true by default). -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, color, filled); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with different monocolored fill and outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor A single color for Rectangle's fill vertices. -// * \param outlineColor A single color for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with multicolored fill and monocolored outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor An array of colors for Rectangle's fill vertices. -// * \param outlineColor A single color for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with monocolored fill and multicolored outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor A single color for Rectangle's fill vertices. -// * \param outlineColor An array of colors for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined rectangle with different multicolored fill and outline. -// * \details This function draws a Rectangle with the given coordinates, dimensions, and color. -// * \param x The x coordinate of the Rectangle's left edge. -// * \param y The y coordinate of the Rectangle's top edge. -// * \param w The Rectangle's width. -// * \param h The Rectangle's height. -// * \param fillColor An array of colors for Rectangle's fill vertices. -// * \param outlineColor An array of colors for Rectangle's outline vertices. -// * \param rotation Rotation of the Rectangle in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Rectangle may not get drawn on some machines. -// */ -// void Canvas::drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Rectangle* rec = new Rectangle(x, y, w, h, fillColor, outlineColor); // Creates the Rectangle with the specified coordinates and color -// rec->setRotation(rotation); -// drawDrawable(rec); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined regular polygon. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param color A single color for RegularPolygon. -// * \param filled Whether the regular polygon should be filled -// * (set to true by default). -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color, bool filled, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined regular polygon. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and color -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param color An array of colors for RegularPolygon. -// * \param filled Whether the regular polygon should be filled -// * (set to true by default). -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, color, filled); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with different monocolored fill and outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor A single color for RegularPolygon's fill vertices. -// * \param outlineColor A single color for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with multicolored fill and monocolored outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor An array of colors for RegularPolygon's fill vertices. -// * \param outlineColor A single color for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with monocolored fill and multicolored outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor A single color for RegularPolygon's fill vertices. -// * \param outlineColor An array of colors for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a filled and outlined regular polygon with different multicolored fill and outline. -// * \details This function draws a RegularPolygon with the given coordinates, radius, sides, and colors -// * \param x The x coordinate of the RegularPolygon's center -// * \param y The y coordinate of the RegularPolygon's center -// * \param radius The distance from the center to each vertex -// * \param sides The number of sides for the RegularPolygon -// * \param fillColor An array of colors for RegularPolygon's fill vertices. -// * \param outlineColor An array of colors for RegularPolygon's outline vertices. -// * \param rotation Rotation of the RegularPolygon in radians clockwise. -// */ -// void Canvas::drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// RegularPolygon *c = new RegularPolygon(x, y, radius, sides, fillColor, outlineColor); -// c->setRotation(rotation); -// drawDrawable(c); -// } - -// /*! -// * \brief Draws a monocolored filled or outlined square. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param color A single color for Square. -// * \param filled Whether the Square should be filled -// * (set to true by default). -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled, float rotation) { -// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined Square. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param color An array of colors for Square. -// * \param filled Whether the Square should be filled -// * (set to true by default). -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled, float rotation) { -// Square* s = new Square(x1, y1, sideLength, color, filled); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with different monocolored fill and outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor A single color for Square's fill vertices. -// * \param outlineColor A single color for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with multicolored fill and monocolored outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor An array of colors for Square's fill vertices. -// * \param outlineColor A single color for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with monocolored fill and multicolored outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor A single color for Square's fill vertices. -// * \param outlineColor An array of colors for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined Square with different multicolored fill and outline. -// * \details This function draws a Square with the given coordinates, dimensions, and color. -// * \param x1 The x coordinate of the Square's left edge. -// * \param y1 The y coordinate of the Square's top edge. -// * \param x2 The x coordinate of the Square's right edge. -// * \param y2 The y coordinate of the Square's bottom edge. -// * \param fillColor An array of colors for Square's fill vertices. -// * \param outlineColor An array of colors for Square's outline vertices. -// * \param rotation Rotation of the Square in radians clockwise. -// * \bug The bottom-right pixel of a non-filled Square may not get drawn on some machines. -// */ -// void Canvas::drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Square* s = new Square(x1, y1, sideLength, fillColor, outlineColor); // Creates the Square with the specified coordinates and color -// s->setRotation(rotation); -// drawDrawable(s); // Push it onto our drawing buffer -// } - - -// /*! -// * \brief Draws a monocolored filled or outlined star. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param color A single color or array of colors for the star vertices. -// * \param filled Whether the star should be filled -// * (set to true by default). -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color, bool filled, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, color, filled, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a multicolored filled or outlined star. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param color A single color or array of colors for the star vertices. -// * \param filled Whether the star should be filled -// * (set to true by default). -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat color[], bool filled, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, color, filled, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with different monocolored fill and outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with multicolored fill and monocolored outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with monocolored fill and multicolored outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - -// /*! -// * \brief Draws a filled and outlined star with different multicolored fill and outline. -// * \details This function draws a Star with the given coordinates, radius, points, and color. -// * \param x1 The x coordinate of the star's center -// * \param y1 The y coordinate of the star's center -// * \param radius Radius of the outer points of the star -// * \param points The number of points on the star -// * \param fillColor A single color or array of colors for the star's fill vertices. -// * \param outlineColor A single color or array of colors for the star's outline vertices. -// * \param ninja makes it look conventional or like a shuriken -// * \param rotation Rotation of the star in radians clockwise. -// */ -// void Canvas::drawStar(int x, int y, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja, float rotation) { -// Star * star = new Star(x, y, radius, points, fillColor, outlineColor, ninja); -// star->setRotation(rotation); -// drawDrawable(star); -// } - // /*! // * \brief Draw a string of text. // * \details This function draws a given string of Text at the given coordinates with the given color. @@ -1669,257 +342,24 @@ void Canvas::draw() // drawText(ws, x, y, size, color, fontFileName, rotation); // } -// /*! -// * \brief Draws a UTF8-encoded string of text. -// * \details This function draws a given string of UTF-8 encoded Text at the given coordinates with the given color. -// * \param text The UTF8-encoded string to draw. -// * \param x The x coordinate of the text's left bound. -// * \param y The y coordinate of the text's left bound. -// * \param size The size of the text in pixels. -// * \param color The color of the Text (set to BLACK by default). -// * \param rotation Rotation of the Text in radians clockwise. -// * \note Identical to the drawText(std::string, ...) aside from the first parameter. -// * \see drawText(std::string s, int x, int y, unsigned size, ColorFloat color = BLACK). -// */ -// void Canvas::drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color, std::string fontFileName, float rotation) { -// Text* t = new Text(text, x, y, size, color); // Creates the Point with the specified coordinates and color -// if(fontFileName != defaultFontFileName && fontFileName != "") { -// t->setFont(fontFileName); -// } else { -// if(defaultFontFileName != "") { -// t->setFont(defaultFontFileName); -// } -// } -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a monocolored filled or outlined triangle. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param color A single color for the Triangle vertices. -// * \param filled Whether the Triangle should be filled (set to true by default). -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a multicolored filled or outlined triangle. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param color An array of colors for the Triangle vertices. -// * \param filled Whether the Triangle should be filled (set to true by default). -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, color, filled); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with different monocolored fill and outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor A single color for the Triangle's fill vertices. -// * \param outlineColor A single color for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with multicolored fill and monocolored outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor An array of colors for the Triangle's fill vertices. -// * \param outlineColor A single color for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with monocolored fill and multicolored outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor A single color for the Triangle's fill vertices. -// * \param outlineColor An array of colors for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws a filled and outlined triangle with different multicolored fill and outline. -// * \details This function draws a Triangle with the given vertices. -// * \param x1 The x coordinate of the first vertex of the Triangle. -// * \param y1 The y coordinate of the first vertex of the Triangle. -// * \param x2 The x coordinate of the second vertex of the Triangle. -// * \param y2 The y coordinate of the second vertex of the Triangle. -// * \param x3 The x coordinate of the third vertex of the Triangle. -// * \param y3 The y coordinate of the third vertex of the Triangle. -// * \param fillColor An array of colors for the Triangle's fill vertices. -// * \param outlineColor An array of colors for the Triangle's outline vertices. -// * \param rotation Rotation of the Triangle in radians clockwise. -// */ -// void Canvas::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// Triangle* t = new Triangle(x1, y1, x2, y2, x3, y3, fillColor, outlineColor); // Creates the Triangle with the specified vertices and color -// t->setRotation(rotation); -// drawDrawable(t); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled or outlined monocolored triangle strip. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param color A single color for the vertices. -// * \param filled Whether the triangle strip should be filled (true) or not (false). -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled or outlined multicolored triangle strip. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param color An array of colors for the said vertices. -// * \param filled Whether the triangle strip should be filled (true) or not (false). -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, color, filled); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with different monocolored fill and outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with multicolored fill and monocolored outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor A single color for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with monocolored fill and multicolored outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor A single color for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - -// /*! -// * \brief Draws an arbitrary filled and outlined triangle strip with different multicolored fill and outline. -// * \details This function draws a TriangleStrip with the given vertex data, specified as -// * a triangle strip. -// * \param size The number of vertices in the polygon. -// * \param x An array of x positions of the vertices. -// * \param y An array of y positions of the vertices. -// * \param fillColor An array of colors for the fill vertices. -// * \param outlineColor An array of colors for the outline vertices. -// * \param rotation Rotation of the TriangleStrip in radians clockwise. -// */ -// void Canvas::drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation) { -// TriangleStrip* p = new TriangleStrip(size, x, y, fillColor, outlineColor); -// p->setRotation(rotation); -// drawDrawable(p); // Push it onto our drawing buffer -// } - void Canvas::errorCallback(int error, const char* string) { fprintf(stderr, "%i: %s\n", error, string); } + /*! + * \brief Accessor for the current background. + * \return The Background that the Canvas draws when draw() is called. + */ +Background * Canvas::getBackground() { + return myBackground; +} + /*! * \brief Accessor for the current background color. * \return The color that the Canvas clears to when clear() is called. */ ColorFloat Canvas::getBackgroundColor() { - return bgcolor; + return myBackground->getClearColor(); } /*! @@ -1957,20 +397,12 @@ float Canvas::getFPS() { return realFPS; } - /*! - * \brief Accessor for window's closed status. - * \return Whether the window is still open (that is, the user has not closed it). - */ -bool Canvas::isOpen() { - return !isFinished; -} - /*! * \brief Accessor for the mouse's x-position. * \return The x coordinates of the mouse on the Canvas. */ int Canvas::getMouseX() { - return mouseX; + return mouseX - winWidth/2; } /*! @@ -1978,43 +410,7 @@ int Canvas::getMouseX() { * \return The y coordinates of the mouse on the Canvas. */ int Canvas::getMouseY() { - return mouseY; -} - - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in row,column format. - * \note (0,0) signifies the top-left of the screen when working with a Canvas object. - * \note (0,0) signifies the bottom-left of the screen when working with a CartesianCanvas. - * \note getPixel() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param row The row (y-position) of the pixel to grab. - * \param col The column (x-position) of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (col,row). - */ -ColorInt Canvas::getPixel(int row, int col) { - return getPoint(col,row); -} - - /*! - * \brief Gets the color of the pixel drawn on the current Canvas at the given screen coordinates, - * specified in x,y format. - * \note (0,0) signifies the left-top of the screen when working with a Canvas object. - * \note (0,0) signifies the left-bottom of the screen when working with a CartesianCanvas. - * \note getPoint() will return only what is currently drawn the screen. Any object waiting to be drawn - * will not affect what is returned. - * \param x The x position of the pixel to grab. - * \param y The y position of the pixel to grab. - * \return A ColorInt containing the color of the pixel at (x, y). - */ -ColorInt Canvas::getPoint(int x, int y) { - int yy; - //if (atiCard) - // yy = (winHeight) - y; //glReadPixels starts from the bottom left, and we have no way to change that... - //else - yy = (winHeight-1) - y; - int off = 3 * (yy * winWidthPadded + x); - return ColorInt(screenBuffer[off], screenBuffer[off + 1], screenBuffer[off + 2], 255); + return winHeight/2 - mouseY; } /*! @@ -2124,7 +520,7 @@ void Canvas::handleIO() { #endif } -void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string title, double timerLength) { +void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string title, ColorFloat backgroundColor, double timerLength) { ++openCanvases; if (ww == -1) @@ -2135,11 +531,10 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti winTitle = title; winWidth = ww, winHeight = hh; - aspect = (float) winWidth / winHeight; + // aspect = (float) winWidth / winHeight; keyDown = false; toClose = false; windowClosed = false; - readyToDraw = false; frameCounter = 0; syncMutexLocked = 0; syncMutexOwner = -1; @@ -2148,47 +543,36 @@ void Canvas::init(int xx, int yy, int ww, int hh, unsigned int b, std::string ti if (padwidth > 0) padwidth = 4-padwidth; winWidthPadded = winWidth + padwidth; - bufferSize = 3 * (winWidthPadded+1) * winHeight; - proceduralBufferSize = 4 * winWidth * winHeight; - screenBuffer = new uint8_t[bufferSize]; - proceduralBuffer = new GLubyte[proceduralBufferSize]; - for (unsigned i = 0; i < bufferSize; ++i) { + screenBuffer = new uint8_t[3 * (winWidthPadded+1) * winHeight]; + for (int i = 0; i < 3 * (winWidthPadded+1) * winHeight; ++i) { screenBuffer[i] = 0; } - for (unsigned i = 0; i < proceduralBufferSize; i++) { - proceduralBuffer[i] = 255; - } started = false; // We haven't started the window yet monitorX = xx; monitorY = yy; - myDrawables = new Array(b); // Initialize myDrawables - drawableBuffer = new Array(b); - // objectBuffer = new Array(b); - vertexData = new float[6 * b]; // Buffer for vertexes for points showFPS = false; // Set debugging FPS to false isFinished = false; // We're not done rendering - pointBufferPosition = pointLastPosition = 0; - loopAround = false; toRecord = 0; - objectBufferEmpty = true; - bgcolor = GRAY; window = nullptr; + defaultBackground = true; + myBackground = nullptr; + drawTimer = new Timer((timerLength > 0.0f) ? timerLength : FRAME); for (int i = 0; i <= GLFW_KEY_LAST * 2 + 1; i++) boundKeys[i++] = nullptr; - defaultFontFileName = ""; - initGlfw(); #ifndef _WIN32 initWindow(); initGlew(); glfwMakeContextCurrent(NULL); // Reset the context #endif + initGl(); + initBackground(backgroundColor); } void Canvas::initGl() { @@ -2214,14 +598,6 @@ void Canvas::initGl() { toClose = true; }); - unsigned char stereo[1] = {5}, dbuff[1] = {5}; - int aux[1] = {5}; - glGetBooleanv(GL_STEREO,stereo); - glGetBooleanv(GL_DOUBLEBUFFER,dbuff); - glGetIntegerv(GL_AUX_BUFFERS,aux); - hasStereo = ((int)stereo[0] > 0); - hasBackbuffer = ((int)dbuff[0] > 0); - glfwMakeContextCurrent(NULL); // Reset the context } @@ -2257,6 +633,12 @@ void Canvas::initGlew() { glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); + textShader = new Shader(textVertexShader, textFragmentShader); + + shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); + + textureShader = new Shader(textureVertexShader, textureFragmentShader); + char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ char *res = realpath(".", buf); if (res) { @@ -2265,46 +647,6 @@ void Canvas::initGlew() { perror("realpath"); exit(EXIT_FAILURE); } - - textShader = new Shader(textVertexShader, textFragmentShader); - - shapeShader = new Shader(shapeVertexShader, shapeFragmentShader); - - textureShader = new Shader(textureVertexShader, textureFragmentShader); - - // configure MSAA framebuffer - // -------------------------- - glGenFramebuffers(1, &multisampledFBO); - glBindFramebuffer(GL_FRAMEBUFFER, multisampledFBO); - // create a multisampled color attachment texture - glGenTextures(1, &multisampledTexture); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, winWidth, winHeight, GL_TRUE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampledTexture, 0); - // create multisampled renderbuffer object - unsigned int rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, winWidth, winHeight); // use a single renderbuffer object for both a depth AND stencil buffer. - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it - - // Create a second framebuffer - intermediateFBO = 0; - glGenFramebuffers(1, &intermediateFBO); - glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); - // The texture we're going to render to - glGenTextures(1, &renderedTexture); - glBindTexture(GL_TEXTURE_2D, renderedTexture); - glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, winWidth, winHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - // Set "renderedTexture" as our colour attachement #0 - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,renderedTexture, 0); - - // Always check that our framebuffer is ok - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - TsglErr("FRAMEBUFFER CREATION FAILED"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); } void Canvas::initGlfw() { @@ -2315,6 +657,13 @@ void Canvas::initGlfw() { } } +void Canvas::initBackground(ColorFloat bgcolor) { + if (!myBackground) { + myBackground = new Background(winWidth, winHeight, bgcolor); + myBackground->init(shapeShader, textShader, textureShader, window); + } +} + void Canvas::initWindow() { glfwSetErrorCallback(errorCallback); @@ -2329,8 +678,8 @@ void Canvas::initWindow() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We're using the standard GL Profile glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Don't use methods that are deprecated in the target version #endif - // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window - glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Do not let the user resize the window + // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE); // Disable the back buffer glfwWindowHint(GLFW_STEREO, GL_FALSE); // Disable the right buffer glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Don't show the window at first glfwWindowHint(GLFW_SAMPLES,4); @@ -2374,6 +723,14 @@ void Canvas::initWindow() { printf("OpenGL version supported %s\n", glGetString(GL_VERSION)); } + /*! + * \brief Accessor for window's closed status. + * \return Whether the window is still open (that is, the user has not closed it). + */ +bool Canvas::isOpen() { + return !isFinished; +} + void Canvas::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { buttonCallback(window, key, action, mods); } @@ -2573,6 +930,22 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { if (can->scrollFunction) can->scrollFunction(xpos, ypos); } + /*! + * \brief Mutator for the Canvas Background. + * \details This function sets the Background which Canvas will draw. + * \param background A pointer to the new Background value which will be assigned to myBackground. + * \param previouslySet Boolean indicating if background has been previously set for this Canvas. + */ +void Canvas::setBackground(Background * background, bool previouslySet) { + if (myBackground != background) { + defaultBackground = false; + myBackground = background; + if (!previouslySet) { + background->init(shapeShader, textShader, textureShader, window); + } + } +} + /*! * \brief Mutator for the background color. * \details This function sets the clear color for when Canvas::clear() is called. @@ -2580,29 +953,13 @@ void Canvas::scrollCallback(GLFWwindow* window, double xpos, double ypos) { * \note The alpha channel of the color is ignored. */ void Canvas::setBackgroundColor(ColorFloat color) { - bgcolor = color; if (window != nullptr) { glfwMakeContextCurrent(window); - glClearColor(color.R,color.G,color.B,color.A); + myBackground->setClearColor(color); glfwMakeContextCurrent(NULL); } } -void Canvas::setDrawBuffer(int buffer) { - Canvas::drawBuffer = buffer; -} - - /*! - * \brief Mutator for the currently loaded font. - * \details This function sets the font with the specified filename into memory. - * Subsequent calls to drawText() will use this font to print. - * \param filename The filename of the font to load. - * \note Supports all font types that FreeType supports. - */ -void Canvas::setFont(std::string filename) { - defaultFontFileName = filename; -} - /*! * \brief Mutator for showing the FPS. * \param b Whether to print the FPS to stdout every draw cycle (for debugging purposes). @@ -2676,14 +1033,12 @@ int Canvas::start() { #ifdef __APPLE__ void* Canvas::startDrawing(void* cPtr) { Canvas* c = (Canvas*)cPtr; - c->initGl(); c->draw(); c->isFinished = true; pthread_exit(NULL); } #else void Canvas::startDrawing(Canvas *c) { - c->initGl(); c->draw(); c->isFinished = true; glfwDestroyWindow(c->window); @@ -2789,283 +1144,4 @@ int Canvas::wait() { return 0; } - -void Canvas::setBackground(Background * background) { - myBackground = background; - background->defineShaders(shapeShader, textShader, textureShader); -} - -//-----------------Unit testing------------------------------------------------------- - /*! - * \brief Runs unit tests for the Canvas. - */ -// void Canvas::runTests() { -// TsglDebug("Testing Canvas class..."); -// Canvas c1(0, 0, 500, 500, "", FRAME); -// c1.setBackgroundColor(WHITE); -// c1.start(); -// tsglAssert(testFilledDraw(c1), "Unit test for filled draw failed!"); -// tsglAssert(testLine(c1), "Unit test for line failed!"); -// // tsglAssert(testAccessors(c1), "Unit test for accessors failed!"); -// tsglAssert(testDrawImage(c1), "Unit test for drawing images failed!"); -// c1.stop(); -// TsglDebug("Unit tests for Canvas complete."); -// std::cout << std::endl; -// } - -// //Similar format is used for the remaining unit tests -// bool Canvas::testFilledDraw(Canvas& can) { -// int passed = 0; //Passed tests -// int failed = 0; //Failed tests -// ColorInt red(255, 0, 0); //Fill color -// can.drawCircle(250, 250, 50, red, true); //Draw filled shape -// can.sleepFor(1); - -// //Test 1: Get middle pixel and see if its red. -// if(can.getPixel(250, 250) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, middle pixel for testFilledDraw() failed!"); -// } - -// //Test 2: Get leftmost and rightmost pixel of the circle -// //Have to add or subtract 1 from the y so that you can get the correct pixel (center radius is 1. No 0 radius). -// if(can.getPixel(250, 201) == red && can.getPixel(250, 299) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 2, leftmost and rightmost pixel for testFilledDraw() failed!"); -// } - -// //Test 3: Outside pixels shouldn't equal inside pixels -// int test = 0; -// //Single pixel.... -// if(can.getPixel(1, 1) != red) { -// //Multiple pixels.... -// for(int i = 201; i <= 299; i++) { -// if(can.getPixel(1, i) != red) { -// test++; -// } -// } -// //Results of multiple pixels... -// if(test == 99) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 3, outside != inside, Multiple pixels for testFilledDraw() failed!"); -// } -// } else { -// failed++; -// TsglErr("Test 3, outside != inside, Single pixel for testFilledDraw() failed!"); -// } - -// //Test 4: A LOT of the pixels on the inside should be red -// int count = 0; -// for(int i = 201; i <= 299; i++) { -// if(can.getPixel(250, i) == red) { -// count++; -// } -// } - -// //Now check the count, should be 99 -// if(count == 99) { -// passed++; -// } else { -// failed++; -// std::cout << "Count: " << count << std::endl; -// TsglErr("Test 4, multiple pixels for testFilledDraw() failed!"); -// } - -// //Determine if we passed all four tests or not, Results: -// if(passed == 4 && failed == 0) { -// // can.clearProcedural(); -// TsglDebug("Unit test for drawing filled shapes passed!"); -// return true; -// } else { -// // can.clearProcedural(); -// TsglErr("This many passed for testFilledDraw(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testFilledDraw(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } - -// bool Canvas::testLine(Canvas & can) { -// int passed = 0; -// int failed = 0; -// can.drawLine(0, 0, 250, 250, BLACK); //Diagonal line -// can.drawLine(253, 253, 400, 253); //Straight line -// can.sleepFor(1); -// ColorInt black(0, 0, 0); -// //Test 1: Near the ending endpoint? (Diagonal) -// if(can.getPoint(249, 249) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, Near the ending endpoint? for testLine() failed!"); -// } - -// //Test 2: Somewhere in the middle? (Diagonal) -// if(can.getPoint(155, 155) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 2, Somewhere in the middle? for testLine() failed!"); -// } - -// //Test 3: Near the starting endpoint? (Diagonal) -// if(can.getPoint(15, 15) == black) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 3, Near the starting endpoint? for testLine() failed!"); -// } - -// //Test 4: An entire line? (Straight) -// int count = 0; -// for(int i = 253; i <= 399; i++) { -// if(can.getPoint(i, 253) == black) { -// count++; -// } -// } - -// //Check the results of the Straight line test -// if(count == 147) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 4, An entire line? (Straight) for testLine() failed!"); -// } - -// //Results: -// if(passed == 4 && failed == 0) { -// // can.clearProcedural(); -// TsglDebug("Unit test for line passed!"); -// return true; -// } else { -// // can.clearProcedural(); -// TsglErr("This many passed testLine(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testLine(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } - -bool Canvas::testAccessors(Canvas& can) { - int passed = 0; - int failed = 0; - ColorFloat white = WHITE; //Have to set these to new variables so that I can compare them - ColorFloat black = BLACK; - - //Test 1: Background color - if(can.getBackgroundColor() == white) { - can.setBackgroundColor(BLACK); - if(can.getBackgroundColor() == black) { - passed++; - } else { - failed++; - TsglErr("Test 1, Background color for testAccessors() failed!"); - } - } - - //Test 2: Window width/height - //width - if(can.getWindowWidth() == 500) { - //height - if(can.getWindowHeight() == 500) { - passed++; - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (height)"); - } - } else { - failed++; - TsglErr("Test 2 for testAccessors() failed! (width)"); - } - - //Test 3: Window x/y - //x - if(can.getWindowX() == 0) { - //y - if(can.getWindowY() == 0) { - passed++; - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (y)"); - } - } else { - failed++; - TsglErr("Test 3 for testAccessors() failed! (x)"); - } - - //Test 4: Window open? - if(can.isOpen() == true) { - passed++; - } else { - failed++; - TsglErr("Test 4, Window open? for testAccessors() failed!"); - } - - //Results: - if(passed == 4 && failed == 0) { - // can.clearProcedural(); - TsglDebug("Unit test for accessors/mutators passed!"); - return true; - } else { - // can.clearProcedural(); - TsglErr("This many passed for testAccessors(): "); - std::cerr << " " << passed << std::endl; - TsglErr("This many failed for testAccessors(): "); - std::cerr << " " << failed << std::endl; - return false; - } -} - -// bool Canvas::testDrawImage(Canvas& can) { -// can.drawImage("../assets/pics/ff0000.png", 0, 0, 200, 200); -// can.sleepFor(1); -// int passed = 0; -// int failed = 0; -// ColorInt red(255, 0, 0); -// //Test 1: Single pixel -// if(can.getPoint(1, 1) == red) { -// passed++; -// } else { -// failed++; -// TsglErr("Test 1, Single pixel for testDrawImage() failed!"); -// } - -// //Test 2: Multiple pixels -// int count = 0; -// for(int i = 0; i < 200; i++) { -// if(can.getPoint(1, i) == red) { -// count++; -// } -// } - -// //Results of Test 2: -// if(count == 200) { -// passed++; -// } else { -// failed++; -// std::cout << "Count: " << count << std::endl; -// TsglErr("Test 2, Multiple pixels for testDrawImage() failed!"); -// } - -// //Results of entire Unit test:s -// if(passed == 2 && failed == 0) { -// TsglDebug("Unit test for drawing images passed!"); -// return true; -// } else { -// TsglErr("This many passed for testDrawImage(): "); -// std::cerr << " " << passed << std::endl; -// TsglErr("This many failed for testDrawImage(): "); -// std::cerr << " " << failed << std::endl; -// return false; -// } -// } -//------------End Unit testing-------------------------------------------------------- } diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index 23ecba6e8..ee5edf6f1 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -41,7 +41,7 @@ #include "TextureHandler.h" // Currently used for screenshots, might change this #include "Util.h" // Needed constants and has cmath for performing math operations -#include "shader_s.h" +#include "Shader.h" #include #include #include @@ -90,48 +90,30 @@ class Canvas { typedef std::function doubleFunction; typedef std::function voidFunction; - float aspect; // Aspect ratio used for setting up the window - ColorFloat bgcolor; // Color of the Canvas' clearRectangle + // float aspect; // Aspect ratio used for setting up the window voidFunction boundKeys [(GLFW_KEY_LAST+1)*2]; // Array of function objects for key binding - std::mutex bufferMutex; // Mutex for locking the render buffer so that only one thread can read/write at a time - unsigned bufferSize; // Size of the screen buffer - std::string defaultFontFileName; + bool defaultBackground; // Boolean indicating whether myBackground has been set by an external source Timer* drawTimer; // Timer to regulate drawing frequency - GLuint multisampledFBO; // Multisampled target buffer for rendering to renderedTexture - GLuint intermediateFBO; // Intermediate framebuffer into which multisampledFBO will be blitted int frameCounter; // Counter for the number of frames that have elapsed in the current session (for animations) - bool hasBackbuffer; // Whether or not the hardware supports double-buffering - bool hasStereo; // Whether or not the hardware supports stereoscopic rendering bool isFinished; // If the rendering is done, which will signal the window to close bool keyDown; // If a key is being pressed. Prevents an action from happening twice TextureHandler loader; // The TextureHandler that holds all our already loaded textures - bool loopAround; // Whether our point buffer has looped back to the beginning this int monitorX, monitorY; // Monitor position for upper left corner double mouseX, mouseY; // Location of the mouse once HandleIO() has been called - Array * myDrawables; // Our buffer of drawables to draw - std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame - bool objectBufferEmpty; // States whether the object buffer is empty/has been recently cleared + Background * myBackground; // Pointer to the Background drawn each frame + std::vector objectBuffer; // Holds a list of pointers to objects drawn each frame std::mutex objectMutex; - Array * drawableBuffer; // Our buffer of drawables that the can be pushed to, and will later be flushed to the shapes array - std::mutex pointArrayMutex; // Mutex for the allPoints array - unsigned int pointBufferPosition, pointLastPosition; // Holds the position of the allPoints array - bool readyToDraw; // Whether a Canvas is ready to start drawing int realFPS; // Actual FPS of drawing - GLuint renderedTexture; // Texture to which we render to every frame. Attached to intermediateFBO - GLuint multisampledTexture; // Texture attached to the multisampled framebuffer #ifdef __APPLE__ pthread_t renderThread; // Thread dedicated to rendering the Canvas #else std::thread renderThread; // Thread dedicated to rendering the Canvas #endif uint8_t* screenBuffer; // Array that is a copy of the screen - GLubyte* proceduralBuffer; // Array that is a copy of just the procedural portion of the window - unsigned proceduralBufferSize; doubleFunction scrollFunction; // Single function object for scrolling // Address of the vertex shader - Shader * textShader; - Shader * shapeShader; - Shader * textureShader; - std::mutex shapesMutex; // Mutex for locking the render array so that only one thread can read/write at a time + Shader * textShader; // Shader for Text class + Shader * shapeShader; // Shader for Shape class + Shader * textureShader; // Shader for Background and Image classes bool showFPS; // Flag to show DEBUGGING FPS bool started; // Whether our canvas is running and the frame counter is counting std::mutex syncMutex; // Mutex for syncing the rendering thread with a computational thread @@ -142,9 +124,8 @@ class Canvas { GLint uniModel, // Model perspective of the camera uniView, // View perspective of the camera uniProj; // Projection of the camera - GLuint VAO, // Address of GL's array buffer object - VBO; // Address of GL's vertex buffer object - float* vertexData; // The allPoints array + GLuint VAO, // Address of GL's vertex array object + VBO; // Address of GL's vertex buffer object GLFWwindow* window; // GLFW window that we will draw to bool windowClosed; // Whether we've closed the Canvas' window or not std::mutex windowMutex; // (OS X) Mutex for handling window contexts @@ -153,22 +134,20 @@ class Canvas { GLint winWidth; // Width of the Canvas' window GLint winWidthPadded; // Window width padded to a multiple of 4 (necessary for taking screenshots) - static int drawBuffer; // Buffer to use for drawing (set to GL_LEFT or GL_RIGHT) static bool glfwIsReady; // Whether or not we have info about our monitor static std::mutex glfwMutex; // Keeps GLFW createWindow from getting called at the same time in multiple threads static displayInfo monInfo; // Info about our display static unsigned openCanvases; // Total number of open Canvases - Background * myBackground; - static void buttonCallback(GLFWwindow* window, int key, int action, int mods); // GLFW callback for mouse buttons void draw(); // Draw loop for the Canvas static void errorCallback(int error, const char* string); // Display where an error is coming from void glDestroy(); // Destroys the GL and GLFW things that are specific for this canvas void init(int xx,int yy,int ww,int hh, - unsigned int b, std::string title, - double timerLength); // Method for initializing the canvas + unsigned int b, std::string title, + ColorFloat backgroundColor, double timerLength); // Method for initializing the canvas + void initBackground(ColorFloat bgcolor); // Initializes myBackground void initGl(); // Initializes the GL things specific to the Canvas void initGlew(); // Initialized the GLEW things specific to the Canvas static void initGlfw(); // Initalizes GLFW for all future canvases. @@ -185,12 +164,7 @@ class Canvas { #else static void startDrawing(Canvas *c); // Static method that is called by the render thread #endif - void selectShaders(unsigned int choice); // Turn textures on or off - // static bool testFilledDraw(Canvas& can); // Unit test for drawing shapes and determining if fill works - // static bool testLine(Canvas& can); // Unit tester for lines - static bool testAccessors(Canvas& can); // Unit tester for accessor methods - // static bool testDrawImage(Canvas& can); // Unit tester for drawing images (simultaneously a Unit test for Image) - + void selectShaders(unsigned int choice); // Select appropriate shader for type of Drawable protected: bool atiCard; // Whether the vendor of the graphics card is ATI void drawDrawable(Drawable* s); // Draw a drawable type @@ -198,7 +172,7 @@ class Canvas { Canvas(double timerLength = 0.0f); - Canvas(int x, int y, int width, int height, std::string title, double timerLength = 0.0f); + Canvas(int x, int y, int width, int height, std::string title, ColorFloat backgroundColor = GRAY, double timerLength = 0.0f); virtual ~Canvas(); @@ -206,159 +180,15 @@ class Canvas { void bindToScroll(std::function function); - // void clearProcedural(); - - void close(); - void add(Drawable * shapePtr); - void remove(Drawable * shapePtr); - - void clearObjectBuffer(bool shouldFreeMemory = false); - - // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color, bool doubleArrow = false); - - // virtual void drawArrow(float x1, float y1, float x2, float y2, const ColorFloat color[], bool doubleArrow = false); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat color, bool filled = true); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat color[], bool filled = true); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor, ColorFloat outlineColor[]); - - // virtual void drawCircle(int x, int y, int radius, ColorFloat fillColor[], ColorFloat outlineColor[]); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConcavePolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawConvexPolygon(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color, bool filled, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat color[], bool filled, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawEllipse(int x, int y, int xRadius, int yRadius, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawImage(std::string filename, int x, int y, int width, int height, float alpha = 1.0f, float rotation = 0); - - // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color = BLACK, float rotation = 0); - - // virtual void drawLine(int x1, int y1, int x2, int y2, ColorFloat color[], float rotation = 0); - - // virtual void drawPixel(int row, int col, ColorFloat color = BLACK); - - // virtual void drawPoint(int x, int y, ColorFloat color = BLACK); - - // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color, float rotation = 0); - - // virtual void drawPolyline(int size, int x[], int y[], ColorFloat color[], float rotation = 0); - - // virtual void drawProgress(ProgressBar* p); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat color[], bool filled = true, float rotation = 0); + void clearBackground(); - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRectangle(float x, float y, float w, float h, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color = BLACK, bool filled = true, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawRegularPolygon(int x, int y, int radius, int sides, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawSquare(int x1, int y1, int sideLength, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color, bool filled = true, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat color[], bool filled = true, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor, bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor, ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - // virtual void drawStar(int x1, int y1, int radius, int points, ColorFloat fillColor[], ColorFloat outlineColor[], bool ninja = false, float rotation = 0); - - // virtual void drawText(std::string text, int x, int y, unsigned size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - // virtual void drawText(std::wstring text, int x, int y, unsigned int size, ColorFloat color = BLACK, std::string fontFileName = "", float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color, bool filled = true, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat color[], bool filled = true, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor, float rotation = 0); - - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor, float rotation = 0); + void close(); - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor, ColorFloat outlineColor[], float rotation = 0); + void clearObjectBuffer(bool shouldFreeMemory = false); - // virtual void drawTriangleStrip(int size, int x[], int y[], ColorFloat fillColor[], ColorFloat outlineColor[], float rotation = 0); + Background * getBackground(); ColorFloat getBackgroundColor(); @@ -370,8 +200,6 @@ class Canvas { float getFPS(); - bool isOpen(); - int getMouseX(); int getMouseY(); @@ -398,10 +226,14 @@ class Canvas { void handleIO(); + bool isOpen(); + void pauseDrawing(); void recordForNumFrames(unsigned int num_frames); + void remove(Drawable * shapePtr); + void reset(); void resumeDrawing(); @@ -426,6 +258,8 @@ class Canvas { virtual void run(void (*myFunction)(Canvas&, int, std::string, bool), int i, std::string s, bool b); + void setBackground(Background * background, bool previouslySet = false); + void setBackgroundColor(ColorFloat color); void setFont(std::string filename); @@ -445,10 +279,6 @@ class Canvas { void takeScreenShot(); int wait(); - - // static void runTests(); - - void setBackground(Background * background); }; } diff --git a/src/TSGL/ConcavePolygon.cpp b/src/TSGL/ConcavePolygon.cpp index 4e1d3128a..0e6fa4898 100644 --- a/src/TSGL/ConcavePolygon.cpp +++ b/src/TSGL/ConcavePolygon.cpp @@ -28,16 +28,16 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int /*! * \brief Explicitly constructs a new ConcavePolygon with monocolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param centerX The x coordinate of the ConcavePolygon's center. - * \param centerY The y coordinate of the ConcavePolygon's center. - * \param centerZ The z coordinate of the ConcavePolygon's center. - * \param numVertices The number of vertices that make up the ConcavePolygon. - * \param x An array of the ConcavePolygon's x vertices. - * \param y An array of the ConcavePolygon's y vertices. - * \param yaw The ConcavePolygon's yaw in 3D space. - * \param pitch The ConcavePolygon's pitch in 3D space. - * \param roll The ConcavePolygon's roll in 3D space. - * \param color A ColorFloat, the ConcavePolygon's fill color. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color A ColorFloat, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { @@ -51,25 +51,26 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } /*! * \brief Explicitly constructs a new ConcavePolygon with multicolored fill. * \details Explicit constructor for a ConcavePolygon object. - * \param centerX The x coordinate of the ConcavePolygon's center. - * \param centerY The y coordinate of the ConcavePolygon's center. - * \param centerZ The z coordinate of the ConcavePolygon's center. - * \param numVertices The number of vertices that make up the ConcavePolygon. - * \param x An array of the ConcavePolygon's x vertices. - * \param y An array of the ConcavePolygon's y vertices. - * \param yaw The ConcavePolygon's yaw in 3D space. - * \param pitch The ConcavePolygon's pitch in 3D space. - * \param roll The ConcavePolygon's roll in 3D space. - * \param color An array of ColorFloats, the ConcavePolygon's fill color. + * \param centerX The x coordinate of the ConcavePolygon's center. + * \param centerY The y coordinate of the ConcavePolygon's center. + * \param centerZ The z coordinate of the ConcavePolygon's center. + * \param numVertices The number of vertices that make up the ConcavePolygon. + * \param x An array of the ConcavePolygon's x vertices. + * \param y An array of the ConcavePolygon's y vertices. + * \param yaw The ConcavePolygon's yaw in 3D space. + * \param pitch The ConcavePolygon's pitch in 3D space. + * \param roll The ConcavePolygon's roll in 3D space. + * \param color An array of ColorFloats, the ConcavePolygon's fill color. * \return A new ConcavePolygon with a buffer for storing the specified number of vertices. + * \warning Can sometimes incorrectly render; if this occurs, try shifting your last vertex to be your first vertex, or otherwise adjusting vertex order. */ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int numVertices, float x[], float y[], float yaw, float pitch, float roll, ColorFloat color[]) : Shape(centerX,centerY,centerZ,yaw,pitch,roll) { attribMutex.lock(); @@ -82,8 +83,8 @@ ConcavePolygon::ConcavePolygon(float centerX, float centerY, float centerZ, int outlineVertices = new GLfloat[numberOfOutlineVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color[i]); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } diff --git a/src/TSGL/ConvexPolygon.cpp b/src/TSGL/ConvexPolygon.cpp index 8c1933f6a..36cf4a83d 100644 --- a/src/TSGL/ConvexPolygon.cpp +++ b/src/TSGL/ConvexPolygon.cpp @@ -50,8 +50,8 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } @@ -80,8 +80,8 @@ ConvexPolygon::ConvexPolygon(float centerX, float centerY, float centerZ, int n myXScale = myYScale = myZScale = 1; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], 0, color[i]); - addOutlineVertex(x[i], y[i], 0, GRAY); + addVertex(x[i] - centerX, y[i] - centerY, 0, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, 0, GRAY); } } diff --git a/src/TSGL/Drawable.h b/src/TSGL/Drawable.h index 3193f4efa..b4f437dde 100644 --- a/src/TSGL/Drawable.h +++ b/src/TSGL/Drawable.h @@ -6,7 +6,7 @@ #define DRAWABLE_H_ #include "Color.h" // Needed for color type -#include "shader_s.h" +#include "Shader.h" #include #include #include diff --git a/src/TSGL/Polyline.cpp b/src/TSGL/Polyline.cpp index a08e6e9fb..0d5d2b99d 100644 --- a/src/TSGL/Polyline.cpp +++ b/src/TSGL/Polyline.cpp @@ -49,7 +49,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color); } } @@ -77,7 +77,7 @@ Polyline::Polyline(float x, float y, float z, int numVertices, float lineVertice vertices = new GLfloat[numberOfVertices * 7]; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(lineVertices[3*i], lineVertices[3*i + 1], lineVertices[3*i + 2], color[i]); + addVertex(lineVertices[3*i] - x, lineVertices[3*i + 1] - y, lineVertices[3*i + 2] - z, color[i]); } } diff --git a/src/TSGL/shader_s.h b/src/TSGL/Shader.h similarity index 100% rename from src/TSGL/shader_s.h rename to src/TSGL/Shader.h diff --git a/src/TSGL/TriangleStrip.cpp b/src/TSGL/TriangleStrip.cpp index 825d733f8..f0fb3bdcb 100644 --- a/src/TSGL/TriangleStrip.cpp +++ b/src/TSGL/TriangleStrip.cpp @@ -26,8 +26,8 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], z[i], color); - addOutlineVertex(x[i], y[i], z[i], GRAY); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } @@ -55,8 +55,8 @@ TriangleStrip::TriangleStrip(float centerX, float centerY, float centerZ, int nu isOutlined = false; attribMutex.unlock(); for (int i = 0; i < numVertices; i++) { - addVertex(x[i], y[i], z[i], color[i]); - addOutlineVertex(x[i], y[i], z[i], GRAY); + addVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, color[i]); + addOutlineVertex(x[i] - centerX, y[i] - centerY, z[i] - centerZ, GRAY); } } } diff --git a/src/examples/ArrayBubbleSort/Makefile b/src/examples/ArrayBubbleSort/Makefile index 981369086..b55827979 100644 --- a/src/examples/ArrayBubbleSort/Makefile +++ b/src/examples/ArrayBubbleSort/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ArrayShakerSort/Makefile b/src/examples/ArrayShakerSort/Makefile index 322017fa3..bfd829499 100644 --- a/src/examples/ArrayShakerSort/Makefile +++ b/src/examples/ArrayShakerSort/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Ballroom/Makefile b/src/examples/Ballroom/Makefile index 981749b21..48e2208aa 100644 --- a/src/examples/Ballroom/Makefile +++ b/src/examples/Ballroom/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Ballroom/testBallroom.cpp b/src/examples/Ballroom/testBallroom.cpp index faa9bbcc7..be01ef74a 100644 --- a/src/examples/Ballroom/testBallroom.cpp +++ b/src/examples/Ballroom/testBallroom.cpp @@ -228,7 +228,7 @@ class BallRoom { balls.push_back(b); } void step(Canvas* c) { - int mx = c->getMouseX() - c->getWindowWidth()/2, my = c->getWindowHeight()/2 - c->getMouseY(); + int mx = c->getMouseX(), my = c->getMouseY(); Vector2 mvec(mx,my); mouseCircle->setCenter(mx, my, 0); if (attract) { diff --git a/src/examples/Clock/Makefile b/src/examples/Clock/Makefile index 729ea5090..0154cdb23 100644 --- a/src/examples/Clock/Makefile +++ b/src/examples/Clock/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Conway/Makefile b/src/examples/Conway/Makefile index beadf029b..bf7830f2b 100644 --- a/src/examples/Conway/Makefile +++ b/src/examples/Conway/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/CubeRun/Makefile b/src/examples/CubeRun/Makefile index 31dcc4ea6..c1b4ed2e6 100644 --- a/src/examples/CubeRun/Makefile +++ b/src/examples/CubeRun/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/DiningPhilosophers/Makefile b/src/examples/DiningPhilosophers/Makefile index 594982eb2..5d579105e 100644 --- a/src/examples/DiningPhilosophers/Makefile +++ b/src/examples/DiningPhilosophers/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/DiningPhilosophers3D/Makefile b/src/examples/DiningPhilosophers3D/Makefile index af6d2a1c3..32ae17ad9 100644 --- a/src/examples/DiningPhilosophers3D/Makefile +++ b/src/examples/DiningPhilosophers3D/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Fireworks/Makefile b/src/examples/Fireworks/Makefile index 8f8a3918f..6ffed5e5a 100644 --- a/src/examples/Fireworks/Makefile +++ b/src/examples/Fireworks/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ForestFire/Makefile b/src/examples/ForestFire/Makefile index 1d7b13c41..434d5c80f 100644 --- a/src/examples/ForestFire/Makefile +++ b/src/examples/ForestFire/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Langton/Makefile b/src/examples/Langton/Makefile index c0bfe9b4d..345e94a77 100644 --- a/src/examples/Langton/Makefile +++ b/src/examples/Langton/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Mandelbrot/Makefile b/src/examples/Mandelbrot/Makefile index f002ec241..04c175425 100644 --- a/src/examples/Mandelbrot/Makefile +++ b/src/examples/Mandelbrot/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/MergeSort/Makefile b/src/examples/MergeSort/Makefile index f9a3a1cbe..92f49411d 100644 --- a/src/examples/MergeSort/Makefile +++ b/src/examples/MergeSort/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/NewtonPendulum/Makefile b/src/examples/NewtonPendulum/Makefile index ed460d696..0536866f2 100644 --- a/src/examples/NewtonPendulum/Makefile +++ b/src/examples/NewtonPendulum/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Pandemic/Makefile b/src/examples/Pandemic/Makefile index ad3608c88..d54fe0591 100644 --- a/src/examples/Pandemic/Makefile +++ b/src/examples/Pandemic/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ParallelPandemic/Makefile b/src/examples/ParallelPandemic/Makefile index 435ae7cfc..4fa801d0f 100644 --- a/src/examples/ParallelPandemic/Makefile +++ b/src/examples/ParallelPandemic/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Pong/Makefile b/src/examples/Pong/Makefile index 2c1527bbc..6ad0cf884 100644 --- a/src/examples/Pong/Makefile +++ b/src/examples/Pong/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ProducerConsumer/Makefile b/src/examples/ProducerConsumer/Makefile index ad5ca9b52..3ff99fa2e 100644 --- a/src/examples/ProducerConsumer/Makefile +++ b/src/examples/ProducerConsumer/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ReaderWriter/Makefile b/src/examples/ReaderWriter/Makefile index 559685352..862c62354 100644 --- a/src/examples/ReaderWriter/Makefile +++ b/src/examples/ReaderWriter/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/SeaUrchin/Makefile b/src/examples/SeaUrchin/Makefile index ace4eed7e..1be09619d 100644 --- a/src/examples/SeaUrchin/Makefile +++ b/src/examples/SeaUrchin/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ShakerSort/Makefile b/src/examples/ShakerSort/Makefile index 74dfe4299..917d5725c 100644 --- a/src/examples/ShakerSort/Makefile +++ b/src/examples/ShakerSort/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/SolarSystem/Makefile b/src/examples/SolarSystem/Makefile index a98ede8c6..f4c17809f 100644 --- a/src/examples/SolarSystem/Makefile +++ b/src/examples/SolarSystem/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ThreadedArrayAddition/Makefile b/src/examples/ThreadedArrayAddition/Makefile index 5aeded5f7..b59faab55 100644 --- a/src/examples/ThreadedArrayAddition/Makefile +++ b/src/examples/ThreadedArrayAddition/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ThreadedArrayBubbleSort/Makefile b/src/examples/ThreadedArrayBubbleSort/Makefile index 8576b9828..132b5768c 100644 --- a/src/examples/ThreadedArrayBubbleSort/Makefile +++ b/src/examples/ThreadedArrayBubbleSort/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ThreadedArrayOperations/Makefile b/src/examples/ThreadedArrayOperations/Makefile index 9b69bacb3..b6c42c27d 100644 --- a/src/examples/ThreadedArrayOperations/Makefile +++ b/src/examples/ThreadedArrayOperations/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/ThreadedSolarSystem/Makefile b/src/examples/ThreadedSolarSystem/Makefile index b9fd3ea18..3749ae27d 100644 --- a/src/examples/ThreadedSolarSystem/Makefile +++ b/src/examples/ThreadedSolarSystem/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/examples/Voronoi/Makefile b/src/examples/Voronoi/Makefile index 50361c397..889b6a711 100644 --- a/src/examples/Voronoi/Makefile +++ b/src/examples/Voronoi/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/Makefile b/src/tests/Makefile index 183246145..53b007e86 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -3,8 +3,7 @@ # ***************************************************** # SUBDIRS_TO_BUILD := $(wildcard test*/.) # Used to build the tests -SUBDIRS_TO_BUILD := test_specs \ - test2Dvs3D \ +SUBDIRS_TO_BUILD := test2Dvs3D \ test3DRotation \ testAlphaRectangle \ testArrows \ @@ -34,6 +33,7 @@ SUBDIRS_TO_BUILD := test_specs \ testTransparency \ testTriangle \ testTriangleStrip \ +# test_specs \ # testAura \ # testBlurImage \ # testCalcPi \ diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile index 2e37f36e4..b47e6705b 100644 --- a/src/tests/test2Dvs3D/Makefile +++ b/src/tests/test2Dvs3D/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp index 2c47d5f79..80a95cf55 100644 --- a/src/tests/test2Dvs3D/test2Dvs3D.cpp +++ b/src/tests/test2Dvs3D/test2Dvs3D.cpp @@ -78,7 +78,7 @@ void contrastFunction(Canvas& can) { stepsTaken++; } } - } + } delete testPyramid; delete triangle1; diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile index 03345c4c7..4867e5663 100644 --- a/src/tests/test3DRotation/Makefile +++ b/src/tests/test3DRotation/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile index 072c3514f..8cc9732c4 100644 --- a/src/tests/testAlphaRectangle/Makefile +++ b/src/tests/testAlphaRectangle/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile index 7411d70f1..f5ce82086 100644 --- a/src/tests/testArrows/Makefile +++ b/src/tests/testArrows/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile index f1487e646..ac0b04617 100644 --- a/src/tests/testAura/Makefile +++ b/src/tests/testAura/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile index 9389a941a..44d45535e 100644 --- a/src/tests/testBackground/Makefile +++ b/src/tests/testBackground/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile index a41f766fc..cd397fbc2 100644 --- a/src/tests/testBlurImage/Makefile +++ b/src/tests/testBlurImage/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile index 4d79e6724..3143da482 100644 --- a/src/tests/testCalcPi/Makefile +++ b/src/tests/testCalcPi/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile index dbd7c9653..b6db6f7c1 100644 --- a/src/tests/testCircle/Makefile +++ b/src/tests/testCircle/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile index 5fbc43185..5597878ec 100644 --- a/src/tests/testColorWheel/Makefile +++ b/src/tests/testColorWheel/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile index b6163fc7e..1a96d509d 100644 --- a/src/tests/testConcavePolygon/Makefile +++ b/src/tests/testConcavePolygon/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile index 38b60a4c2..1397f98ec 100644 --- a/src/tests/testCone/Makefile +++ b/src/tests/testCone/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testConstructors/Makefile b/src/tests/testConstructors/Makefile index c01fe882d..0e5dd9004 100644 --- a/src/tests/testConstructors/Makefile +++ b/src/tests/testConstructors/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile index 642cd99a6..6537beaf5 100644 --- a/src/tests/testConvexPolygon/Makefile +++ b/src/tests/testConvexPolygon/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile index 7190a88d7..9168d0c81 100644 --- a/src/tests/testCosineIntegral/Makefile +++ b/src/tests/testCosineIntegral/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile index 9373a2ea4..a6cee0436 100644 --- a/src/tests/testCube/Makefile +++ b/src/tests/testCube/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile index 4a5120ec3..39d6305bc 100644 --- a/src/tests/testCuboid/Makefile +++ b/src/tests/testCuboid/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile index aff15ef0d..c4aaa8cbd 100644 --- a/src/tests/testCylinder/Makefile +++ b/src/tests/testCylinder/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile index eef80cbac..fecc9dee9 100644 --- a/src/tests/testDice/Makefile +++ b/src/tests/testDice/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile index 1b880fb14..b16c3dcb3 100644 --- a/src/tests/testDiorama/Makefile +++ b/src/tests/testDiorama/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile index 1e88f9d23..616f25dcf 100644 --- a/src/tests/testEllipse/Makefile +++ b/src/tests/testEllipse/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile index 2b2ce5104..4a17d0ec8 100644 --- a/src/tests/testEllipsoid/Makefile +++ b/src/tests/testEllipsoid/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile index 94991da39..a793694b0 100644 --- a/src/tests/testFunction/Makefile +++ b/src/tests/testFunction/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile index 072c3514f..8cc9732c4 100644 --- a/src/tests/testGetPixels/Makefile +++ b/src/tests/testGetPixels/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile index cdc77e86f..a938cb996 100644 --- a/src/tests/testGradientWheel/Makefile +++ b/src/tests/testGradientWheel/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile index 72b5e97cf..d2c98911f 100644 --- a/src/tests/testGraydient/Makefile +++ b/src/tests/testGraydient/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile index 6ef2c993b..f8006bd00 100644 --- a/src/tests/testGreyscale/Makefile +++ b/src/tests/testGreyscale/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile index cc93c6633..7a7234a61 100644 --- a/src/tests/testHighData/Makefile +++ b/src/tests/testHighData/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile index 9a4b4e9de..e6be7a235 100644 --- a/src/tests/testImage/Makefile +++ b/src/tests/testImage/Makefile @@ -28,18 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** # Targets needed to bring the executable up to date diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile index eddf3e4c3..b25be2ee2 100644 --- a/src/tests/testImageCart/Makefile +++ b/src/tests/testImageCart/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile index 27d4cd03e..025b99295 100644 --- a/src/tests/testInverter/Makefile +++ b/src/tests/testInverter/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile index 48304e949..57e438eef 100644 --- a/src/tests/testLineChain/Makefile +++ b/src/tests/testLineChain/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile index 8f2cb68e6..bd5bb0e0d 100644 --- a/src/tests/testLineFan/Makefile +++ b/src/tests/testLineFan/Makefile @@ -28,18 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ - +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** # Targets needed to bring the executable up to date diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile index 035a50499..62c9bd644 100644 --- a/src/tests/testLines/Makefile +++ b/src/tests/testLines/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile index 404a455c4..610825c18 100644 --- a/src/tests/testMouse/Makefile +++ b/src/tests/testMouse/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile index d89316619..4504d8feb 100644 --- a/src/tests/testPixels/Makefile +++ b/src/tests/testPixels/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile index 7da1a87b9..9635d2909 100644 --- a/src/tests/testPrism/Makefile +++ b/src/tests/testPrism/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile index 0373a8e25..5046e7a51 100644 --- a/src/tests/testProcedural/Makefile +++ b/src/tests/testProcedural/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile index 8f0f83322..b6a8a30a0 100644 --- a/src/tests/testProgressBar/Makefile +++ b/src/tests/testProgressBar/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile index 68e0bf69a..4fc0cf1a1 100644 --- a/src/tests/testProjectiles/Makefile +++ b/src/tests/testProjectiles/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile index c4721dd36..30b527bd8 100644 --- a/src/tests/testPyramid/Makefile +++ b/src/tests/testPyramid/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile index 5e0cf7fe5..84df3c14c 100644 --- a/src/tests/testRectangle/Makefile +++ b/src/tests/testRectangle/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile index 9383cba89..5c4d9e646 100644 --- a/src/tests/testRegularPolygon/Makefile +++ b/src/tests/testRegularPolygon/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile index bfc7c5018..7233aca90 100644 --- a/src/tests/testScreenshot/Makefile +++ b/src/tests/testScreenshot/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile index dfaa0fba6..d400ed195 100644 --- a/src/tests/testSpectrogram/Makefile +++ b/src/tests/testSpectrogram/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile index 760443e7b..e38142bf9 100644 --- a/src/tests/testSpectrum/Makefile +++ b/src/tests/testSpectrum/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile index d7a7189d6..9aca41ab1 100644 --- a/src/tests/testSphere/Makefile +++ b/src/tests/testSphere/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile index 339f7d968..611a990b6 100644 --- a/src/tests/testSquare/Makefile +++ b/src/tests/testSquare/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile index 90f33c627..91533096d 100644 --- a/src/tests/testStar/Makefile +++ b/src/tests/testStar/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile index 41fa2cd44..090716448 100644 --- a/src/tests/testText/Makefile +++ b/src/tests/testText/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile index 5963dd8bb..f7764c963 100644 --- a/src/tests/testTextCart/Makefile +++ b/src/tests/testTextCart/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile index a230e8978..d67a6ad46 100644 --- a/src/tests/testTextTwo/Makefile +++ b/src/tests/testTextTwo/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile index 44792324d..3fc4549c1 100644 --- a/src/tests/testTransparency/Makefile +++ b/src/tests/testTransparency/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile index 53cee6da5..eb6f1377b 100644 --- a/src/tests/testTriangle/Makefile +++ b/src/tests/testTriangle/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile index e5f78015b..45490579b 100644 --- a/src/tests/testTriangleStrip/Makefile +++ b/src/tests/testTriangleStrip/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile index c0ec4da0b..dfbd88cc5 100644 --- a/src/tests/testUnits/Makefile +++ b/src/tests/testUnits/Makefile @@ -28,17 +28,32 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif + CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile index d5cb2797a..ccec4f1bf 100644 --- a/src/tests/test_specs/Makefile +++ b/src/tests/test_specs/Makefile @@ -27,18 +27,33 @@ dummy_build_folder := $(shell mkdir -p $(ODIR)) # Flags NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable + +ifeq ($(UNAME), Linux) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), CYGWIN_NT-10.0) +GL_FLAGS = -lGLU -lglut -lGL +BREW := +endif +ifeq ($(UNAME), Darwin) +GL_FLAGS = -framework OpenGL -lglut +BREW := -lomp -I"$(brew --prefix libomp)/include" +endif CXXFLAGS = -Wall -g\ -I/usr/local/include/TSGL \ -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ $(NOWARN)\ -std=c++11\ -Wc++11-compat\ -I/usr/include \ -I/usr/include/freetype2 \ -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw -lGLU -lglut -lGL -fopenmp \ - -L/usr/local/lib \ +LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ + $(BREW) -L/usr/local/lib \ # **************************************************** diff --git a/src/tests/test_specs/test_specs.cpp b/src/tests/test_specs/test_specs.cpp index 367badcb1..c11fa8271 100644 --- a/src/tests/test_specs/test_specs.cpp +++ b/src/tests/test_specs/test_specs.cpp @@ -1,4 +1,6 @@ -#include "tsgl.h" +#include + +using namespace tsgl; int main(int argc, char* argv[]) { glfwInit(); diff --git a/uninstall-mac b/uninstall-mac index e540fbd49..288e682b9 100755 --- a/uninstall-mac +++ b/uninstall-mac @@ -7,8 +7,11 @@ make clean #Remove the bin and lib folders rm -rf bin lib +#Remove the copy of stb from /usr/local/include +sudo rm -rf /usr/local/include/stb + #Take out the TSGL header files -rm -rf /usr/local/include/TSGL +sudo rm -rf /usr/local/include/TSGL #Take out the TSGL lib files rm /usr/local/lib/libtsgl.* From 16895b04b4310420223919af65394d1bb03fead8 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 29 Jul 2020 15:37:29 -0400 Subject: [PATCH 081/105] Fixed SPIA tests added; more fixes/changes needed --- src/examples/Conway/LifeFarm.cpp | 11 +- src/examples/Conway/testConway.cpp | 11 +- .../DiningPhilosophers/testPhilosophers.cpp | 2 +- src/examples/Fireworks/Arc.cpp | 23 +- src/examples/Fireworks/Arc.h | 1 + src/examples/Fireworks/Dot.cpp | 5 +- src/examples/Fireworks/Dot.h | 1 + src/examples/Fireworks/Firework.cpp | 2 +- src/examples/Fireworks/testFireworks.cpp | 5 +- src/examples/ForestFire/testForestFire.cpp | 39 +-- src/examples/Langton/testLangton.cpp | 2 +- src/examples/Makefile | 6 +- src/examples/Mandelbrot/testMandelbrot.cpp | 10 +- src/examples/Pong/testPong.cpp | 3 +- .../ProducerConsumer/testProducerConsumer.cpp | 4 +- .../ReaderWriter/testReaderWriter.cpp | 14 +- src/examples/Voronoi/testVoronoi.cpp | 4 +- src/tests/Makefile | 21 +- src/tests/test2Dvs3D/test2Dvs3D.cpp | 2 +- src/tests/testArrows/testArrows.cpp | 2 +- src/tests/testAura/testAura.cpp | 11 +- src/tests/testBlurImage/testBlurImage.cpp | 50 +-- src/tests/testColorWheel/testColorWheel.cpp | 13 +- src/tests/testConstructors/Makefile | 78 ----- .../testConstructors/testConstructors.cpp | 304 ------------------ src/tests/testDice/testCylinder.cpp | 75 +++++ src/tests/testGetPixels/Makefile | 4 +- src/tests/testGetPixels/testGetPixels.cpp | 17 +- .../testGradientWheel/testGradientWheel.cpp | 17 +- src/tests/testGraydient/testGraydient.cpp | 9 +- src/tests/testGreyscale/testGreyscale.cpp | 27 +- src/tests/testHighData/testHighData.cpp | 13 +- src/tests/testInverter/ImageInverter.cpp | 19 +- src/tests/testInverter/testInverter.cpp | 4 +- src/tests/testPixels/testPixels.cpp | 8 +- 35 files changed, 264 insertions(+), 553 deletions(-) delete mode 100644 src/tests/testConstructors/Makefile delete mode 100644 src/tests/testConstructors/testConstructors.cpp create mode 100644 src/tests/testDice/testCylinder.cpp diff --git a/src/examples/Conway/LifeFarm.cpp b/src/examples/Conway/LifeFarm.cpp index bd6bb9ff5..1381f73d8 100644 --- a/src/examples/Conway/LifeFarm.cpp +++ b/src/examples/Conway/LifeFarm.cpp @@ -34,7 +34,7 @@ LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { for (int i = 9*h/10; i > h/10; --i) { bool newrow = true; for (int j = 9*w/10; j > w/10; --j) { - if ((rand() % 2) > 0) { + if ((saferand(1,100) % 2) > 0) { if (newrow) { *currentstate = (i + 1); ++currentstate; @@ -61,6 +61,7 @@ LifeFarm::LifeFarm(int w, int h, Canvas* c, bool randomize) { void LifeFarm::initGun() { int w = width/2, h = height/2; + // int w = 0, h = 0; currentstart = currentstate; *currentstate++ = h+1; *currentstate++ = -(w+25); @@ -212,6 +213,8 @@ void LifeFarm::moveAntsOld() { //Reset the end of the list for the next iteration listend = 0; + Background * bg = can->getBackground(); + //Redraw any cell whose living status has changed, and repopulate the living list bool lives, lived; for (int row = 0; row < height; ++row) { @@ -220,11 +223,11 @@ void LifeFarm::moveAntsOld() { lives = ( (neighbors[row][col] == 3) || ( lived && (neighbors[row][col] == 2) )); if (lives != lived) { if (lives) { - can->drawPoint(col, row, fcolor); + bg->drawPixel(col - width/2, height/2 - row, fcolor); addAnt(col,row); } else if (drawdead) - can->drawPoint(col, row, bgcolor); + bg->drawPixel(col - width/2, height/2 - row, bgcolor); alive[row][col] = lives; } else if (lives) addAnt(col,row); @@ -346,7 +349,7 @@ void LifeFarm::life(int *current, int *fresh) { /* what does this bitmap indicate? */ if(state[bitmap] && !(y > height-3 || y < 3) && !((-x) > width-3 || (-x) < 3)) { //If our bitmap is now alive *(++fresh) = x - 1; //Increment the cell pointer of our new board, and set the next value to the current x-coordinate minus 1 - can->drawPoint(-(x), y, fcolor); //Draw it + can->getBackground()->drawPixel(-(x), height / 2 - y, fcolor); //Draw it } else if(bitmap == 000) //If our bitmap is now empty... break; //No more consecutive living cells; move on to the next explicitly stored pointer diff --git a/src/examples/Conway/testConway.cpp b/src/examples/Conway/testConway.cpp index 5770c07f4..b434ba798 100644 --- a/src/examples/Conway/testConway.cpp +++ b/src/examples/Conway/testConway.cpp @@ -5,7 +5,7 @@ */ #include -#include "Conway/LifeFarm.h" +#include "LifeFarm.h" using namespace tsgl; @@ -41,6 +41,7 @@ using namespace tsgl; * \param can Reference to the Canvas to draw to. */ void conwayFunction(Canvas& can) { + Background * bg = can.getBackground(); const int IPF = 100, // Iterations per frame WW = can.getWindowWidth(), // Window width WH = can.getWindowHeight(); // Window height @@ -67,15 +68,15 @@ void conwayFunction(Canvas& can) { if(!paused) { for (int i = 0; i < IPF; i++) { if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + farm.addAnt(can.getMouseX() + WW/2, can.getMouseY() + WH/2); + bg->drawPixel(can.getMouseX(), can.getMouseY(), ColorInt(255,255,255,255)); } farm.moveAnts(); } } if(mouseDown) { - farm.addAnt(can.getMouseX(), can.getMouseY()); - can.drawPoint(can.getMouseX(), can.getMouseY(), WHITE); + farm.addAnt(can.getMouseX() + WW/2, can.getMouseY() + WH/2); + bg->drawPixel(can.getMouseX(), can.getMouseY(), ColorInt(255,255,255,255)); } } } diff --git a/src/examples/DiningPhilosophers/testPhilosophers.cpp b/src/examples/DiningPhilosophers/testPhilosophers.cpp index eb2ac2076..8fe4b4160 100644 --- a/src/examples/DiningPhilosophers/testPhilosophers.cpp +++ b/src/examples/DiningPhilosophers/testPhilosophers.cpp @@ -96,7 +96,7 @@ void philosopherFunction(Canvas& can,int philosophers, std::string RM, bool step int main(int argc, char* argv[]) { if( argc == 1) { std::cout << "\nTo run the program with different values, use the format:\n\t./DiningPhilosophers " - << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in Table.h" << std::endl; + << "\nwhere is a character specifying conflict resolution of the philosophers. Find options in DiningPhilosophers/main.cpp" << std::endl; } int nphil = (argc > 1) ? atoi(argv[1]) : 5; //Number of philosophers defaults to 5 int speed = (argc > 2 && atoi(argv[2]) > 0) ? atoi(argv[2]) : 10; //Speed defaults to 5 diff --git a/src/examples/Fireworks/Arc.cpp b/src/examples/Fireworks/Arc.cpp index 0c154288a..e96a9c623 100644 --- a/src/examples/Fireworks/Arc.cpp +++ b/src/examples/Fireworks/Arc.cpp @@ -15,10 +15,11 @@ Arc::Arc(Canvas& can) { f = NULL; myLife = 0; myCan = &can; - myX = rand() % myCan->getWindowWidth(); - myY = rand() % myCan->getWindowHeight(); - myAngle = ((rand() % 32000) / 32000.0f) * 2.0f*PI; - myRad = 20 + rand() % 180; + myBackground = myCan->getBackground(); + myX = saferand(-myCan->getWindowWidth()/2,myCan->getWindowWidth()/2); + myY = saferand(-myCan->getWindowHeight()/2,myCan->getWindowHeight()/2); + myAngle = (randfloat(32000)) * 2.0f*PI; + myRad = 20 + saferand(0,179); computeStepSize(); myColor = ColorHSV(0.0f,1.0f,1.0f,1.0f); } @@ -44,7 +45,7 @@ Arc::Arc(Canvas* can, int x, int y, int rad, float angle) { * \details Returns if myX and myY are between 0 and the Canvas' width and height respectively. */ bool Arc::outOfBounds() { - return (myX < 0 || myY < 0 || myX > myCan->getWindowWidth() || myY > myCan->getWindowHeight()); + return (myX < -myCan->getWindowWidth()/2 || myY < -myCan->getWindowHeight()/2 || myX > myCan->getWindowWidth()/2 || myY > myCan->getWindowHeight()/2); } /*! @@ -52,7 +53,7 @@ bool Arc::outOfBounds() { */ bool Arc::onBlackPixel() { const int LET = 14; - ColorInt col = myCan->getPoint(myX,myY); + ColorInt col = myCan->getBackground()->getPixel(myX,myY); return !(col.RgetWindowWidth(); - myY = rand() % myCan->getWindowHeight(); + myX = saferand(-myCan->getWindowWidth()/2,myCan->getWindowWidth()/2); + myY = saferand(-myCan->getWindowHeight()/2,myCan->getWindowHeight()/2); } computeStepSize(); } @@ -87,7 +88,7 @@ void Arc::relocate() { void Arc::step() { if (f != NULL) f->step(); - if (rand() % 100 < 2) { + if (saferand(0,99) < 2) { ++myRad; myStepSize = 1.0f/(myRad); } @@ -100,7 +101,7 @@ void Arc::step() { f = new Firework(*myCan,myX,myY); relocate(); } - myCan->drawPoint(myX,myY,myColor); + myBackground->drawPixel(myX,myY,myColor); } Arc::~Arc() { diff --git a/src/examples/Fireworks/Arc.h b/src/examples/Fireworks/Arc.h index a7cd14718..474ea7a65 100644 --- a/src/examples/Fireworks/Arc.h +++ b/src/examples/Fireworks/Arc.h @@ -13,6 +13,7 @@ using namespace tsgl; class Arc { private: Canvas* myCan; + Background * myBackground; int myLife; float myX, myY, myRad; float myAngle, myStepSize; diff --git a/src/examples/Fireworks/Dot.cpp b/src/examples/Fireworks/Dot.cpp index ccd6c5b37..2ac7e3cfa 100644 --- a/src/examples/Fireworks/Dot.cpp +++ b/src/examples/Fireworks/Dot.cpp @@ -16,6 +16,7 @@ */ Dot::Dot(Canvas& can, float x, float y, float s, float d, float f) { myCan = &can; + myBackground = myCan->getBackground(); dead = false; myX = x; myY = y; mySpeed = s; myDir = d; myFric = f; @@ -29,8 +30,8 @@ void Dot::step() { myX += mySpeed*cos(myDir); myY += mySpeed*sin(myDir); mySpeed *= myFric; - if (!dead) - myCan->drawPoint(myX,myY,WHITE); + if (!dead && abs(myX) < myCan->getWindowWidth() / 2 && abs(myY) < myCan->getWindowHeight() / 2) + myBackground->drawPixel(myX,myY,ColorInt(255,255,255,255)); if (mySpeed < 0.5f) dead = true; } diff --git a/src/examples/Fireworks/Dot.h b/src/examples/Fireworks/Dot.h index 12052a7bf..94166d68e 100644 --- a/src/examples/Fireworks/Dot.h +++ b/src/examples/Fireworks/Dot.h @@ -13,6 +13,7 @@ class Dot { private: bool dead; Canvas* myCan; + Background * myBackground; float myX, myY, mySpeed, myDir, myFric; public: Dot(Canvas& can, float x, float y, float s, float d, float f); diff --git a/src/examples/Fireworks/Firework.cpp b/src/examples/Fireworks/Firework.cpp index d222832a2..9ab5d9ed7 100644 --- a/src/examples/Fireworks/Firework.cpp +++ b/src/examples/Fireworks/Firework.cpp @@ -17,7 +17,7 @@ Firework::Firework(Canvas& can, int x, int y) { myX = x; myY = y; for (int i = 0; i < 10; ++i) { - myDots[i] = new Dot(can, myX,myY,(rand() % 10000)/10000.0f,(rand() % 10000)/10000.0f * 2 * PI, 0.99f); + myDots[i] = new Dot(can, myX,myY,randfloat(),randfloat() * 2 * PI, 0.99f); } } diff --git a/src/examples/Fireworks/testFireworks.cpp b/src/examples/Fireworks/testFireworks.cpp index 11711fb4e..e3499cb3a 100644 --- a/src/examples/Fireworks/testFireworks.cpp +++ b/src/examples/Fireworks/testFireworks.cpp @@ -5,7 +5,7 @@ */ #include -#include "Fireworks/Arc.h" +#include "Arc.h" using namespace tsgl; @@ -18,6 +18,7 @@ using namespace tsgl; * \param speed How fast the fireworks move. */ void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { + Background * bg = can.getBackground(); Arc** arcs = new Arc*[numFireworks]; for (int i = 0; i < numFireworks; i++) { arcs[i] = new Arc(can); @@ -35,7 +36,7 @@ void fireworkFunction(Canvas& can, int threads, int numFireworks, int speed) { for (int i = tid; i < numFireworks; i += nthreads) arcs[i]->step(); if (tid == 0) - can.drawRectangle(0,0,CWW,CWH,col); + bg->drawRectangle(0,0,0,CWW,CWH,0,0,0,col); #pragma omp barrier } } diff --git a/src/examples/ForestFire/testForestFire.cpp b/src/examples/ForestFire/testForestFire.cpp index 60a43ae24..4b2665bb8 100644 --- a/src/examples/ForestFire/testForestFire.cpp +++ b/src/examples/ForestFire/testForestFire.cpp @@ -8,10 +8,6 @@ using namespace tsgl; -float randfloat(int divisor = 10000) { - return (rand() % divisor) / (float) divisor; -} - /*! * \brief Pseudo-simulates a forest fire using a lot of probability and randomness. * \details @@ -41,12 +37,13 @@ float randfloat(int divisor = 10000) { * \param can Reference to the Canvas being drawn to. */ void forestFireFunction(Canvas& can) { + Background * bg = can.getBackground(); const int WINDOW_W = can.getWindowWidth(), // Set the screen sizes WINDOW_H = can.getWindowHeight(); const float LIFE = 10, STRENGTH = 0.03, MAXDIST = sqrt(WINDOW_W * WINDOW_W + WINDOW_H * WINDOW_H) / 2; - srand(time(NULL)); // Seed the random number generator + // srand(time(NULL)); // Seed the random number generator bool* onFire = new bool[WINDOW_W * WINDOW_H](); float* flammability = new float[WINDOW_W * WINDOW_H](); //Setting each pixel's flammablity @@ -57,21 +54,22 @@ void forestFireFunction(Canvas& can) { float tdist = (MAXDIST - sqrt(xi * xi + yi * yi)) / MAXDIST; float f = 0.01 + (i * j % 100) / 100.0 * randfloat(100) / 2 * tdist; flammability[i * WINDOW_H + j] = f; - can.drawPoint(i, j, ColorFloat(0.0f, f, 0.0f, 1.0f)); + bg->drawPixel(i - WINDOW_W/2, WINDOW_H/2 - j, ColorFloat(0.0f, f, 0.0f, 1.0f)); } } + can.sleep(); // sleep in order to get all the pixels rendered before lakes //"Lakes" for (int reps = 0; reps < 32; reps++) { - int x = rand() % WINDOW_W; - int y = rand() % WINDOW_H; - int w = rand() % (WINDOW_W - x); - int h = rand() % (WINDOW_H - y); + int x = saferand(-WINDOW_W/2, WINDOW_W/2); + int y = saferand(-WINDOW_H/2, WINDOW_H/2); + int w = saferand(0, WINDOW_W/2 - abs(x)) * 2; + int h = saferand(0, WINDOW_H/2 - abs(y)) * 2; if (w > 32) w = 32; if (h > 32) h = 32; - for (int i = 0; i < w; i++) { - for (int j = 0; j < h; j++) { - flammability[(x + i) * WINDOW_H + (y + j)] = 0.01; - can.drawPoint(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); + for (int i = -w/2; i < w/2; i++) { + for (int j = -h/2; j < h/2; j++) { + flammability[(x + i + WINDOW_W/2) * WINDOW_H + (y + j + WINDOW_H/2)] = 0.01; + bg->drawPixel(x + i, y + j, ColorFloat(0.0f, 0.0f, 1.0f, 0.25f)); } } } @@ -86,11 +84,9 @@ void forestFireFunction(Canvas& can) { for (int j = 0; j < 2; j++) { firePoint fire = { WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, LIFE, STRENGTH }; fires.push(fire); - can.drawPoint(WINDOW_W / 2 - 1 + i, WINDOW_H / 2 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); + bg->drawPixel(0 - 1 + i, 0 - 1 + j, ColorFloat(1.0f, 0.0f, 0.0f, STRENGTH)); } } - Rectangle *rec = new Rectangle(10,10,10,10,BLUE); - can.add(rec); while (can.isOpen()) { can.sleep(); int l = fires.size(); @@ -103,30 +99,29 @@ void forestFireFunction(Canvas& can) { firePoint fire = { f.x - 1, f.y, LIFE, f.strength }; fires.push(fire); onFire[myCell - WINDOW_H] = true; - can.drawPoint(f.x - 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2 - 1, f.y - WINDOW_H/2, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.x < WINDOW_W - 1 && !onFire[myCell + WINDOW_H] && randfloat() < flammability[myCell + WINDOW_H]) { firePoint fire = { f.x + 1, f.y, LIFE, f.strength }; fires.push(fire); onFire[myCell + WINDOW_H] = true; - can.drawPoint(f.x + 1, f.y, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2 + 1, f.y - WINDOW_H/2, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.y > 0 && !onFire[myCell - 1] && randfloat() < flammability[myCell - 1]) { firePoint fire = { f.x, f.y - 1, LIFE, f.strength }; fires.push(fire); onFire[myCell - 1] = true; - can.drawPoint(f.x, f.y - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2, f.y - WINDOW_H/2 - 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } if (f.y < WINDOW_H && !onFire[myCell + 1] && randfloat() < flammability[myCell + 1]) { firePoint fire = { f.x, f.y + 1, LIFE, f.strength }; fires.push(fire); onFire[myCell + 1] = true; - can.drawPoint(f.x, f.y + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); + bg->drawPixel(f.x - WINDOW_W/2, f.y - WINDOW_H/2 + 1, ColorFloat(f.life / LIFE, 0.0f, 0.0f, f.life / LIFE)); } } } - delete rec; delete[] onFire; delete[] flammability; } diff --git a/src/examples/Langton/testLangton.cpp b/src/examples/Langton/testLangton.cpp index 60c0c1324..d9d6acd57 100644 --- a/src/examples/Langton/testLangton.cpp +++ b/src/examples/Langton/testLangton.cpp @@ -7,7 +7,7 @@ #include #include -#include "Langton/AntFarm.h" +#include "AntFarm.h" using namespace tsgl; diff --git a/src/examples/Makefile b/src/examples/Makefile index 8378a6f6d..527df333e 100644 --- a/src/examples/Makefile +++ b/src/examples/Makefile @@ -7,9 +7,12 @@ SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ ArrayShakerSort/. \ Ballroom/. \ Clock/. \ + Conway/. \ CubeRun/. \ DiningPhilosophers/. \ DiningPhilosophers3D/. \ + Fireworks/. \ + ForestFire/. \ MergeSort/. \ NewtonPendulum/. \ Pong/. \ @@ -20,9 +23,6 @@ SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ ThreadedArrayBubbleSort/. \ ThreadedArrayOperations/. \ ThreadedSolarSystem/. \ -# Conway/. \ -# Fireworks/. \ -# ForestFire/. \ # Langton/. \ # Mandelbrot/. \ # ParallelPandemic/. \ diff --git a/src/examples/Mandelbrot/testMandelbrot.cpp b/src/examples/Mandelbrot/testMandelbrot.cpp index f36ac871c..c731fa95f 100644 --- a/src/examples/Mandelbrot/testMandelbrot.cpp +++ b/src/examples/Mandelbrot/testMandelbrot.cpp @@ -6,11 +6,11 @@ /*testMandelbrot.cpp contains multiple functions that display a Mandelbrot set in similar fashions (and one that displays a Julia set). */ -#include "Mandelbrot/Buddhabrot.h" -#include "Mandelbrot/Mandelbrot.h" -#include "Mandelbrot/GradientMandelbrot.h" -#include "Mandelbrot/Julia.h" -#include "Mandelbrot/Nova.h" +#include "Buddhabrot.h" +#include "Mandelbrot.h" +#include "GradientMandelbrot.h" +#include "Julia.h" +#include "Nova.h" using namespace tsgl; diff --git a/src/examples/Pong/testPong.cpp b/src/examples/Pong/testPong.cpp index eb12267da..db2efd80d 100644 --- a/src/examples/Pong/testPong.cpp +++ b/src/examples/Pong/testPong.cpp @@ -67,7 +67,6 @@ int main(int argc, char * argv[]) { ballSpeed = BALL_DEFAULT_SPEED; paddleSpeed = PADDLE_DEFAULT_SPEED; } - Canvas c(-1,-1,w,h,"Tennis for Two"); - c.setBackgroundColor(BLACK); + Canvas c(-1,-1,w,h,"Tennis for Two", BLACK); c.run(pongFunction,ballSpeed, paddleSpeed); } diff --git a/src/examples/ProducerConsumer/testProducerConsumer.cpp b/src/examples/ProducerConsumer/testProducerConsumer.cpp index a3e1d1f29..446b1f65f 100644 --- a/src/examples/ProducerConsumer/testProducerConsumer.cpp +++ b/src/examples/ProducerConsumer/testProducerConsumer.cpp @@ -10,8 +10,8 @@ #include #include #include //for try-catch debugging -#include "ProducerConsumer/Producer.h" -#include "ProducerConsumer/Consumer.h" +#include "Producer.h" +#include "Consumer.h" using namespace tsgl; diff --git a/src/examples/ReaderWriter/testReaderWriter.cpp b/src/examples/ReaderWriter/testReaderWriter.cpp index 36a66082f..aacfbfedc 100644 --- a/src/examples/ReaderWriter/testReaderWriter.cpp +++ b/src/examples/ReaderWriter/testReaderWriter.cpp @@ -9,13 +9,13 @@ //#include #include #include -#include "ReaderWriter/Reader.h" -#include "ReaderWriter/Writer.h" -#include "ReaderWriter/RWDatabase.h" -#include "ReaderWriter/Lock.h" -#include "ReaderWriter/RLock.h" -#include "ReaderWriter/WLock.h" -#include "ReaderWriter/FLock.h" +#include "Reader.h" +#include "Writer.h" +#include "RWDatabase.h" +#include "Lock.h" +#include "RLock.h" +#include "WLock.h" +#include "FLock.h" using namespace tsgl; //Constants diff --git a/src/examples/Voronoi/testVoronoi.cpp b/src/examples/Voronoi/testVoronoi.cpp index d0a05d6e9..5015fa227 100644 --- a/src/examples/Voronoi/testVoronoi.cpp +++ b/src/examples/Voronoi/testVoronoi.cpp @@ -6,8 +6,8 @@ /* testVoronoi.cpp contains multiple functions that display a Voronoi diagram in similar fashions. */ -#include "Voronoi/Voronoi.h" -#include "Voronoi/ShadedVoronoi.h" +#include "Voronoi.h" +#include "ShadedVoronoi.h" using namespace tsgl; diff --git a/src/tests/Makefile b/src/tests/Makefile index 53b007e86..e46074f75 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -7,20 +7,28 @@ SUBDIRS_TO_BUILD := test2Dvs3D \ test3DRotation \ testAlphaRectangle \ testArrows \ + testAura \ testBackground \ testCircle \ + testColorWheel \ testConcavePolygon \ testCone \ testConvexPolygon \ testCube \ testCuboid \ testCylinder \ - testDice \ testDiorama \ testEllipse \ testEllipsoid \ + testGetPixels \ + testGradientWheel \ + testGraydient \ + testGreyscale \ + testHighData \ testImage \ + testInverter \ testLines \ + testPixels \ testPrism \ testProcedural \ testPyramid \ @@ -34,24 +42,15 @@ SUBDIRS_TO_BUILD := test2Dvs3D \ testTriangle \ testTriangleStrip \ # test_specs \ -# testAura \ # testBlurImage \ # testCalcPi \ -# testColorWheel \ -# testConstructors \ # testCosineIntegral \ +# testDice \ # testFunction \ -# testGetPixels \ -# testGradientWheel \ -# testGraydient \ -# testGreyscale \ -# testHighData \ # testImageCart \ -# testInverter \ # testLineChain \ # testLineFan \ # testMouse \ -# testPixels \ # testProgressBar \ # testProjectiles \ # testScreenshot \ diff --git a/src/tests/test2Dvs3D/test2Dvs3D.cpp b/src/tests/test2Dvs3D/test2Dvs3D.cpp index 80a95cf55..2c47d5f79 100644 --- a/src/tests/test2Dvs3D/test2Dvs3D.cpp +++ b/src/tests/test2Dvs3D/test2Dvs3D.cpp @@ -78,7 +78,7 @@ void contrastFunction(Canvas& can) { stepsTaken++; } } - } + } delete testPyramid; delete triangle1; diff --git a/src/tests/testArrows/testArrows.cpp b/src/tests/testArrows/testArrows.cpp index 61b13731c..d325b9b17 100644 --- a/src/tests/testArrows/testArrows.cpp +++ b/src/tests/testArrows/testArrows.cpp @@ -46,6 +46,6 @@ void arrowFunction(Canvas& c) { int main(int argc, char* argv[]) { int w = 1000; int h = 1000; - Canvas c(-1, -1, w, h, "Arrows"); + Canvas c(-1, -1, w, h, "Arrows", BLACK); c.run(arrowFunction); } \ No newline at end of file diff --git a/src/tests/testAura/testAura.cpp b/src/tests/testAura/testAura.cpp index 5620f36d7..77e9c5cfa 100644 --- a/src/tests/testAura/testAura.cpp +++ b/src/tests/testAura/testAura.cpp @@ -21,6 +21,7 @@ inline void scatter(float& f, float max) { * */ void auraFunction(Canvas& can, int segs) { + Background * bg = can.getBackground(); const float SR2 = sqrt(2); const int CW = can.getWindowWidth(), CH = can.getWindowHeight(); const int ccw = CW/2, cch = CH/2; @@ -58,11 +59,11 @@ void auraFunction(Canvas& can, int segs) { if (cf[i].H > 6.0f) cf[i].H = 0.0f; float sang = sin(ang), cang = cos(ang); if (fabs(cang) > fabs(sang)) { - x1[i] = (cang > 0) ? CW : 0; - y1[i] = cch+cch*sang*SR2; + x1[i] = (cang > 0) ? ccw : -ccw; + y1[i] = cch*sang*SR2; } else { - y1[i] = (sang > 0) ? CH : 0; - x1[i] = ccw+ccw*cang*SR2; + y1[i] = (sang > 0) ? cch : -cch; + x1[i] = ccw*cang*SR2; } ang += OFF; } @@ -88,7 +89,7 @@ void auraFunction(Canvas& can, int segs) { } } if (next >= 0) { - can.drawTriangle(mx,my,x1[next],y1[next],x2[next],y2[next],cf[next],true); + bg->drawTriangle(mx,my,0,x1[next],y1[next],0,x2[next],y2[next],0,0,0,0,cf[next],false); drawn[next] = true; } } diff --git a/src/tests/testBlurImage/testBlurImage.cpp b/src/tests/testBlurImage/testBlurImage.cpp index 005d6399d..34ec57b86 100644 --- a/src/tests/testBlurImage/testBlurImage.cpp +++ b/src/tests/testBlurImage/testBlurImage.cpp @@ -16,47 +16,51 @@ int depthtest(int xmin, int ymin, int xmax, int ymax) { return ((xd > yd) ? xd : yd); } -bool blur(Canvas& can, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { +bool blur(Background * bg, int xmin, int ymin, int xmax, int ymax, int&numdrawn, int depth) { if (xmin > xmax || ymin > ymax) return false; if (depth > 0) { int xmid = (xmin+xmax)/2, ymid = (ymin+ymax)/2; - blur(can,xmin, ymin, xmid,ymid,numdrawn, depth-1); - blur(can,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); - blur(can,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); - blur(can,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); + blur(bg,xmin, ymin, xmid,ymid,numdrawn, depth-1); + blur(bg,xmid+1,ymin, xmax,ymid,numdrawn, depth-1); + blur(bg,xmin, ymid+1,xmid,ymax,numdrawn, depth-1); + blur(bg,xmid+1,ymid+1,xmax,ymax,numdrawn, depth-1); return false; } - ColorFloat top = Colors::blend(can.getPoint(xmin,ymin),can.getPoint(xmax,ymin)); - ColorFloat bot = Colors::blend(can.getPoint(xmin,ymax),can.getPoint(xmax,ymax)); + ColorFloat top = Colors::blend(bg->getPixel(xmin,ymin),bg->getPixel(xmax,ymin)); + ColorFloat bot = Colors::blend(bg->getPixel(xmin,ymax),bg->getPixel(xmax,ymax)); for (int j = ymin; j <= ymax; ++j) for (int i = xmin; i <= xmax; ++i) - can.drawPoint(i,j,Colors::blend(top,bot)); + bg->drawPixel(i,j,Colors::blend(top,bot)); return true; } void blurImageFunction(Canvas& can, std::string fpath, int threads) { + Background * bg = can.getBackground(); int cww = can.getWindowWidth(), cwh = can.getWindowHeight(); - int side = sqrt(threads); //Square root of the number of threads, rounded down - can.drawImage(fpath, 0, 0, cww, cwh); - can.sleepFor(0.5f); - #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square - { - side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads - int tid = omp_get_thread_num(); - int ndrawn = 0, xblock = cww/side, yblock = cwh/side; - int xmin = (tid%side)*xblock, ymin = (tid/side)*yblock; - int xmax = xmin+xblock; clamp(xmax,0,cww-1); - int ymax = ymin+yblock; clamp(ymax,0,cwh-1); - int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); - for (bool d = false; !d && can.isOpen(); d = blur(can, xmin, ymin, xmax, ymax, ndrawn, depth--)); - } + bg->drawImage(0,0,0,fpath,cww,cwh,0,0,0,1.0); + // int side = sqrt(threads); //Square root of the number of threads, rounded down + // can.sleepFor(0.5f); + // #pragma omp parallel num_threads (side*side) //Make sure the actual number of threads is a square + // { + // side=sqrt(omp_get_num_threads()); //Verify we actually have a workable number of threads + // int tid = omp_get_thread_num(); + // int ndrawn = 0, xblock = cww/side, yblock = cwh/side; + // int xmin = (tid%side)*xblock - cww/2, ymin = (tid/side)*yblock - cwh/2; + // int xmax = xmin+xblock; clamp(xmax,0,cww-1); + // int ymax = ymin+yblock; clamp(ymax,0,cwh-1); + // int depth = depthtest(xmin, ymin, xmin+xblock, ymin+yblock); + // for (bool d = false; !d && can.isOpen(); d = blur(bg, xmin, ymin, xmax, ymax, ndrawn, depth--)); + // } } int main(int argc, char* argv[]) { int w, h, t = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - std::string fname = (argc > 2) ? argv[2] : "../assets/pics/colorful_cars.jpg"; + std::string fname = (argc > 2) ? argv[2] : "./assets/pics/HDR_landscape.jpg"; TextureHandler::getDimensions(fname,w,h); + w*=0.6; + h*=0.6; + printf("%d, %d\n", w, h); Canvas c(-1, -1, w, h, "Blurring using recursive splitting"); c.run(blurImageFunction,fname,t); } diff --git a/src/tests/testColorWheel/testColorWheel.cpp b/src/tests/testColorWheel/testColorWheel.cpp index 3a7404d33..2ec404255 100644 --- a/src/tests/testColorWheel/testColorWheel.cpp +++ b/src/tests/testColorWheel/testColorWheel.cpp @@ -39,6 +39,7 @@ using namespace tsgl; * \param threads Number of threads to use. */ void colorWheelFunction(Canvas& can, int threads) { + Background * bg = can.getBackground(); const int CW = can.getWindowWidth() / 2, // Half the window's width CH = can.getWindowHeight() / 2; // Half the window's height const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel @@ -52,12 +53,12 @@ void colorWheelFunction(Canvas& can, int threads) { while (can.isOpen()) { can.sleep(); int start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + delta) % NUM_COLORS; - x2 = CW + RADIUS * sin(GRADIENT * start); - y2 = CH + RADIUS * cos(GRADIENT * start); - x3 = CW + RADIUS * sin(GRADIENT * (start + 1)); - y3 = CH + RADIUS * cos(GRADIENT * (start + 1)); - can.drawTriangle(CW, CH, x2, y2, x3, y3, - ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), true); + x2 = RADIUS * sin(GRADIENT * start); + y2 = RADIUS * cos(GRADIENT * start); + x3 = RADIUS * sin(GRADIENT * (start + 1)); + y3 = RADIUS * cos(GRADIENT * (start + 1)); + bg->drawTriangle(0,0,0, x2,y2,0, x3,y3,0, 0,0,0, + ColorHSV(start * 6.0f / NUM_COLORS, 1.0f, shading), false); } } } diff --git a/src/tests/testConstructors/Makefile b/src/tests/testConstructors/Makefile deleted file mode 100644 index 0e5dd9004..000000000 --- a/src/tests/testConstructors/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -# Makefile for testConstructors - -# ***************************************************** -# Variables to control Makefile operation - -CXX = g++ -RM = rm -f -r - -# Directory this example is contained in -MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) - -# Dependencies -_DEPS = \ - -# Main source file -TARGET = testConstructors - -# Object files -ODIR = obj -_OBJ = $(TARGET).o -OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) - -# To create obj directory -dummy_build_folder := $(shell mkdir -p $(ODIR)) - -# Flags -NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ - -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable - -ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL -BREW := -endif -ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL -BREW := -endif -ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut -BREW := -lomp -I"$(brew --prefix libomp)/include" -endif - -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - -LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ - $(BREW) -L/usr/local/lib \ - - -# **************************************************** -# Targets needed to bring the executable up to date - -all: $(TARGET) - -$(ODIR)/%.o: %.cpp $(_DEPS) - $(CXX) -c -o $@ $< $(CXXFLAGS) $(LFLAGS) - -$(TARGET): $(OBJ) - $(CXX) -o $@ $^ $(LFLAGS) - -.PHONY: clean - -clean: - $(RM) $(ODIR)/*.o $(ODIR) $(TARGET) - @echo "" - @tput setaf 5; - @echo "*************** All output files removed from $(DIR)! ***************" - @tput sgr0; - @echo "" \ No newline at end of file diff --git a/src/tests/testConstructors/testConstructors.cpp b/src/tests/testConstructors/testConstructors.cpp deleted file mode 100644 index 062fa79e5..000000000 --- a/src/tests/testConstructors/testConstructors.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * testConcavePolygon.cpp - * - * Usage: ./testConcavePolygon - */ - -#include -#include "Util.h" //Constants - -using namespace tsgl; - -/** - * \brief Draw Concave polygons, which have one or more interior angles > 180 - * \note See http://www.mathopenref.com/polygonconcave.html - * \details - * - Initialize a constant \b PSIZE. - * - Have four arrays of integers \b x, \b y, \b xx, and \b yy and set them to have size \b PSIZE. - * - Create an empty array of colors of size \b PSIZE and fill it with random colors. - * - Fill the arrays of integers, \b x and \b y with specific values (which will then be used in the while loop to draw a Concave polygon). - * - Fill the other arrays of integers, \b xx and \b yy, with specific values. - * - While the Canvas is open: - * - Sleep the internal timer of the Canvas until the Canvas is ready to draw. - * - Draw a Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * - Draw another Concave polygon on the Canvas and pass \b PSIZE, the arrays \b x and \b y, and the array of colors as arguments. - * . - * . - * \param can Reference to the Canvas being drawn to. - */ -void constructorFunction(Canvas& can) { - // srand(time(NULL)); - const int PSIZE = 50; - - ColorFloat fillColor[PSIZE]; - ColorFloat outlineColor[PSIZE]; - for (unsigned i = 0; i < PSIZE; ++i) { - fillColor[i] = Colors::randomColor(1.0f); - outlineColor[i] = Colors::randomColor(1.0f); - } - - can.drawRectangle(15, 5, 70, 95, fillColor[0], true); - can.drawRectangle(115, 5, 70, 95, fillColor[0], false); - can.drawRectangle(215, 5, 70, 95, fillColor, true); - can.drawRectangle(315, 5, 70, 95, fillColor, false); - - can.drawRectangle(415, 5, 70, 95, fillColor[0], outlineColor[0]); - can.drawRectangle(515, 5, 70, 95, fillColor, outlineColor[0]); - can.drawRectangle(615, 5, 70, 95, fillColor[0], outlineColor); - can.drawRectangle(715, 5, 70, 95, fillColor, outlineColor); - - can.drawSquare(5, 105, 90, fillColor[0], true); - can.drawSquare(105, 105, 90, fillColor[0], false); - can.drawSquare(205, 105, 90, fillColor, true); - can.drawSquare(305, 105, 90, fillColor, false); - - can.drawSquare(405, 105, 90, fillColor[0], outlineColor[0]); - can.drawSquare(505, 105, 90, fillColor, outlineColor[0]); - can.drawSquare(605, 105, 90, fillColor[0], outlineColor); - can.drawSquare(705, 105, 90, fillColor, outlineColor); - - can.drawStar(50, 250, 45, 6, fillColor[0], true, false); - can.drawStar(150, 250, 45, 6, fillColor[0], false, true); - can.drawStar(250, 250, 45, 6, fillColor, true, false); - can.drawStar(350, 250, 45, 6, fillColor, false, true); - - can.drawStar(450, 250, 45, 6, fillColor[0], outlineColor[0], false); - can.drawStar(550, 250, 45, 6, fillColor, outlineColor[0], false); - can.drawStar(650, 250, 45, 6, fillColor[0], outlineColor, false); - can.drawStar(750, 250, 45, 6, fillColor, outlineColor, false); - - can.drawRegularPolygon(50, 350, 45, 6, fillColor[0], true); - can.drawRegularPolygon(150, 350, 45, 6, fillColor[0], false); - can.drawRegularPolygon(250, 350, 45, 6, fillColor, true); - can.drawRegularPolygon(350, 350, 45, 6, fillColor, false); - - can.drawRegularPolygon(450, 350, 45, 6, fillColor[0], outlineColor[0]); - can.drawRegularPolygon(550, 350, 45, 6, fillColor, outlineColor[0]); - can.drawRegularPolygon(650, 350, 45, 6, fillColor[0], outlineColor); - can.drawRegularPolygon(750, 350, 45, 6, fillColor, outlineColor); - - can.drawEllipse(50, 450, 35, 45, fillColor[0], true); - can.drawEllipse(150, 450, 35, 45, fillColor[0], false); - can.drawEllipse(250, 450, 35, 45, fillColor, true); - can.drawEllipse(350, 450, 35, 45, fillColor, false); - - can.drawEllipse(450, 450, 35, 45, fillColor[0], outlineColor[0]); - can.drawEllipse(550, 450, 35, 45, fillColor, outlineColor[0]); - can.drawEllipse(650, 450, 35, 45, fillColor[0], outlineColor); - can.drawEllipse(750, 450, 35, 45, fillColor, outlineColor); - - can.drawTriangle(50, 505, 5, 595, 95, 595, fillColor[0], true); - can.drawTriangle(150, 505, 105, 595, 195, 595, fillColor[0], false); - can.drawTriangle(250, 505, 205, 595, 295, 595, fillColor, true); - can.drawTriangle(350, 505, 305, 595, 395, 595, fillColor, false); - - can.drawTriangle(450, 505, 405, 595, 495, 595, fillColor[0], outlineColor[0]); - can.drawTriangle(550, 505, 505, 595, 595, 595, fillColor, outlineColor[0]); - can.drawTriangle(650, 505, 605, 595, 695, 595, fillColor[0], outlineColor); - can.drawTriangle(750, 505, 705, 595, 795, 595, fillColor, outlineColor); - - can.drawCircle(50, 650, 45, fillColor[0], true); - can.drawCircle(150, 650, 45, fillColor[0], false); - can.drawCircle(250, 650, 45, fillColor, true); - can.drawCircle(350, 650, 45, fillColor, false); - - can.drawCircle(450, 650, 45, fillColor[0], outlineColor[0]); - can.drawCircle(550, 650, 45, fillColor, outlineColor[0]); - can.drawCircle(650, 650, 45, fillColor[0], outlineColor); - can.drawCircle(750, 650, 45, fillColor, outlineColor); - - int x1[5], x2[5], x3[5], x4[5], x5[5], x6[5], x7[5], x8[5], y1[5], y2[5], y3[5], y4[5], y5[5], y6[5], y7[5], y8[5]; - - x1[0] = x1[1] = 5; - x1[2] = 50; - x1[3] = x1[4] = 95; - - x2[0] = x2[1] = 105; - x2[2] = 150; - x2[3] = x2[4] = 195; - - x3[0] = x3[1] = 205; - x3[2] = 250; - x3[3] = x3[4] = 295; - - x4[0] = x4[1] = 305; - x4[2] = 350; - x4[3] = x4[4] = 395; - - x5[0] = x5[1] = 405; - x5[2] = 450; - x5[3] = x5[4] = 495; - - x6[0] = x6[1] = 505; - x6[2] = 550; - x6[3] = x6[4] = 595; - - x7[0] = x7[1] = 605; - x7[2] = 650; - x7[3] = x7[4] = 695; - - x8[0] = x8[1] = 705; - x8[2] = 750; - x8[3] = x8[4] = 795; - - y1[0] = y2[0] = y3[0] = y4[0] = y5[0] = y6[0] = y7[0] = y8[0] = 795; - y1[1] = y2[1] = y3[1] = y4[1] = y5[1] = y6[1] = y7[1] = y8[1] = 750; - y1[2] = y2[2] = y3[2] = y4[2] = y5[2] = y6[2] = y7[2] = y8[2] = 705; - y1[3] = y2[3] = y3[3] = y4[3] = y5[3] = y6[3] = y7[3] = y8[3] = 750; - y1[4] = y2[4] = y3[4] = y4[4] = y5[4] = y6[4] = y7[4] = y8[4] = 795; - - can.drawTriangleStrip(5, x1, y1, fillColor[0], true); - can.drawTriangleStrip(5, x2, y2, fillColor[0], false); - can.drawTriangleStrip(5, x3, y3, fillColor, true); - can.drawTriangleStrip(5, x4, y4, fillColor, false); - - can.drawTriangleStrip(5, x5, y5, fillColor[0], outlineColor[0]); - can.drawTriangleStrip(5, x6, y6, fillColor, outlineColor[0]); - can.drawTriangleStrip(5, x7, y7, fillColor[0], outlineColor); - can.drawTriangleStrip(5, x8, y8, fillColor, outlineColor); - - int x9[6], x10[6], x11[6], x12[6], x13[6], x14[6], x15[6], x16[6], - y9[6], y10[6], y11[6], y12[6], y13[6], y14[6], y15[6], y16[6]; - - x9[0] = x9[1] = 5; - x9[2] = x9[5] = 50; - x9[3] = x9[4] = 95; - - x10[0] = x10[1] = 105; - x10[2] = x10[5] = 150; - x10[3] = x10[4] = 195; - - x11[0] = x11[1] = 205; - x11[2] = x11[5] = 250; - x11[3] = x11[4] = 295; - - x12[0] = x12[1] = 305; - x12[2] = x12[5] = 350; - x12[3] = x12[4] = 395; - - x13[0] = x13[1] = 405; - x13[2] = x13[5] = 450; - x13[3] = x13[4] = 495; - - x14[0] = x14[1] = 505; - x14[2] = x14[5] = 550; - x14[3] = x14[4] = 595; - - x15[0] = x15[1] = 605; - x15[2] = x15[5] = 650; - x15[3] = x15[4] = 695; - - x16[0] = x16[1] = 705; - x16[2] = x16[5] = 750; - x16[3] = x16[4] = 795; - - y9[0] = y10[0] = y11[0] = y12[0] = y13[0] = y14[0] = y15[0] = y16[0] = 870; - y9[1] = y10[1] = y11[1] = y12[1] = y13[1] = y14[1] = y15[1] = y16[1] = 840; - y9[2] = y10[2] = y11[2] = y12[2] = y13[2] = y14[2] = y15[2] = y16[2] = 805; - y9[3] = y10[3] = y11[3] = y12[3] = y13[3] = y14[3] = y15[3] = y16[3] = 830; - y9[4] = y10[4] = y11[4] = y12[4] = y13[4] = y14[4] = y15[4] = y16[4] = 860; - y9[5] = y10[5] = y11[5] = y12[5] = y13[5] = y14[5] = y15[5] = y16[5] = 895; - - can.drawConvexPolygon(6, x9, y9, fillColor[0], true); - can.drawConvexPolygon(6, x10, y10, fillColor[0], false); - can.drawConvexPolygon(6, x11, y11, fillColor, true); - can.drawConvexPolygon(6, x12, y12, fillColor, false); - - can.drawConvexPolygon(6, x13, y13, fillColor[0], outlineColor[0]); - can.drawConvexPolygon(6, x14, y14, fillColor[0], outlineColor); - can.drawConvexPolygon(6, x15, y15, fillColor, outlineColor[0]); - can.drawConvexPolygon(6, x16, y16, fillColor, outlineColor); - - int x17[6], x18[6], x19[6], x20[6], x21[6], x22[6], x23[6], x24[6], - y17[6], y18[6], y19[6], y20[6], y21[6], y22[6], y23[6], y24[6]; - - x17[0] = x17[1] = 5; - x17[2] = x17[5] = 50; - x17[3] = x17[4] = 95; - - x18[0] = x18[1] = 105; - x18[2] = x18[5] = 150; - x18[3] = x18[4] = 195; - - x19[0] = x19[1] = 205; - x19[2] = x19[5] = 250; - x19[3] = x19[4] = 295; - - x20[0] = x20[1] = 305; - x20[2] = x20[5] = 350; - x20[3] = x20[4] = 395; - - x21[0] = x21[1] = 405; - x21[2] = x21[5] = 450; - x21[3] = x21[4] = 495; - - x22[0] = x22[1] = 505; - x22[2] = x22[5] = 550; - x22[3] = x22[4] = 595; - - x23[0] = x23[1] = 605; - x23[2] = x23[5] = 650; - x23[3] = x23[4] = 695; - - x24[0] = x24[1] = 705; - x24[2] = x24[5] = 750; - x24[3] = x24[4] = 795; - - y17[0] = y18[0] = y19[0] = y20[0] = y21[0] = y22[0] = y23[0] = y24[0] = 995; - y17[1] = y18[1] = y19[1] = y20[1] = y21[1] = y22[1] = y23[1] = y24[1] = 950; - y17[2] = y18[2] = y19[2] = y20[2] = y21[2] = y22[2] = y23[2] = y24[2] = 905; - y17[3] = y18[3] = y19[3] = y20[3] = y21[3] = y22[3] = y23[3] = y24[3] = 950; - y17[4] = y18[4] = y19[4] = y20[4] = y21[4] = y22[4] = y23[4] = y24[4] = 995; - y17[5] = y18[5] = y19[5] = y20[5] = y21[5] = y22[5] = y23[5] = y24[5] = 955; - - can.drawConcavePolygon(6, x17, y17, fillColor[0], true); - can.drawConcavePolygon(6, x18, y18, fillColor[0], true); - can.drawConcavePolygon(6, x19, y19, fillColor, true); - can.drawConcavePolygon(6, x20, y20, fillColor, true); - - can.drawConcavePolygon(6, x21, y21, fillColor[0], outlineColor[0]); - can.drawConcavePolygon(6, x22, y22, fillColor, outlineColor[0]); - can.drawConcavePolygon(6, x23, y23, fillColor[0], outlineColor); - can.drawConcavePolygon(6, x24, y24, fillColor, outlineColor); - - can.drawArrow(805, 5, 895, 95, fillColor[3], true); - can.drawArrow(805, 105, 895, 195, fillColor, true); - - can.drawLine(805, 205, 895, 295, fillColor[3]); - can.drawLine(805, 305, 895, 395, fillColor); - - int x25[5], x26[5], y25[5], y26[5]; - - x25[0] = x26[0] = 820; - x25[1] = x26[1] = 805; - x25[2] = x26[2] = 880; - x25[3] = x26[3] = 895; - x25[4] = x26[4] = 870; - - y25[0] = 450; - y25[1] = 405; - y25[2] = 420; - y25[3] = 460; - y25[4] = 495; - - y26[0] = 550; - y26[1] = 505; - y26[2] = 520; - y26[3] = 560; - y26[4] = 595; - - can.drawPolyline(5, x25, y25, fillColor[3]); - can.drawPolyline(5, x26, y26, outlineColor); - - while (can.isOpen()) { // Checks to see if the window has been closed - can.sleep(); - - } -} - -int main(int argc, char* argv[]) { - int w = 0.9*Canvas::getDisplayHeight(); - int h = w; - Canvas c(-1, -1, w, h, "Constructors", WHITE); - c.run(constructorFunction); -} diff --git a/src/tests/testDice/testCylinder.cpp b/src/tests/testDice/testCylinder.cpp new file mode 100644 index 000000000..8df38a692 --- /dev/null +++ b/src/tests/testDice/testCylinder.cpp @@ -0,0 +1,75 @@ +/* + * testCylinder.cpp + * + * Usage: ./testCylinder + */ + +#include +#include + +using namespace tsgl; + +void cylinderFunction(Canvas& can) { + ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), + ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), + ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), + ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), + ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; + Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); + Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); + can.add(testCylinder); + can.add(testCylinder2); + float rotation = 0.0f; + // GLfloat delta = 0.05; + bool boolean = false; + while (can.isOpen()) { + can.sleep(); + // testCylinder->setCenterX(sin(rotation)*2); + // testCylinder->setCenterY(cos(rotation)*2); + // testCylinder->setCenterZ(sin(rotation)); + // testCylinder->setYaw(rotation*45); + testCylinder->setPitch(rotation*45); + // testCylinder->setRoll(rotation*45); + // testCylinder->setHeight(sin(rotation)+1.01); + // testCylinder->setRadius(sin(rotation)+1.01); + // if(testCylinder->getHeight() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getHeight() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeHeightBy(delta); + // if(testCylinder->getRadius() >= 2) { + // delta = -0.05; + // } + // if(testCylinder->getRadius() <= 0.05) { + // delta = 0.05; + // } + // testCylinder->changeRadiusBy(delta); + // if (rotation*45 >= 360) { + // boolean = !boolean; + // rotation = 0; + // } + if (rotation*45 >= 360) { + if (boolean) { + testCylinder->setColor(RED); + } else { + testCylinder->setColor(colors); + } + boolean = !boolean; + rotation = 0; + } + rotation+=0.01; + } + + delete testCylinder; +} + +int main(int argc, char* argv[]) { + int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); + int h = (argc > 2) ? atoi(argv[2]) : w; + if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid + w = h = 960; //If not, set the width and height to a default value + Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); + c.run(cylinderFunction); +} \ No newline at end of file diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile index 8cc9732c4..1321597be 100644 --- a/src/tests/testGetPixels/Makefile +++ b/src/tests/testGetPixels/Makefile @@ -1,4 +1,4 @@ -# Makefile for testAlphaRectangle +# Makefile for testGetPixels # ***************************************************** # Variables to control Makefile operation @@ -14,7 +14,7 @@ DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) _DEPS = \ # Main source file -TARGET = testAlphaRectangle +TARGET = testGetPixels # Object files ODIR = obj diff --git a/src/tests/testGetPixels/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp index a3b2e55e9..60e853298 100644 --- a/src/tests/testGetPixels/testGetPixels.cpp +++ b/src/tests/testGetPixels/testGetPixels.cpp @@ -36,19 +36,20 @@ using namespace tsgl; * \param threads Number of threads to use. */ void getPixelsFunction(Canvas& can, int threads) { - unsigned width = can.getWindowWidth(), height = can.getWindowHeight(); - can.drawImage("../assets/pics/test.png", 0, 0, width, height); + Background * bg = can.getBackground(); + int width = can.getWindowWidth(), height = can.getWindowHeight(); + bg->drawImage(0,0,0,"./assets/pics/test.png",width, height, 0,0,0); can.sleepFor(0.5f); #pragma omp parallel num_threads(threads) { - unsigned blocksize = (double)height / omp_get_num_threads(); - unsigned row = blocksize * omp_get_thread_num(); + int blocksize = (double)height / omp_get_num_threads(); + int row = blocksize * omp_get_thread_num() - can.getWindowHeight()/2; while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class - for (unsigned y = row; y < row + blocksize; y++) { - for (unsigned x = 0; x < width; x++) { - ColorInt c = can.getPoint(x,y); - can.drawPoint(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); + for (int y = row; y < row + blocksize; y++) { + for (int x = -(width/2); x < width/2; x++) { + ColorInt c = bg->getPixel(x,y); + bg->drawPixel(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); } } } diff --git a/src/tests/testGradientWheel/testGradientWheel.cpp b/src/tests/testGradientWheel/testGradientWheel.cpp index 9e590ab01..44c3caaa0 100644 --- a/src/tests/testGradientWheel/testGradientWheel.cpp +++ b/src/tests/testGradientWheel/testGradientWheel.cpp @@ -22,6 +22,7 @@ using namespace tsgl; * \param threads Number of threads to use. */ void gradientWheelFunction(Canvas& can, int threads) { + Background * background = can.getBackground(); const int CW = can.getWindowWidth() / 2, // Half the window's width CH = can.getWindowHeight() / 2; // Half the window's height const float RADIUS = (CH < CW ? CH : CW) * .95, // Radius of wheel @@ -33,7 +34,8 @@ void gradientWheelFunction(Canvas& can, int threads) { int delta = (NUM_COLORS / threads); // Distance between threads to compute float shading = 1 - (float)tid / threads; // Shading based on thread ID ColorFloat color[3]; // RGB color to build - int start, end, xx[3], yy[3]; // Setup the arrays of values for vertices + int start, end; + float xx[3], yy[3], zz[3]; // Setup the arrays of values for vertices while (can.isOpen()) { can.sleep(); start = (NUM_COLORS - (can.getReps() % NUM_COLORS) + tid*delta) % NUM_COLORS; // Starting hue of the segment @@ -42,13 +44,14 @@ void gradientWheelFunction(Canvas& can, int threads) { color[1] = ColorHSV(start / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); color[2] = ColorHSV(end / (float)NUM_COLORS * 6, 1.0f, shading, 1.0f); - xx[0] = CW; yy[0] = CH; // Set first vertex to center of screen - xx[1] = CW + RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle - yy[1] = CH + RADIUS * cos(ARCLENGTH * start); - xx[2] = CW + RADIUS * sin(ARCLENGTH * (start + 1)); - yy[2] = CH + RADIUS * cos(ARCLENGTH * (start + 1)); + xx[0] = 0; yy[0] = 0; // Set first vertex to center of screen + xx[1] = RADIUS * sin(ARCLENGTH * start); // Add the next two vertices around the circle + yy[1] = RADIUS * cos(ARCLENGTH * start); + xx[2] = RADIUS * sin(ARCLENGTH * (start + 1)); + yy[2] = RADIUS * cos(ARCLENGTH * (start + 1)); + zz[0] = zz[1] = zz[2] = 0; - can.drawTriangleStrip(3, xx, yy, color, true); + background->drawTriangleStrip(0,0,0,3,xx,yy,zz,0,0,0,color); } } } diff --git a/src/tests/testGraydient/testGraydient.cpp b/src/tests/testGraydient/testGraydient.cpp index 4d3a2af77..4f5dfe0fa 100644 --- a/src/tests/testGraydient/testGraydient.cpp +++ b/src/tests/testGraydient/testGraydient.cpp @@ -25,13 +25,14 @@ using namespace tsgl; * \param threads Number of threads to use. */ void graydientFunction(Canvas& can, int threads) { + Background * bg = can.getBackground(); #pragma omp parallel num_threads(threads) { - for (int i = omp_get_thread_num(); i < can.getWindowWidth(); i += omp_get_num_threads()) { + for (int i = omp_get_thread_num() - (can.getWindowWidth() / 2); i < (can.getWindowWidth() / 2); i += omp_get_num_threads()) { if (!can.isOpen()) break; - for (int j = 0; j < can.getWindowHeight(); j++) { - int color = i * MAX_COLOR / 2 / can.getWindowWidth() + j * MAX_COLOR / 2 / can.getWindowHeight(); - can.drawPoint(i, j, ColorInt(color, color, color)); + for (int j = -can.getWindowHeight()/2; j < can.getWindowHeight()/2; j++) { + int color = (i + can.getWindowWidth() / 2) * MAX_COLOR / 2 / can.getWindowWidth() + (j + can.getWindowHeight()/2) * MAX_COLOR / 2 / can.getWindowHeight(); + bg->drawPixel(i, j, ColorInt(color, color, color)); } can.sleep(); } diff --git a/src/tests/testGreyscale/testGreyscale.cpp b/src/tests/testGreyscale/testGreyscale.cpp index f62b7cfbc..61f659fdd 100644 --- a/src/tests/testGreyscale/testGreyscale.cpp +++ b/src/tests/testGreyscale/testGreyscale.cpp @@ -45,31 +45,32 @@ using namespace tsgl; * \param numberOfThreads Reference to the number of threads to use. */ void greyScaleFunction(Canvas& can, int numberOfThreads) { + Background * background = can.getBackground(); int threads = numberOfThreads; clamp(threads,1,30); const unsigned thickness = 3; - const unsigned WW = can.getWindowWidth(),WH = can.getWindowHeight(); - can.drawImage("../assets/pics/colorful_cars.jpg", 0, 0, WW, WH); + const int WW = can.getWindowWidth(),WH = can.getWindowHeight(); + background->drawImage(0,0,0,"./assets/pics/colorful_cars.jpg", WW, WH, 0,0,0); can.sleepFor(0.25f); #pragma omp parallel num_threads(threads) { int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); - for (unsigned int y = row; y < row + blocksize; y++) { - for (unsigned int x = 0; x < WW; x++) { - ColorInt pixelColor = can.getPoint(x, y); + int blocksize = WH / nthreads; + int row = blocksize * omp_get_thread_num() - WH / 2; + // ColorFloat color = Colors::highContrastColor(omp_get_thread_num()); + for (int y = row; y < row + blocksize; y++) { + for (int x = -WW / 2; x < WW / 2; x++) { + ColorInt pixelColor = background->getPixel(x, y); int gray = (pixelColor.R + pixelColor.G + pixelColor.B) / 3; - can.drawPoint(x, y, ColorInt(gray, gray, gray)); + background->drawPixel(x, y, ColorInt(gray, gray, gray)); } if (! can.isOpen()) break; can.sleep(); } - for (unsigned int i = 0; i < thickness; i++) { - can.drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); - // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); - } + // for (unsigned int i = 0; i < thickness; i++) { + // bg->drawRectangle(i, row + i, WW - 1 - i, blocksize - i*2, color, false); + // // can.drawRectangle(column + i, i, column + blocksize - i, WH - 1 - i, color, false); + // } } } diff --git a/src/tests/testHighData/testHighData.cpp b/src/tests/testHighData/testHighData.cpp index 43ce27f05..744505b42 100644 --- a/src/tests/testHighData/testHighData.cpp +++ b/src/tests/testHighData/testHighData.cpp @@ -24,20 +24,21 @@ using namespace tsgl; * \param threads Number of threads to use. */ void highData(Canvas& can, unsigned threads) { + Background * background = can.getBackground(); const float HVAL = 6.0f/255.0f; // For converting integer hues to floating point values - const unsigned int width = can.getWindowWidth(), height = can.getWindowHeight(); + const int width = can.getWindowWidth(), height = can.getWindowHeight(); #pragma omp parallel num_threads(threads) { float tid = omp_get_thread_num(), nthreads = omp_get_num_threads(); int offset = (MAX_COLOR*tid)/nthreads; - unsigned bstart = tid*(width/nthreads); - unsigned bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; + int bstart = tid*(width/nthreads) - width/2; + int bend = (tid==nthreads) ? width-1 : bstart + width/nthreads; ColorHSV tcol= Colors::highContrastColor(tid); while (can.isOpen()) { tcol.H = HVAL * ((can.getReps() + offset) % MAX_COLOR); - for (unsigned i = bstart; i <= bend; i++) - for (unsigned int j = 0; j < height; j++) - can.drawPoint(i, j, tcol); + for (int i = bstart; i <= bend; i++) + for (int j = -height/2; j < height/2; j++) + background->drawPixel(i, j, tcol); can.handleIO(); } } diff --git a/src/tests/testInverter/ImageInverter.cpp b/src/tests/testInverter/ImageInverter.cpp index f559065b1..c13478f3d 100644 --- a/src/tests/testInverter/ImageInverter.cpp +++ b/src/tests/testInverter/ImageInverter.cpp @@ -10,7 +10,7 @@ ImageInverter::ImageInverter(const std::string& fileName, unsigned width, unsign myWidth(width), myHeight(height), myFileName(fileName) { myCanvas1.start(); - myCanvas1.drawImage(fileName, 0, 0, width, height); + myCanvas1.getBackground()->drawImage(0,0,0,fileName,width, height,0,0,0); // myCanvas1.drawRectangle(1,1,width-2,height-2,BLACK,false); sleep(1); myCanvas2.start(); @@ -22,21 +22,24 @@ void ImageInverter::run(unsigned numThreads) { } void ImageInverter::invertImage(unsigned numThreads) { + Background * background1 = myCanvas1.getBackground(); + Background * background2 = myCanvas2.getBackground(); + // background2->drawSquare(0,0,0,50,0,0,0,RED); ColorInt pixelColor; // #pragma omp parallel for num_threads(numThreads) - const unsigned WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); + const int WW = myCanvas1.getWindowWidth(),WH = myCanvas1.getWindowHeight(); #pragma omp parallel num_threads(numThreads) { int nthreads = omp_get_num_threads(); - unsigned int blocksize = WH / nthreads; - unsigned int row = blocksize * omp_get_thread_num(); - for (unsigned int x = row; x < row + blocksize; x++) { - for (unsigned int y = 0; y < WW; y++) { - pixelColor = myCanvas1.getPixel(x, y); + int blocksize = WW / nthreads; + int row = blocksize * omp_get_thread_num() - WW/2; + for (int x = row; x < row + blocksize; x++) { + for (int y = -WH/2; y < WH/2; y++) { + pixelColor = background1->getPixel(x, y); int invertedR = 255 - pixelColor.R; int invertedG = 255 - pixelColor.G; int invertedB = 255 - pixelColor.B; - myCanvas2.drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); + background2->drawPixel(x, y, ColorInt(invertedR,invertedG,invertedB) ); } myCanvas1.sleep(); myCanvas2.sleep(); diff --git a/src/tests/testInverter/testInverter.cpp b/src/tests/testInverter/testInverter.cpp index 370b4f62f..d94245150 100644 --- a/src/tests/testInverter/testInverter.cpp +++ b/src/tests/testInverter/testInverter.cpp @@ -5,12 +5,12 @@ */ #include -#include "ImageInverter/ImageInverter.h" +#include "ImageInverter.h" using namespace tsgl; int main(int argc, char* argv[]) { int numThreads = (argc > 1) ? atoi(argv[1]) : omp_get_num_procs(); - ImageInverter ii("../assets/pics/Car-colors.jpg", 1022, 1024); + ImageInverter ii("./assets/pics/Car-colors.jpg", 1022, 1024); ii.run(numThreads); } diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp index c4b05bbef..66a253cd5 100644 --- a/src/tests/testPixels/testPixels.cpp +++ b/src/tests/testPixels/testPixels.cpp @@ -48,7 +48,7 @@ void colorPointsFunction(Canvas& can, int numberOfThreads) { for (int j = 0; j < can.getWindowWidth(); j++) { // int id = omp_get_thread_num(); if (i % 2 == 0) { - background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, BLACK); + background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(0,0,0,255)); } else { background->drawPixel(j - can.getWindowWidth()/2, i - can.getWindowHeight()/2, ColorInt(i % 255, j % 255, (i*j) % 255)); } @@ -81,9 +81,9 @@ void colorPointsFunction(Canvas& can, int numberOfThreads) { // mouseX = can.getMouseX(); // mouseY = can.getMouseY(); // if (print) { - // background->drawPixel(mouseY, mouseX, RED); - // c = background->getPixel(mouseY, mouseX); // mouse Y is ROW. mouse X is COLUMN. Think about it. - // printf("%d, %d - ", mouseY, mouseX); + // c = background->getPixel(mouseX, mouseY); + // background->drawPixel(mouseX, mouseY, RED); + // printf("%d, %d - ", mouseX, mouseY); // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); // print = false; // } From 6a3584af924296714dd9f40e03e90f7c1541865d Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Wed, 29 Jul 2020 15:43:26 -0400 Subject: [PATCH 082/105] Tiny commit: fixing miscopy --- src/tests/testDice/testCylinder.cpp | 75 ----------------------------- 1 file changed, 75 deletions(-) delete mode 100644 src/tests/testDice/testCylinder.cpp diff --git a/src/tests/testDice/testCylinder.cpp b/src/tests/testDice/testCylinder.cpp deleted file mode 100644 index 8df38a692..000000000 --- a/src/tests/testDice/testCylinder.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * testCylinder.cpp - * - * Usage: ./testCylinder - */ - -#include -#include - -using namespace tsgl; - -void cylinderFunction(Canvas& can) { - ColorFloat colors[] = { ColorFloat(0.5,0.5,0.5,1), ColorFloat(0,0,1,1), - ColorFloat(0,1,0,1), ColorFloat(0,1,1,1), ColorFloat(1,0,0,1), - ColorFloat(1,0,1,1), ColorFloat(1,1,0,1), ColorFloat(1,1,1,1), - ColorFloat(0.5,0,0.5,1), ColorFloat(0,0.5,0.5,1), - ColorFloat(0.5,0.5,0,1), ColorFloat(0,0.5,1,1) }; - Cylinder * testCylinder = new Cylinder(0.0, 0.0, 0.0, 100, 100, 0.0, 0.0, 45.0, ColorFloat(1,0,0,1)); - Cylinder * testCylinder2 = new Cylinder(-300, 0.0, 0.0, 200, 150, 0.0, 45.0, 45.0, colors); - can.add(testCylinder); - can.add(testCylinder2); - float rotation = 0.0f; - // GLfloat delta = 0.05; - bool boolean = false; - while (can.isOpen()) { - can.sleep(); - // testCylinder->setCenterX(sin(rotation)*2); - // testCylinder->setCenterY(cos(rotation)*2); - // testCylinder->setCenterZ(sin(rotation)); - // testCylinder->setYaw(rotation*45); - testCylinder->setPitch(rotation*45); - // testCylinder->setRoll(rotation*45); - // testCylinder->setHeight(sin(rotation)+1.01); - // testCylinder->setRadius(sin(rotation)+1.01); - // if(testCylinder->getHeight() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getHeight() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeHeightBy(delta); - // if(testCylinder->getRadius() >= 2) { - // delta = -0.05; - // } - // if(testCylinder->getRadius() <= 0.05) { - // delta = 0.05; - // } - // testCylinder->changeRadiusBy(delta); - // if (rotation*45 >= 360) { - // boolean = !boolean; - // rotation = 0; - // } - if (rotation*45 >= 360) { - if (boolean) { - testCylinder->setColor(RED); - } else { - testCylinder->setColor(colors); - } - boolean = !boolean; - rotation = 0; - } - rotation+=0.01; - } - - delete testCylinder; -} - -int main(int argc, char* argv[]) { - int w = (argc > 1) ? atoi(argv[1]) : 0.9*Canvas::getDisplayHeight(); - int h = (argc > 2) ? atoi(argv[2]) : w; - if (w <= 0 || h <= 0) //Checked the passed width and height if they are valid - w = h = 960; //If not, set the width and height to a default value - Canvas c(-1, -1, 1024, 620, "Basic Cylinder", BLACK); - c.run(cylinderFunction); -} \ No newline at end of file From 6348dcb4961c932cf0474c5c0848ffbf14c7ac19 Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Mon, 3 Aug 2020 10:27:00 -0400 Subject: [PATCH 083/105] Optimizations; testGetPixels still slow --- src/TSGL/Background.cpp | 105 +++++++++--------- src/TSGL/Background.h | 6 +- src/examples/ArrayBubbleSort/Makefile | 28 +++-- src/examples/ArrayShakerSort/Makefile | 28 +++-- src/examples/Ballroom/Makefile | 28 +++-- src/examples/Clock/Makefile | 28 +++-- src/examples/Conway/Makefile | 28 +++-- src/examples/CubeRun/Makefile | 28 +++-- src/examples/DiningPhilosophers/Makefile | 28 +++-- src/examples/DiningPhilosophers3D/Makefile | 28 +++-- src/examples/Fireworks/Makefile | 28 +++-- src/examples/ForestFire/Makefile | 28 +++-- src/examples/Langton/Makefile | 28 +++-- src/examples/Mandelbrot/Makefile | 28 +++-- src/examples/MergeSort/Makefile | 28 +++-- src/examples/NewtonPendulum/Makefile | 28 +++-- src/examples/Pandemic/Makefile | 28 +++-- src/examples/ParallelPandemic/Makefile | 28 +++-- src/examples/Pong/Makefile | 28 +++-- src/examples/ProducerConsumer/Makefile | 28 +++-- src/examples/ReaderWriter/Makefile | 28 +++-- src/examples/SeaUrchin/Makefile | 28 +++-- src/examples/ShakerSort/Makefile | 28 +++-- src/examples/SolarSystem/Makefile | 28 +++-- src/examples/ThreadedArrayAddition/Makefile | 28 +++-- src/examples/ThreadedArrayBubbleSort/Makefile | 28 +++-- src/examples/ThreadedArrayOperations/Makefile | 28 +++-- src/examples/ThreadedSolarSystem/Makefile | 28 +++-- src/examples/Voronoi/Makefile | 28 +++-- src/tests/test2Dvs3D/Makefile | 28 +++-- src/tests/test3DRotation/Makefile | 28 +++-- src/tests/testAlphaRectangle/Makefile | 28 +++-- src/tests/testArrows/Makefile | 28 +++-- src/tests/testAura/Makefile | 28 +++-- src/tests/testBackground/Makefile | 28 +++-- src/tests/testBlurImage/Makefile | 28 +++-- src/tests/testCalcPi/Makefile | 28 +++-- src/tests/testCircle/Makefile | 28 +++-- src/tests/testColorWheel/Makefile | 28 +++-- src/tests/testConcavePolygon/Makefile | 28 +++-- src/tests/testCone/Makefile | 28 +++-- src/tests/testConvexPolygon/Makefile | 28 +++-- src/tests/testCosineIntegral/Makefile | 28 +++-- src/tests/testCube/Makefile | 28 +++-- src/tests/testCuboid/Makefile | 28 +++-- src/tests/testCylinder/Makefile | 28 +++-- src/tests/testDice/Makefile | 28 +++-- src/tests/testDiorama/Makefile | 28 +++-- src/tests/testEllipse/Makefile | 28 +++-- src/tests/testEllipsoid/Makefile | 28 +++-- src/tests/testFunction/Makefile | 28 +++-- src/tests/testGetPixels/Makefile | 28 +++-- src/tests/testGetPixels/testGetPixels.cpp | 2 +- src/tests/testGradientWheel/Makefile | 28 +++-- src/tests/testGraydient/Makefile | 28 +++-- src/tests/testGreyscale/Makefile | 28 +++-- src/tests/testHighData/Makefile | 28 +++-- src/tests/testImage/Makefile | 28 +++-- src/tests/testImageCart/Makefile | 29 +++-- src/tests/testInverter/Makefile | 28 +++-- src/tests/testLineChain/Makefile | 28 +++-- src/tests/testLineFan/Makefile | 28 +++-- src/tests/testLines/Makefile | 28 +++-- src/tests/testMouse/Makefile | 28 +++-- src/tests/testPixels/Makefile | 28 +++-- src/tests/testPixels/testPixels.cpp | 2 +- src/tests/testPrism/Makefile | 28 +++-- src/tests/testProcedural/Makefile | 28 +++-- src/tests/testProgressBar/Makefile | 28 +++-- src/tests/testProjectiles/Makefile | 28 +++-- src/tests/testPyramid/Makefile | 28 +++-- src/tests/testRectangle/Makefile | 28 +++-- src/tests/testRegularPolygon/Makefile | 28 +++-- src/tests/testScreenshot/Makefile | 28 +++-- src/tests/testSpectrogram/Makefile | 28 +++-- src/tests/testSpectrum/Makefile | 28 +++-- src/tests/testSphere/Makefile | 28 +++-- src/tests/testSquare/Makefile | 28 +++-- src/tests/testStar/Makefile | 28 +++-- src/tests/testText/Makefile | 28 +++-- src/tests/testTextCart/Makefile | 28 +++-- src/tests/testTextTwo/Makefile | 28 +++-- src/tests/testTransparency/Makefile | 28 +++-- src/tests/testTriangle/Makefile | 28 +++-- src/tests/testTriangleStrip/Makefile | 28 +++-- src/tests/testUnits/Makefile | 28 +++-- src/tests/test_specs/Makefile | 28 +++-- 87 files changed, 1553 insertions(+), 887 deletions(-) diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp index 267adc20c..d785740b7 100644 --- a/src/TSGL/Background.cpp +++ b/src/TSGL/Background.cpp @@ -35,10 +35,12 @@ Background::Background(GLint width, GLint height, const ColorFloat &clearColor) } readPixelMutex.unlock(); pixelBufferMutex.lock(); - pixelTextureBuffer = new uint8_t[myWidth * myHeight * 4]; - for (int i = 0; i < myWidth * myHeight * 4; ++i) { - pixelTextureBuffer[i] = 0; + pixelBufferCapacity = myWidth * myHeight * 7 * 2; + pixelBuffer = new GLfloat[pixelBufferCapacity]; + for (int i = 0; i < pixelBufferCapacity; ++i) { + pixelBuffer[i] = 0; } + pixelBufferPosition = pixelLastPosition = 0; pixelBufferMutex.unlock(); vertices = new GLfloat[30]; @@ -103,19 +105,6 @@ void Background::init(Shader * shapeS, Shader * textS, Shader * textureS, GLFWwi glBindFramebuffer(GL_FRAMEBUFFER, 0); - // generate a texture for the pixels - // -------------------------- - glGenTextures(1, &pixelTexture); - glBindTexture(GL_TEXTURE_2D, pixelTexture); - // Set texture parameters for wrapping. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // Set texture parameters for filtering. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glBindTexture(GL_TEXTURE_2D, 0); - shapeShader = shapeS; textShader = textS; textureShader = textureS; @@ -163,47 +152,54 @@ void Background::draw() { myDrawables->clear(); drawableMutex.unlock(); - // setting up texture shaders for both pixel drawing and post-blit render - selectShaders(TEXTURE_SHADER_TYPE); - - glm::mat4 model = glm::mat4(1.0f); - model = glm::scale(model, glm::vec3(myWidth, myHeight, 1)); - - unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); - - unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); - glUniform1f(alphaLoc, 1.0f); - - // check for new pixels being drawn - pixelBufferMutex.lock(); + // draw new pixels to non-MSAA framebuffer if (newPixelsDrawn) { - glBindTexture(GL_TEXTURE_2D, pixelTexture); - - // actually generate the texture + mipmaps - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myWidth, myHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, pixelTextureBuffer); - glGenerateMipmap(GL_TEXTURE_2D); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, vertices, GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLES, 0, 6); - + selectShaders(SHAPE_SHADER_TYPE); + glDisable(GL_MULTISAMPLE); + pixelBufferMutex.lock(); + int pos = pixelBufferPosition; + int posLast = pixelLastPosition; newPixelsDrawn = false; - for (int i = 0; i < myWidth * myHeight * 4; ++i) { - pixelTextureBuffer[i] = 0; + pixelBufferMutex.unlock(); + if (loopAround) { + int toend = pixelBufferCapacity - posLast; + glBufferData(GL_ARRAY_BUFFER, toend * sizeof(float), &pixelBuffer[posLast], GL_DYNAMIC_DRAW); + glDrawArrays(GL_POINTS, 0, toend); + posLast = 0; + loopAround = false; + } + int pbsize = pos - posLast; + if (pbsize > 0) { + glBufferData(GL_ARRAY_BUFFER, pbsize * sizeof(float), &pixelBuffer[posLast], GL_DYNAMIC_DRAW); + glDrawArrays(GL_POINTS, 0, pbsize/7); + pixelLastPosition = pos; } + glEnable(GL_MULTISAMPLE); } - pixelBufferMutex.unlock(); // blit MSAA framebuffer to non-MSAA framebuffer's texture glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO); glBlitFramebuffer(0, 0, myWidth, myHeight, 0, 0, myWidth, myHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); + // setting up texture shaders for post-blit render + selectShaders(TEXTURE_SHADER_TYPE); + + glm::mat4 model = glm::mat4(1.0f); + model = glm::scale(model, glm::vec3(myWidth, myHeight, 1)); + + unsigned int modelLoc = glGetUniformLocation(textureShader->ID, "model"); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + + unsigned int alphaLoc = glGetUniformLocation(textureShader->ID, "alpha"); + glUniform1f(alphaLoc, 1.0f); + // render non-MSAA framebuffer's texture to default framebuffer glBindTexture(GL_TEXTURE_2D,intermediateTexture); glPixelStorei(GL_UNPACK_ALIGNMENT,4); @@ -552,12 +548,18 @@ void Background::drawPixel(int x, int y, ColorInt c) { return; } pixelBufferMutex.lock(); - x += myWidth / 2; - y += myHeight / 2; - pixelTextureBuffer[(y * myWidth + x) * 4] = c.R; - pixelTextureBuffer[(y * myWidth + x) * 4 + 1] = c.G; - pixelTextureBuffer[(y * myWidth + x) * 4 + 2] = c.B; - pixelTextureBuffer[(y * myWidth + x) * 4 + 3] = c.A; + if (pixelBufferPosition >= pixelBufferCapacity) { + loopAround = true; + pixelBufferPosition = 0; + } + pixelBuffer[pixelBufferPosition] = x; + pixelBuffer[pixelBufferPosition + 1] = y; + pixelBuffer[pixelBufferPosition + 2] = 0; + pixelBuffer[pixelBufferPosition + 3] = (float) c.R / 255; + pixelBuffer[pixelBufferPosition + 4] = (float) c.G / 255; + pixelBuffer[pixelBufferPosition + 5] = (float) c.B / 255; + pixelBuffer[pixelBufferPosition + 6] = (float) c.A / 255; + pixelBufferPosition += 7; newPixelsDrawn = true; pixelBufferMutex.unlock(); } @@ -921,10 +923,9 @@ void Background::setClearColor(ColorFloat c) { Background::~Background() { myDrawables->clear(); delete [] readPixelBuffer; - delete [] pixelTextureBuffer; + delete [] pixelBuffer; delete [] vertices; delete myDrawables; - glDeleteTextures(1, &pixelTexture); glDeleteTextures(1, &intermediateFBO); glDeleteFramebuffers(1, &intermediateTexture); glDeleteTextures(1, &multisampledTexture); diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h index 32db5169b..ebc5a6de0 100644 --- a/src/TSGL/Background.h +++ b/src/TSGL/Background.h @@ -52,9 +52,11 @@ class Background { uint8_t* readPixelBuffer; std::mutex pixelBufferMutex; - GLuint pixelTexture; - uint8_t* pixelTextureBuffer; + GLfloat* pixelBuffer; bool newPixelsDrawn; + bool loopAround; + int pixelBufferPosition, pixelLastPosition; + int pixelBufferCapacity; bool complete; std::mutex attribMutex; diff --git a/src/examples/ArrayBubbleSort/Makefile b/src/examples/ArrayBubbleSort/Makefile index b55827979..7c11161b9 100644 --- a/src/examples/ArrayBubbleSort/Makefile +++ b/src/examples/ArrayBubbleSort/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ArrayShakerSort/Makefile b/src/examples/ArrayShakerSort/Makefile index bfd829499..84859b908 100644 --- a/src/examples/ArrayShakerSort/Makefile +++ b/src/examples/ArrayShakerSort/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Ballroom/Makefile b/src/examples/Ballroom/Makefile index 48e2208aa..0c4dac6ea 100644 --- a/src/examples/Ballroom/Makefile +++ b/src/examples/Ballroom/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Clock/Makefile b/src/examples/Clock/Makefile index 0154cdb23..b2391b03d 100644 --- a/src/examples/Clock/Makefile +++ b/src/examples/Clock/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Conway/Makefile b/src/examples/Conway/Makefile index bf7830f2b..f70f2aa07 100644 --- a/src/examples/Conway/Makefile +++ b/src/examples/Conway/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/CubeRun/Makefile b/src/examples/CubeRun/Makefile index c1b4ed2e6..c5bf5fe6e 100644 --- a/src/examples/CubeRun/Makefile +++ b/src/examples/CubeRun/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/DiningPhilosophers/Makefile b/src/examples/DiningPhilosophers/Makefile index 5d579105e..c19ed7663 100644 --- a/src/examples/DiningPhilosophers/Makefile +++ b/src/examples/DiningPhilosophers/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/DiningPhilosophers3D/Makefile b/src/examples/DiningPhilosophers3D/Makefile index 32ae17ad9..b64aff46b 100644 --- a/src/examples/DiningPhilosophers3D/Makefile +++ b/src/examples/DiningPhilosophers3D/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Fireworks/Makefile b/src/examples/Fireworks/Makefile index 6ffed5e5a..069961f52 100644 --- a/src/examples/Fireworks/Makefile +++ b/src/examples/Fireworks/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ForestFire/Makefile b/src/examples/ForestFire/Makefile index 434d5c80f..5a5e3c30a 100644 --- a/src/examples/ForestFire/Makefile +++ b/src/examples/ForestFire/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Langton/Makefile b/src/examples/Langton/Makefile index 345e94a77..475a54b37 100644 --- a/src/examples/Langton/Makefile +++ b/src/examples/Langton/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Mandelbrot/Makefile b/src/examples/Mandelbrot/Makefile index 04c175425..f09acd988 100644 --- a/src/examples/Mandelbrot/Makefile +++ b/src/examples/Mandelbrot/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/MergeSort/Makefile b/src/examples/MergeSort/Makefile index 92f49411d..7844f8fb9 100644 --- a/src/examples/MergeSort/Makefile +++ b/src/examples/MergeSort/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/NewtonPendulum/Makefile b/src/examples/NewtonPendulum/Makefile index 0536866f2..299fefdbb 100644 --- a/src/examples/NewtonPendulum/Makefile +++ b/src/examples/NewtonPendulum/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Pandemic/Makefile b/src/examples/Pandemic/Makefile index d54fe0591..73f09c86b 100644 --- a/src/examples/Pandemic/Makefile +++ b/src/examples/Pandemic/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ParallelPandemic/Makefile b/src/examples/ParallelPandemic/Makefile index 4fa801d0f..783328409 100644 --- a/src/examples/ParallelPandemic/Makefile +++ b/src/examples/ParallelPandemic/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Pong/Makefile b/src/examples/Pong/Makefile index 6ad0cf884..b74c29b13 100644 --- a/src/examples/Pong/Makefile +++ b/src/examples/Pong/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ProducerConsumer/Makefile b/src/examples/ProducerConsumer/Makefile index 3ff99fa2e..b025a15ae 100644 --- a/src/examples/ProducerConsumer/Makefile +++ b/src/examples/ProducerConsumer/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ReaderWriter/Makefile b/src/examples/ReaderWriter/Makefile index 862c62354..b54a991fd 100644 --- a/src/examples/ReaderWriter/Makefile +++ b/src/examples/ReaderWriter/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/SeaUrchin/Makefile b/src/examples/SeaUrchin/Makefile index 1be09619d..8a9d22249 100644 --- a/src/examples/SeaUrchin/Makefile +++ b/src/examples/SeaUrchin/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ShakerSort/Makefile b/src/examples/ShakerSort/Makefile index 917d5725c..e19237401 100644 --- a/src/examples/ShakerSort/Makefile +++ b/src/examples/ShakerSort/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/SolarSystem/Makefile b/src/examples/SolarSystem/Makefile index f4c17809f..a3952eb2c 100644 --- a/src/examples/SolarSystem/Makefile +++ b/src/examples/SolarSystem/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ThreadedArrayAddition/Makefile b/src/examples/ThreadedArrayAddition/Makefile index b59faab55..b9de2c040 100644 --- a/src/examples/ThreadedArrayAddition/Makefile +++ b/src/examples/ThreadedArrayAddition/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ThreadedArrayBubbleSort/Makefile b/src/examples/ThreadedArrayBubbleSort/Makefile index 132b5768c..da543ef97 100644 --- a/src/examples/ThreadedArrayBubbleSort/Makefile +++ b/src/examples/ThreadedArrayBubbleSort/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ThreadedArrayOperations/Makefile b/src/examples/ThreadedArrayOperations/Makefile index b6c42c27d..6ab959e48 100644 --- a/src/examples/ThreadedArrayOperations/Makefile +++ b/src/examples/ThreadedArrayOperations/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/ThreadedSolarSystem/Makefile b/src/examples/ThreadedSolarSystem/Makefile index 3749ae27d..231bc1ba0 100644 --- a/src/examples/ThreadedSolarSystem/Makefile +++ b/src/examples/ThreadedSolarSystem/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/examples/Voronoi/Makefile b/src/examples/Voronoi/Makefile index 889b6a711..9c97a45a2 100644 --- a/src/examples/Voronoi/Makefile +++ b/src/examples/Voronoi/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/test2Dvs3D/Makefile b/src/tests/test2Dvs3D/Makefile index b47e6705b..cc3995c7c 100644 --- a/src/tests/test2Dvs3D/Makefile +++ b/src/tests/test2Dvs3D/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/test3DRotation/Makefile b/src/tests/test3DRotation/Makefile index 4867e5663..f0abfc243 100644 --- a/src/tests/test3DRotation/Makefile +++ b/src/tests/test3DRotation/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testAlphaRectangle/Makefile b/src/tests/testAlphaRectangle/Makefile index 8cc9732c4..7429fefbd 100644 --- a/src/tests/testAlphaRectangle/Makefile +++ b/src/tests/testAlphaRectangle/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testArrows/Makefile b/src/tests/testArrows/Makefile index f5ce82086..aef5ba7ea 100644 --- a/src/tests/testArrows/Makefile +++ b/src/tests/testArrows/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testAura/Makefile b/src/tests/testAura/Makefile index ac0b04617..251986afb 100644 --- a/src/tests/testAura/Makefile +++ b/src/tests/testAura/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testBackground/Makefile b/src/tests/testBackground/Makefile index 44d45535e..a585dbc4f 100644 --- a/src/tests/testBackground/Makefile +++ b/src/tests/testBackground/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testBlurImage/Makefile b/src/tests/testBlurImage/Makefile index cd397fbc2..9625ad7d0 100644 --- a/src/tests/testBlurImage/Makefile +++ b/src/tests/testBlurImage/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCalcPi/Makefile b/src/tests/testCalcPi/Makefile index 3143da482..35e1c6e9f 100644 --- a/src/tests/testCalcPi/Makefile +++ b/src/tests/testCalcPi/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCircle/Makefile b/src/tests/testCircle/Makefile index b6db6f7c1..809d18ecd 100644 --- a/src/tests/testCircle/Makefile +++ b/src/tests/testCircle/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testColorWheel/Makefile b/src/tests/testColorWheel/Makefile index 5597878ec..f53e67dbf 100644 --- a/src/tests/testColorWheel/Makefile +++ b/src/tests/testColorWheel/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testConcavePolygon/Makefile b/src/tests/testConcavePolygon/Makefile index 1a96d509d..f3bad5573 100644 --- a/src/tests/testConcavePolygon/Makefile +++ b/src/tests/testConcavePolygon/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCone/Makefile b/src/tests/testCone/Makefile index 1397f98ec..3d33654e4 100644 --- a/src/tests/testCone/Makefile +++ b/src/tests/testCone/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testConvexPolygon/Makefile b/src/tests/testConvexPolygon/Makefile index 6537beaf5..1d0767b05 100644 --- a/src/tests/testConvexPolygon/Makefile +++ b/src/tests/testConvexPolygon/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCosineIntegral/Makefile b/src/tests/testCosineIntegral/Makefile index 9168d0c81..057ef3ede 100644 --- a/src/tests/testCosineIntegral/Makefile +++ b/src/tests/testCosineIntegral/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCube/Makefile b/src/tests/testCube/Makefile index a6cee0436..72dd32cdf 100644 --- a/src/tests/testCube/Makefile +++ b/src/tests/testCube/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCuboid/Makefile b/src/tests/testCuboid/Makefile index 39d6305bc..df99bb16f 100644 --- a/src/tests/testCuboid/Makefile +++ b/src/tests/testCuboid/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testCylinder/Makefile b/src/tests/testCylinder/Makefile index c4aaa8cbd..ba05bbb95 100644 --- a/src/tests/testCylinder/Makefile +++ b/src/tests/testCylinder/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testDice/Makefile b/src/tests/testDice/Makefile index fecc9dee9..dc8082271 100644 --- a/src/tests/testDice/Makefile +++ b/src/tests/testDice/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testDiorama/Makefile b/src/tests/testDiorama/Makefile index b16c3dcb3..1dc0695b8 100644 --- a/src/tests/testDiorama/Makefile +++ b/src/tests/testDiorama/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testEllipse/Makefile b/src/tests/testEllipse/Makefile index 616f25dcf..c945b4db6 100644 --- a/src/tests/testEllipse/Makefile +++ b/src/tests/testEllipse/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testEllipsoid/Makefile b/src/tests/testEllipsoid/Makefile index 4a17d0ec8..1a90b84a8 100644 --- a/src/tests/testEllipsoid/Makefile +++ b/src/tests/testEllipsoid/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testFunction/Makefile b/src/tests/testFunction/Makefile index a793694b0..cdcee8187 100644 --- a/src/tests/testFunction/Makefile +++ b/src/tests/testFunction/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testGetPixels/Makefile b/src/tests/testGetPixels/Makefile index 1321597be..00152404f 100644 --- a/src/tests/testGetPixels/Makefile +++ b/src/tests/testGetPixels/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testGetPixels/testGetPixels.cpp b/src/tests/testGetPixels/testGetPixels.cpp index 60e853298..2b3fd9fc1 100644 --- a/src/tests/testGetPixels/testGetPixels.cpp +++ b/src/tests/testGetPixels/testGetPixels.cpp @@ -49,7 +49,7 @@ void getPixelsFunction(Canvas& can, int threads) { for (int y = row; y < row + blocksize; y++) { for (int x = -(width/2); x < width/2; x++) { ColorInt c = bg->getPixel(x,y); - bg->drawPixel(x, y, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); + bg->drawPixel(x, y+1, ColorInt((1+c.R) % NUM_COLORS, (1+c.G) % NUM_COLORS, (1+c.B) % NUM_COLORS)); } } } diff --git a/src/tests/testGradientWheel/Makefile b/src/tests/testGradientWheel/Makefile index a938cb996..43c4e3c8b 100644 --- a/src/tests/testGradientWheel/Makefile +++ b/src/tests/testGradientWheel/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testGraydient/Makefile b/src/tests/testGraydient/Makefile index d2c98911f..411fe595d 100644 --- a/src/tests/testGraydient/Makefile +++ b/src/tests/testGraydient/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testGreyscale/Makefile b/src/tests/testGreyscale/Makefile index f8006bd00..ab9903a79 100644 --- a/src/tests/testGreyscale/Makefile +++ b/src/tests/testGreyscale/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testHighData/Makefile b/src/tests/testHighData/Makefile index 7a7234a61..e6d271c4f 100644 --- a/src/tests/testHighData/Makefile +++ b/src/tests/testHighData/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testImage/Makefile b/src/tests/testImage/Makefile index e6be7a235..52e75c587 100644 --- a/src/tests/testImage/Makefile +++ b/src/tests/testImage/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testImageCart/Makefile b/src/tests/testImageCart/Makefile index b25be2ee2..f148ad610 100644 --- a/src/tests/testImageCart/Makefile +++ b/src/tests/testImageCart/Makefile @@ -41,17 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ - +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testInverter/Makefile b/src/tests/testInverter/Makefile index 025b99295..570218fc2 100644 --- a/src/tests/testInverter/Makefile +++ b/src/tests/testInverter/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testLineChain/Makefile b/src/tests/testLineChain/Makefile index 57e438eef..4ee2e3d41 100644 --- a/src/tests/testLineChain/Makefile +++ b/src/tests/testLineChain/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testLineFan/Makefile b/src/tests/testLineFan/Makefile index bd5bb0e0d..be9c9b113 100644 --- a/src/tests/testLineFan/Makefile +++ b/src/tests/testLineFan/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testLines/Makefile b/src/tests/testLines/Makefile index 62c9bd644..c3275149e 100644 --- a/src/tests/testLines/Makefile +++ b/src/tests/testLines/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testMouse/Makefile b/src/tests/testMouse/Makefile index 610825c18..4e033ec34 100644 --- a/src/tests/testMouse/Makefile +++ b/src/tests/testMouse/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testPixels/Makefile b/src/tests/testPixels/Makefile index 4504d8feb..af88c097c 100644 --- a/src/tests/testPixels/Makefile +++ b/src/tests/testPixels/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testPixels/testPixels.cpp b/src/tests/testPixels/testPixels.cpp index 66a253cd5..8080781ba 100644 --- a/src/tests/testPixels/testPixels.cpp +++ b/src/tests/testPixels/testPixels.cpp @@ -82,7 +82,7 @@ void colorPointsFunction(Canvas& can, int numberOfThreads) { // mouseY = can.getMouseY(); // if (print) { // c = background->getPixel(mouseX, mouseY); - // background->drawPixel(mouseX, mouseY, RED); + // background->drawPixel(mouseX, mouseY, ColorInt(255,0,0,255)); // printf("%d, %d - ", mouseX, mouseY); // printf("%d:%d:%d:%d\n", c.R, c.G, c.B, c.A); // print = false; diff --git a/src/tests/testPrism/Makefile b/src/tests/testPrism/Makefile index 9635d2909..f1ac0f82e 100644 --- a/src/tests/testPrism/Makefile +++ b/src/tests/testPrism/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testProcedural/Makefile b/src/tests/testProcedural/Makefile index 5046e7a51..a371f8d55 100644 --- a/src/tests/testProcedural/Makefile +++ b/src/tests/testProcedural/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testProgressBar/Makefile b/src/tests/testProgressBar/Makefile index b6a8a30a0..2bd3f5be5 100644 --- a/src/tests/testProgressBar/Makefile +++ b/src/tests/testProgressBar/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testProjectiles/Makefile b/src/tests/testProjectiles/Makefile index 4fc0cf1a1..59b4cd1da 100644 --- a/src/tests/testProjectiles/Makefile +++ b/src/tests/testProjectiles/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testPyramid/Makefile b/src/tests/testPyramid/Makefile index 30b527bd8..bd1a7ee1f 100644 --- a/src/tests/testPyramid/Makefile +++ b/src/tests/testPyramid/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testRectangle/Makefile b/src/tests/testRectangle/Makefile index 84df3c14c..84a4f5fdd 100644 --- a/src/tests/testRectangle/Makefile +++ b/src/tests/testRectangle/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testRegularPolygon/Makefile b/src/tests/testRegularPolygon/Makefile index 5c4d9e646..f4729a9ed 100644 --- a/src/tests/testRegularPolygon/Makefile +++ b/src/tests/testRegularPolygon/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testScreenshot/Makefile b/src/tests/testScreenshot/Makefile index 7233aca90..f0ff9d04d 100644 --- a/src/tests/testScreenshot/Makefile +++ b/src/tests/testScreenshot/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testSpectrogram/Makefile b/src/tests/testSpectrogram/Makefile index d400ed195..01dcfe154 100644 --- a/src/tests/testSpectrogram/Makefile +++ b/src/tests/testSpectrogram/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testSpectrum/Makefile b/src/tests/testSpectrum/Makefile index e38142bf9..3deaef2d5 100644 --- a/src/tests/testSpectrum/Makefile +++ b/src/tests/testSpectrum/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testSphere/Makefile b/src/tests/testSphere/Makefile index 9aca41ab1..2e99d641a 100644 --- a/src/tests/testSphere/Makefile +++ b/src/tests/testSphere/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testSquare/Makefile b/src/tests/testSquare/Makefile index 611a990b6..92938ee01 100644 --- a/src/tests/testSquare/Makefile +++ b/src/tests/testSquare/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testStar/Makefile b/src/tests/testStar/Makefile index 91533096d..e91462b1d 100644 --- a/src/tests/testStar/Makefile +++ b/src/tests/testStar/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testText/Makefile b/src/tests/testText/Makefile index 090716448..1c5693dbe 100644 --- a/src/tests/testText/Makefile +++ b/src/tests/testText/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testTextCart/Makefile b/src/tests/testTextCart/Makefile index f7764c963..e1fce8625 100644 --- a/src/tests/testTextCart/Makefile +++ b/src/tests/testTextCart/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testTextTwo/Makefile b/src/tests/testTextTwo/Makefile index d67a6ad46..30b56aa19 100644 --- a/src/tests/testTextTwo/Makefile +++ b/src/tests/testTextTwo/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testTransparency/Makefile b/src/tests/testTransparency/Makefile index 3fc4549c1..69bb76b28 100644 --- a/src/tests/testTransparency/Makefile +++ b/src/tests/testTransparency/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testTriangle/Makefile b/src/tests/testTriangle/Makefile index eb6f1377b..1969c5554 100644 --- a/src/tests/testTriangle/Makefile +++ b/src/tests/testTriangle/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testTriangleStrip/Makefile b/src/tests/testTriangleStrip/Makefile index 45490579b..5316d9360 100644 --- a/src/tests/testTriangleStrip/Makefile +++ b/src/tests/testTriangleStrip/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/testUnits/Makefile b/src/tests/testUnits/Makefile index dfbd88cc5..f19f2b5da 100644 --- a/src/tests/testUnits/Makefile +++ b/src/tests/testUnits/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ diff --git a/src/tests/test_specs/Makefile b/src/tests/test_specs/Makefile index ccec4f1bf..16b2d9306 100644 --- a/src/tests/test_specs/Makefile +++ b/src/tests/test_specs/Makefile @@ -41,16 +41,24 @@ GL_FLAGS = -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif -CXXFLAGS = -Wall -g\ - -I/usr/local/include/TSGL \ - -I/usr/local/include \ - -I/usr/local/include/freetype2 \ - -I/usr/local/include/freetype2/freetype \ - $(NOWARN)\ - -std=c++11\ - -Wc++11-compat\ - -I/usr/include \ - -I/usr/include/freetype2 \ +CXXFLAGS = -O3 -g3 -ggdb3 \ + -Wall -Wextra \ + -D__GXX_EXPERIMENTAL_CXX0X__ \ + -I/usr/local/include/Cellar/glfw3/3.3/include/ \ + -I/usr/local/include/TSGL \ + -I/usr/local/include \ + -I/usr/local/include/freetype2 \ + -I/usr/local/include/freetype2/freetype \ + $(NOWARN)\ + -std=c++11\ + -Wc++11-compat\ + -I/opt/AMDAPP/include/ \ + -I/usr/include/c++/4.6/ \ + -I/usr/include/c++/4.6/x86_64-linux-gnu/ \ + -I/usr/lib/gcc/x86_64-linux-gnu/9/include/ \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -I/usr/include/freetype2/freetype \ LFLAGS = -g -ltsgl -lfreetype -lGLEW -lglfw $(GL_FLAGS) -fopenmp \ $(BREW) -L/usr/local/lib \ From 32a4577b79d8ad5ad2648ffaf266d7d2dee0470e Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Tue, 4 Aug 2020 16:23:55 -0400 Subject: [PATCH 084/105] Line updated w/ endpoint constructors, tests fixed --- src/TSGL/Background.cpp | 42 +++++ src/TSGL/Background.h | 4 + src/TSGL/Line.cpp | 177 ++++++++++++++++++++-- src/TSGL/Line.h | 51 +++++++ src/tests/Makefile | 4 +- src/tests/testLineChain/testLineChain.cpp | 11 +- src/tests/testLineFan/testLineFan.cpp | 7 +- src/tests/testLines/testLines.cpp | 28 +++- 8 files changed, 297 insertions(+), 27 deletions(-) diff --git a/src/TSGL/Background.cpp b/src/TSGL/Background.cpp index d785740b7..a6703b125 100644 --- a/src/TSGL/Background.cpp +++ b/src/TSGL/Background.cpp @@ -498,6 +498,48 @@ void Background::drawImage(float x, float y, float z, std::string filename, floa drawableMutex.unlock(); } +/*! + * \brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the color of the Line. + */ +void Background::drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color) { + Line * l = new Line(x1,y1,z1,x2,y2,z2,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + +/*! + * \brief Procedurally draws a Line to the Background. + * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color Array of ColorFloats for the Line's vertices. + */ +void Background::drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color[]) { + Line * l = new Line(x1,y1,z1,x2,y2,z2,yaw,pitch,roll,color); + drawableMutex.lock(); + myDrawables->push(l); + drawableMutex.unlock(); +} + /*!\brief Procedurally draws a Line to the Background. * \details Initializes a new Line based on the parameter values, and then adds it to the Array of Drawables to be rendered. * \param x The x coordinate of the Line's center location. diff --git a/src/TSGL/Background.h b/src/TSGL/Background.h index ebc5a6de0..b1eeb4a46 100644 --- a/src/TSGL/Background.h +++ b/src/TSGL/Background.h @@ -98,6 +98,10 @@ class Background { virtual void drawImage(float x, float y, float z, std::string filename, float width, float height, float yaw, float pitch, float roll, float alpha = 1.0f); + virtual void drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color); + + virtual void drawLine(float x1, float y1, float z1, float x2, float y2, float z2, float yaw, float pitch, float roll, ColorFloat color[]); + virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color); virtual void drawLine(float x, float y, float z, float length, float yaw, float pitch, float roll, ColorFloat color[]); diff --git a/src/TSGL/Line.cpp b/src/TSGL/Line.cpp index f6a166442..a63cc7090 100644 --- a/src/TSGL/Line.cpp +++ b/src/TSGL/Line.cpp @@ -20,11 +20,16 @@ Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, fl if (length <= 0) TsglDebug("Cannot have a line with length less than or equal to 0."); attribMutex.lock(); - myXScale = length; - myLength = length; + myLength = length; + endpointX1 = -length/2 + x; + endpointY1 = y; + endpointZ1 = z; + endpointX2 = -length/2 + x; + endpointY2 = y; + endpointZ2 = z; attribMutex.unlock(); - addVertex(-0.5, 0, 0, color); - addVertex(0.5, 0, 0, color); + addVertex(-length/2, 0, 0, color); + addVertex(length/2, 0, 0, color); } /*! @@ -45,16 +50,153 @@ Line::Line(float x, float y, float z, GLfloat length, float yaw, float pitch, fl if (length <= 0) TsglDebug("Cannot have a line with length less than or equal to 0."); attribMutex.lock(); - myXScale = length; - myLength = length; + myLength = length; + endpointX1 = -length/2 + x; + endpointY1 = y; + endpointZ1 = z; + endpointX2 = -length/2 + x; + endpointY2 = y; + endpointZ2 = z; + attribMutex.unlock(); + addVertex(-length/2, 0, 0, color[0]); + addVertex(length/2, 0, 0, color[1]); +} + +/*! + * \brief Explicitly constructs a new Line. + * \details This is the constructor for the Line class. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the color of the Line. + * \return A new Line with the specified length and color. + */ +Line::Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color) : Polyline((x2 + x1) / 2, (y2 + y1) / 2, (z2 + z1) / 2, 2, yaw, pitch, roll) { + attribMutex.lock(); + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + endpointX1 = x1; + endpointY1 = y1; + endpointZ1 = z1; + endpointX2 = x2; + endpointY2 = y2; + endpointZ2 = z2; + attribMutex.unlock(); + addVertex(x1 - myCenterX, y1 - myCenterY, z1 - myCenterZ, color); + addVertex(x2 - myCenterX, y2 - myCenterY, z2 - myCenterZ, color); +} + +/*! + * \brief Explicitly constructs a new Line. + * \details This is the constructor for the Line class. + * \param x1 The x coordinate of the first endpoint of the line. + * \param y1 The y coordinate of the first endpoint of the line. + * \param z1 The z coordinate of the first endpoint of the line. + * \param x2 The x coordinate of the second endpoint of the line. + * \param y2 The y coordinate of the second endpoint of the line. + * \param z2 The z coordinate of the second endpoint of the line. + * \param yaw The yaw of the line. + * \param pitch The pitch of the line. + * \param roll The roll of the line. + * \param color The reference variable to the colors of the Line. + * \return A new Line with the specified length and color. + */ +Line::Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color[]) : Polyline((x2 + x1) / 2, (y2 + y1) / 2, (z2 + z1) / 2, 2, yaw, pitch, roll) { + attribMutex.lock(); + myLength = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2) + pow(z2 - z1, 2)); + endpointX1 = x1; + endpointY1 = y1; + endpointZ1 = z1; + endpointX2 = x2; + endpointY2 = y2; + endpointZ2 = z2; + attribMutex.unlock(); + addVertex(x1 - myCenterX, y1 - myCenterY, z1 - myCenterZ, color[0]); + addVertex(x2 - myCenterX, y2 - myCenterY, z2 - myCenterZ, color[1]); +} + +/** + * \brief Moves the line's first endpoint to the parameter coordinates. + * \param x The Line's first endpoint's new x-coordinate. + * \param y The Line's first endpoint's new y-coordinate. + * \param z The Line's first endpoint's new z-coordinate. + * \warning Upon altering an endpoint, center coordinates will be altered accordingly, + * yaw, pitch, and roll will be reset to 0, + * and rotation point coordinates will be adjusted if they previously matched the center of the line. + */ +void Line::setFirstEndpoint(float x, float y, float z) { + attribMutex.lock(); + endpointX1 = x; endpointY1 = y; endpointZ1 = z; + myLength = sqrt(pow(endpointX2 - endpointX1, 2) + pow(endpointY2 - endpointY1, 2) + pow(endpointZ2 - endpointZ1, 2)); + if (centerMatchesRotationPoint()) { + myRotationPointX = (endpointX2 + endpointX1) / 2; + myRotationPointY = (endpointY2 + endpointY1) / 2; + myRotationPointZ = (endpointZ2 + endpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (endpointX2 + endpointX1) / 2; + myCenterY = (endpointY2 + endpointY1) / 2; + myCenterZ = (endpointZ2 + endpointZ1) / 2; + } + myCurrentYaw = 0; + myCurrentPitch = 0; + myCurrentRoll = 0; + vertices[0] = endpointX1 - myCenterX; + vertices[1] = endpointY1 - myCenterY; + vertices[2] = endpointZ1 - myCenterZ; + vertices[7] = endpointX2 - myCenterX; + vertices[8] = endpointY2 - myCenterY; + vertices[9] = endpointZ2 - myCenterZ; + attribMutex.unlock(); +} + +/** + * \brief Moves the line's second endpoint to the parameter coordinates. + * \param x The Line's second endpoint's new x-coordinate. + * \param y The Line's second endpoint's new y-coordinate. + * \param z The Line's second endpoint's new z-coordinate. + * \warning Upon altering an endpoint, center coordinates will be altered accordingly, + * yaw, pitch, and roll will be reset to 0, + * and rotation point coordinates will be adjusted if they previously matched the center of the line. + */ +void Line::setSecondEndpoint(float x, float y, float z) { + attribMutex.lock(); + endpointX2 = x; endpointY2 = y; endpointZ2 = z; + myLength = sqrt(pow(endpointX2 - endpointX1, 2) + pow(endpointY2 - endpointY1, 2) + pow(endpointZ2 - endpointZ1, 2)); + if (centerMatchesRotationPoint()) { + myRotationPointX = (endpointX2 + endpointX1) / 2; + myRotationPointY = (endpointY2 + endpointY1) / 2; + myRotationPointZ = (endpointZ2 + endpointZ1) / 2; + myCenterX = myRotationPointX; + myCenterY = myRotationPointY; + myCenterZ = myRotationPointZ; + } else { + myCenterX = (endpointX2 + endpointX1) / 2; + myCenterY = (endpointY2 + endpointY1) / 2; + myCenterZ = (endpointZ2 + endpointZ1) / 2; + } + myCurrentYaw = 0; + myCurrentPitch = 0; + myCurrentRoll = 0; + vertices[0] = endpointX1 - myCenterX; + vertices[1] = endpointY1 - myCenterY; + vertices[2] = endpointZ1 - myCenterZ; + vertices[7] = endpointX2 - myCenterX; + vertices[8] = endpointY2 - myCenterY; + vertices[9] = endpointZ2 - myCenterZ; attribMutex.unlock(); - addVertex(-0.5, 0, 0, color[0]); - addVertex(0.5, 0, 0, color[1]); } /** * \brief Mutates the line's length to the new parameter value. - * \param length The Prism's new length. + * \param length The Line's new length. */ void Line::setLength(GLfloat length) { if (length <= 0) { @@ -62,8 +204,14 @@ void Line::setLength(GLfloat length) { return; } attribMutex.lock(); - myXScale = length; + float ratio = length / myLength; myLength = length; + vertices[0] *= ratio; + vertices[1] *= ratio; + vertices[2] *= ratio; + vertices[7] *= ratio; + vertices[8] *= ratio; + vertices[9] *= ratio; attribMutex.unlock(); } @@ -74,11 +222,18 @@ void Line::setLength(GLfloat length) { void Line::changeLengthBy(GLfloat delta) { if (myLength + delta <= 0) { TsglDebug("Cannot have a Line with length less than or equal to 0."); + printf("failure\n"); return; } attribMutex.lock(); - myXScale += delta; + float ratio = (myLength + delta) / myLength; myLength += delta; + vertices[0] *= ratio; + vertices[1] *= ratio; + vertices[2] *= ratio; + vertices[7] *= ratio; + vertices[8] *= ratio; + vertices[9] *= ratio; attribMutex.unlock(); } diff --git a/src/TSGL/Line.h b/src/TSGL/Line.h index b94cc3912..fe304fc85 100755 --- a/src/TSGL/Line.h +++ b/src/TSGL/Line.h @@ -16,11 +16,20 @@ namespace tsgl { class Line : public Polyline { private: GLfloat myLength; + GLfloat endpointX1, endpointY1, endpointZ1, endpointX2, endpointY2, endpointZ2; public: Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color); Line(float x, float y, float z, GLfloat length, float yaw, float pitch, float roll, ColorFloat color[]); + Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color); + + Line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2, float yaw, float pitch, float roll, ColorFloat color[]); + + void setFirstEndpoint(float x, float y, float z); + + void setSecondEndpoint(float x, float y, float z); + void setLength(GLfloat length); void changeLengthBy(GLfloat delta); @@ -31,6 +40,48 @@ class Line : public Polyline { * \return Length of the Line. */ GLfloat getLength() { return myLength; } + + /** + * \brief Returns the x-coordinate of the line's first endpoint. + * \details Returns the value of the endpointX1 instance variable. + * \return x-coordinate of the Line's first endpoint. + */ + GLfloat getFirstEndpointX() { return endpointX1; } + + /** + * \brief Returns the y-coordinate of the line's first endpoint. + * \details Returns the value of the endpointY1 instance variable. + * \return y-coordinate of the Line's first endpoint. + */ + GLfloat getFirstEndpointY() { return endpointY1; } + + /** + * \brief Returns the z-coordinate of the line's first endpoint. + * \details Returns the value of the endpointZ1 instance variable. + * \return z-coordinate of the Line's first endpoint. + */ + GLfloat getFirstEndpointZ() { return endpointZ1; } + + /** + * \brief Returns the x-coordinate of the line's second endpoint. + * \details Returns the value of the endpointX2 instance variable. + * \return x-coordinate of the Line's second endpoint. + */ + GLfloat getSecondEndpointX() { return endpointX2; } + + /** + * \brief Returns the y-coordinate of the line's second endpoint. + * \details Returns the value of the endpointY2 instance variable. + * \return y-coordinate of the Line's second endpoint. + */ + GLfloat getSecondEndpointY() { return endpointY2; } + + /** + * \brief Returns the z-coordinate of the line's second endpoint. + * \details Returns the value of the endpointZ2 instance variable. + * \return z-coordinate of the Line's second endpoint. + */ + GLfloat getSecondEndpointZ() { return endpointZ2; } }; } diff --git a/src/tests/Makefile b/src/tests/Makefile index e46074f75..6b58c3fd2 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -27,6 +27,8 @@ SUBDIRS_TO_BUILD := test2Dvs3D \ testHighData \ testImage \ testInverter \ + testLineChain \ + testLineFan \ testLines \ testPixels \ testPrism \ @@ -48,8 +50,6 @@ SUBDIRS_TO_BUILD := test2Dvs3D \ # testDice \ # testFunction \ # testImageCart \ -# testLineChain \ -# testLineFan \ # testMouse \ # testProgressBar \ # testProjectiles \ diff --git a/src/tests/testLineChain/testLineChain.cpp b/src/tests/testLineChain/testLineChain.cpp index 8a2b390ad..e9dd210a2 100644 --- a/src/tests/testLineChain/testLineChain.cpp +++ b/src/tests/testLineChain/testLineChain.cpp @@ -39,6 +39,7 @@ using namespace tsgl; * \param t The number of threads to use in the function. */ void lineChainFunction(Canvas& can, int t) { + Background * bg = can.getBackground(); const int IPF = 3; const int CWW = can.getWindowWidth() / 2, CWH = can.getWindowHeight() / 2; const float ARC = 2.3f, SPIN = 0.01f; @@ -47,7 +48,7 @@ void lineChainFunction(Canvas& can, int t) { const float NTHREADS = omp_get_num_threads(); const float FADERATE = (NTHREADS < 200) ? 1.0f*NTHREADS/200 : 1; const int TID = omp_get_thread_num(); - int xOld, yOld, xNew = CWW*2, yNew = CWH; + int xOld, yOld, xNew = CWW, yNew = 0; float next = (ARC*TID)/NTHREADS, s = next; ColorFloat c = Colors::highContrastColor(TID); while (can.isOpen()) { // Checks to see if the window has been closed @@ -56,12 +57,12 @@ void lineChainFunction(Canvas& can, int t) { next += ARC; s += SPIN; xOld = xNew; yOld = yNew; float size = cos(s); - xNew = CWW + CWW*size*cos(next); - yNew = CWH + CWH*size*sin(next); - can.drawLine(xOld, yOld, xNew, yNew, c); + xNew = CWW*size*cos(next); + yNew = CWH*size*sin(next); + bg->drawLine(xOld, yOld, 0, xNew, yNew, 0, 0,0,0, c); } if (TID == 0) - can.drawRectangle(0,0,CWW*2,CWH*2,ColorFloat(0,0,0,FADERATE)); + bg->drawRectangle(0,0,0,CWW*2,CWH*2,0,0,0,ColorFloat(0,0,0,FADERATE)); #pragma omp barrier } } diff --git a/src/tests/testLineFan/testLineFan.cpp b/src/tests/testLineFan/testLineFan.cpp index 74aaf0d4a..54db48d3c 100644 --- a/src/tests/testLineFan/testLineFan.cpp +++ b/src/tests/testLineFan/testLineFan.cpp @@ -29,14 +29,15 @@ using namespace tsgl; * \param t The number of threads to use in the function. */ void lineFanFunction(Canvas& can, int t) { + Background * bg = can.getBackground(); const double ARC = 7.11; //(Arbitrary) spacing between arcs of the fan while (can.isOpen()) { #pragma omp parallel num_threads(t) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class int a, b, c, d, red, green, blue; - double angle, offset = omp_get_thread_num() * ARC; - angle = offset + can.getReps() * RAD; + double angle, offset = omp_get_thread_num() * ARC * 180 / PI; + angle = offset + can.getReps(); a = can.getWindowWidth() / 2 * (1 + sin(angle)); b = can.getWindowHeight() / 2 * (1 + cos(angle)); c = can.getWindowWidth() / 2 * (1 - sin(angle)); @@ -44,7 +45,7 @@ void lineFanFunction(Canvas& can, int t) { red = (a + can.getReps()) % NUM_COLORS; green = (b + can.getReps()) % NUM_COLORS; blue = (a * b + can.getReps()) % NUM_COLORS; - can.drawLine(a, b, c, d, ColorInt(red, green, blue)); + bg->drawLine(0, 0, 0, can.getWindowHeight() * 0.9, angle, 0,0, ColorInt(red, green, blue)); } } } diff --git a/src/tests/testLines/testLines.cpp b/src/tests/testLines/testLines.cpp index 625f32b79..19d8d0f65 100644 --- a/src/tests/testLines/testLines.cpp +++ b/src/tests/testLines/testLines.cpp @@ -24,15 +24,22 @@ void lineFunction(Canvas& c) { Polyline * p = new Polyline(0,0,0,7,vertices,0,0,0,colors); + Line * l2 = new Line(-250, -250, -100, -150, 200, 100, 0,0,0, colors); // printf("Line: %f\n", l->getAlpha()); // printf("Pline: %f\n", p->getAlpha()); + c.bindToButton(TSGL_SPACE, TSGL_PRESS, [&l2] () { + // l2->setFirstEndpoint(-250, -250, -100); + printf("%f\n", l2->getLength()); + }); + // p->setColor(BLUE); - p->setColor(colors); + // p->setColor(colors); c.add(l); c.add(p); + c.add(l2); float floatVal = 0.0f; - GLfloat delta = 0.05; + GLfloat delta = 5; while( c.isOpen() ) { c.sleep(); // l->setCenterX(sin(floatVal/90)); @@ -41,8 +48,8 @@ void lineFunction(Canvas& c) { // l->setYaw(floatVal); // l->setPitch(floatVal); // l->setRoll(floatVal); - // l->setLength(sin(floatVal/90) + 2); - // if (l->getLength() > 3 || l->getLength() < 1) { + // l->setLength(100 * sin(floatVal/90) + 200); + // if (l->getLength() > 300 || l->getLength() < 100) { // delta *= -1; // } // l->changeLengthBy(delta); @@ -51,17 +58,26 @@ void lineFunction(Canvas& c) { // p->setCenterZ(sin(floatVal/90)); // p->setYaw(floatVal); // p->setPitch(floatVal); - p->setRoll(floatVal); + // p->setRoll(floatVal); + // l2->setFirstEndpoint(-250,-250 * cos((float) c.getFrameNumber()/180),-100); + // l2->setSecondEndpoint(-150,200 * cos((float) c.getFrameNumber()/180),100); + // l2->setLength(350 + 150 * cos(floatVal/90)); + // if (l2->getLength() > 500 || l2->getLength() < 300) { + // delta *= -1; + // } + // l2->changeLengthBy(delta); + // printf("%f, %f, %f - %f, %f, %f\n",l2->getFirstEndpointX(),l2->getFirstEndpointY(),l2->getFirstEndpointZ(),l2->getSecondEndpointX(),l2->getSecondEndpointY(),l2->getSecondEndpointZ()); floatVal += 1; } delete l; delete p; + delete l2; } int main(int argc, char* argv[]) { int w = 1000; - int h = 1000; + int h = 600; Canvas c(-1, -1, w, h, "Lines"); c.run(lineFunction); } \ No newline at end of file From ea2f332266f84f4fb0714dee0fbd82a42459d93b Mon Sep 17 00:00:00 2001 From: mrsillydog Date: Thu, 6 Aug 2020 17:47:03 -0400 Subject: [PATCH 085/105] Test fixes, including Spectrogram + ProgressBar --- src/TSGL/Canvas.h | 2 +- src/TSGL/ProgressBar.cpp | 171 +++++---- src/TSGL/ProgressBar.h | 121 +++--- src/TSGL/Spectrogram.cpp | 354 +++++++++--------- src/TSGL/Spectrogram.h | 85 ++--- src/examples/ArrayBubbleSort/Makefile | 7 +- src/examples/ArrayShakerSort/Makefile | 7 +- src/examples/Ballroom/Makefile | 7 +- src/examples/Clock/Makefile | 7 +- src/examples/Conway/Makefile | 7 +- src/examples/CubeRun/Makefile | 7 +- src/examples/DiningPhilosophers/Makefile | 7 +- src/examples/DiningPhilosophers3D/Makefile | 7 +- src/examples/Fireworks/Makefile | 7 +- src/examples/ForestFire/Makefile | 7 +- src/examples/Langton/AntFarm.cpp | 11 +- src/examples/Langton/LangtonAnt.cpp | 8 +- src/examples/Langton/Makefile | 7 +- src/examples/Langton/testLangton.cpp | 34 +- src/examples/Makefile | 2 +- src/examples/Mandelbrot/Makefile | 7 +- src/examples/MergeSort/Makefile | 7 +- src/examples/NewtonPendulum/Makefile | 7 +- src/examples/Pandemic/Makefile | 7 +- src/examples/ParallelPandemic/Makefile | 7 +- src/examples/ParallelPandemic/obj/Person.o | Bin 318592 -> 742996 bytes src/examples/Pong/Makefile | 7 +- src/examples/ProducerConsumer/Makefile | 7 +- src/examples/ReaderWriter/Makefile | 7 +- src/examples/SeaUrchin/Makefile | 7 +- src/examples/ShakerSort/Makefile | 7 +- src/examples/SolarSystem/Makefile | 7 +- src/examples/ThreadedArrayAddition/Makefile | 7 +- src/examples/ThreadedArrayBubbleSort/Makefile | 7 +- src/examples/ThreadedArrayOperations/Makefile | 7 +- src/examples/ThreadedSolarSystem/Makefile | 7 +- src/examples/Voronoi/Makefile | 7 +- src/tests/Makefile | 16 +- src/tests/test2Dvs3D/Makefile | 7 +- src/tests/test3DRotation/Makefile | 7 +- src/tests/testAlphaRectangle/Makefile | 7 +- src/tests/testArrows/Makefile | 7 +- src/tests/testAura/Makefile | 7 +- src/tests/testBackground/Makefile | 7 +- src/tests/testBlurImage/Makefile | 7 +- src/tests/testBlurImage/testBlurImage.cpp | 26 +- src/tests/testCalcPi/Makefile | 7 +- src/tests/testCircle/Makefile | 7 +- src/tests/testColorWheel/Makefile | 7 +- src/tests/testConcavePolygon/Makefile | 7 +- src/tests/testCone/Makefile | 7 +- src/tests/testConvexPolygon/Makefile | 7 +- src/tests/testCosineIntegral/Makefile | 7 +- src/tests/testCube/Makefile | 7 +- src/tests/testCuboid/Makefile | 7 +- src/tests/testCylinder/Makefile | 7 +- src/tests/testDice/Makefile | 7 +- src/tests/testDiorama/Makefile | 7 +- src/tests/testEllipse/Makefile | 7 +- src/tests/testEllipsoid/Makefile | 7 +- src/tests/testFunction/Makefile | 7 +- src/tests/testGetPixels/Makefile | 7 +- src/tests/testGradientWheel/Makefile | 7 +- src/tests/testGraydient/Makefile | 7 +- src/tests/testGreyscale/Makefile | 7 +- src/tests/testHighData/Makefile | 7 +- src/tests/testImage/Makefile | 7 +- src/tests/testImageCart/Makefile | 7 +- src/tests/testInverter/Makefile | 7 +- src/tests/testLineChain/Makefile | 7 +- src/tests/testLineFan/Makefile | 7 +- src/tests/testLines/Makefile | 7 +- src/tests/testMouse/Makefile | 7 +- src/tests/testMouse/testMouse.cpp | 26 +- src/tests/testPixels/Makefile | 7 +- src/tests/testPrism/Makefile | 7 +- src/tests/testProcedural/Makefile | 7 +- src/tests/testProgressBar/Makefile | 7 +- src/tests/testProgressBar/testProgressBar.cpp | 16 +- src/tests/testProjectiles/Makefile | 7 +- src/tests/testProjectiles/testProjectiles.cpp | 29 +- src/tests/testPyramid/Makefile | 7 +- src/tests/testRectangle/Makefile | 7 +- src/tests/testRegularPolygon/Makefile | 7 +- src/tests/testScreenshot/Makefile | 7 +- src/tests/testScreenshot/testScreenshot.cpp | 7 +- src/tests/testSpectrogram/Makefile | 7 +- src/tests/testSpectrogram/testSpectrogram.cpp | 18 +- src/tests/testSpectrum/Makefile | 7 +- src/tests/testSpectrum/testSpectrum.cpp | 9 +- src/tests/testSphere/Makefile | 7 +- src/tests/testSquare/Makefile | 7 +- src/tests/testStar/Makefile | 7 +- src/tests/testText/Makefile | 7 +- src/tests/testTextCart/Makefile | 7 +- src/tests/testTextTwo/Makefile | 7 +- src/tests/testTextTwo/testTextTwo.cpp | 20 +- src/tests/testTransparency/Makefile | 7 +- src/tests/testTriangle/Makefile | 7 +- src/tests/testTriangleStrip/Makefile | 7 +- src/tests/testUnits/Makefile | 7 +- 101 files changed, 824 insertions(+), 705 deletions(-) diff --git a/src/TSGL/Canvas.h b/src/TSGL/Canvas.h index ee5edf6f1..13e5789f4 100644 --- a/src/TSGL/Canvas.h +++ b/src/TSGL/Canvas.h @@ -27,7 +27,7 @@ #include "Keynums.h" // Our enums for key presses #include "Line.h" // Our own class for drawing straight lines #include "Polyline.h" // Our own class for drawing polylines -// #include "ProgressBar.h" // Our own class for drawing progress bars +#include "ProgressBar.h" // Our own class for drawing progress bars #include "Pyramid.h" // Our own class for drawing pyramids #include "Rectangle.h" // Our own class for drawing rectangles #include "RegularPolygon.h" // Our own class for drawing regular polygons diff --git a/src/TSGL/ProgressBar.cpp b/src/TSGL/ProgressBar.cpp index aa6e4ddd1..5366a85c5 100644 --- a/src/TSGL/ProgressBar.cpp +++ b/src/TSGL/ProgressBar.cpp @@ -1,87 +1,98 @@ -// #include "ProgressBar.h" +#include "ProgressBar.h" -// namespace tsgl { +namespace tsgl { -// /*! -// * \brief Explicit ProgressBar constructor method. -// * \details This is the explicit constructor for the ProgressBar class. -// * \param x The x position of the left edge of the ProgressBar. -// * \param y The y position of the top edge of the ProgressBar. -// * \param width The maximum width in pixels of the ProgressBar. -// * \param height The maximum height in pixels of the ProgressBar. -// * \param minValue The minimum value represented by the ProgressBar. -// * \param maxValue The maximum value represented by the ProgressBar. -// * \param numSegments The number of segments in the progress bar -// * \return A new ProgressBar with the specified coordinates, maximum dimensions, value range, and segments. -// */ -// ProgressBar::ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments) { -// startX = new float[numSegments]; -// endX = new float[numSegments]; -// min = minValue; max = maxValue; -// xx = x; yy = y; -// myWidth = width; myHeight = height; -// segs = numSegments; -// startX[0] = x; endX[0] = x + myWidth/segs; -// for (int i = 1; i < segs; ++i) { -// startX[i] = endX[i-1]; -// endX[i] = startX[i] + myWidth/segs; -// } -// } + /*! + * \brief Explicit ProgressBar constructor method. + * \details This is the explicit constructor for the ProgressBar class. + * \param x The x position of the left edge of the ProgressBar. + * \param y The y position of the top edge of the ProgressBar. + * \param width The maximum width in pixels of the ProgressBar. + * \param height The maximum height in pixels of the ProgressBar. + * \param minValue The minimum value represented by the ProgressBar. + * \param maxValue The maximum value represented by the ProgressBar. + * \param numSegments The number of segments in the progress bar + * \return A new ProgressBar with the specified coordinates, maximum dimensions, value range, and segments. + */ +ProgressBar::ProgressBar(float x, float y, float z, float width, float height, float minValue, float maxValue, unsigned numSegments, float yaw, float pitch, float roll) +: Drawable(x, y, z, yaw, pitch, roll) { + shaderType = SHAPE_SHADER_TYPE; + segRecs = new Rectangle*[numSegments]; + segBorders = new Polyline*[numSegments]; + startX = new float[numSegments]; + endX = new float[numSegments]; + min = minValue; max = maxValue; + myWidth = width; myHeight = height; + segs = numSegments; + startX[0] = -myWidth / 2; endX[0] = startX[0] + myWidth/segs; + for (int i = 1; i < segs; ++i) { + startX[i] = endX[i-1]; + endX[i] = startX[i] + myWidth/segs; + } -// /*! -// * \brief ProgressBar destructor method. -// * \details This is the destructor for the ProgressBar class. -// * \details Frees up memory that was allocated to a ProgressBar instance. -// */ -// ProgressBar::~ProgressBar() { -// delete [] startX; delete [] endX; -// } + // all Polylines can have the same vertices; different locations will be handled with draw() + float vertices[15] = { -(myWidth/segs)/2,myHeight/2,0, + -(myWidth/segs)/2,-myHeight/2,0, + (myWidth/segs)/2,-myHeight/2,0, + (myWidth/segs)/2,myHeight/2,0, + -(myWidth/segs)/2,myHeight/2,0 }; + for (int i = 0; i < segs; i++) { + segBorders[i] = new Polyline(0,0,0,5,vertices,yaw,pitch,roll,BLACK); + segRecs[i] = new Rectangle(0,0,0,myWidth/segs,myHeight-2,yaw,pitch,roll,Colors::highContrastColor(i)); + segRecs[i]->setIsOutlined(false); + } -// /*! -// * \brief Updates a ProgressBar segment with a new value. -// * \details This function updates the segment seg of the ProgressBar to represent -// * the new value newV. If newV is less than the segment's minimum value, the segment -// * is set to its minimum value. If newV is more than the segment's maximum value, the segment -// * is set to its maximum value. -// * \param newValue The value to set the segment to. -// * \param segnum The segment whose value to update. A value of -1 indicates the current thread number. -// * \note The minimum value for a segment is calculated as minV + (maxV-minV)*seg/segs -// * \note The maximum value for a segment is calculated as minV + (maxV-minV)*(seg+1)/segs -// */ -// void ProgressBar::update(float newValue, int segnum) { -// if (segnum == -1) -// segnum = omp_get_thread_num(); -// float d = max-min; -// float start = min + (d * segnum)/segs; -// float end = start + d/segs; -// clamp(newValue,start,end); -// float percent = (newValue-start) / (end-start); -// endX[segnum] = startX[segnum]+percent*(myWidth/segs); -// } + init = true; +} -// /*! -// * \brief Accessor for the ProgressBar's representative Polyline array. -// * \param index Index of the segment to access. -// * \return A pointer to the Polyline array representing segment border i of the ProgressBar. -// */ -// Polyline* ProgressBar::getBorder(int index) { -// int y2 = yy+myHeight; -// Polyline* p = new Polyline(5); -// p->addVertex(startX[index],yy,BLACK); -// p->addVertex(startX[index]+myWidth/segs,yy,BLACK); -// p->addVertex(startX[index]+myWidth/segs,y2,BLACK); -// p->addVertex(startX[index],y2,BLACK); -// p->addVertex(startX[index],yy,BLACK); -// return p; -// } + /*! + * \brief ProgressBar destructor method. + * \details This is the destructor for the ProgressBar class. + * \details Frees up memory that was allocated to a ProgressBar instance. + */ +ProgressBar::~ProgressBar() { + delete [] startX; delete [] endX; + for (int i = 0; i < segs; i++) { + delete segBorders[i]; + delete segRecs[i]; + } + delete [] segBorders; delete [] segRecs; +} -// /*! -// * \brief Accessor for the ProgressBar's representative Rectangle array. -// * \param index Index of the segment to access. -// * \return A pointer to the Rectangle array representing segment i of the ProgressBar. -// */ -// Rectangle* ProgressBar::getRect(int index) { -// return new Rectangle(startX[index], yy, endX[index]-startX[index], myHeight, Colors::highContrastColor(index)); -// } +void ProgressBar::draw(Shader * shader) { + for (int i = 0; i < segs; i++) { + segBorders[i]->setCenter(myCenterX + (myWidth/segs) * ( (float)i - (float)(segs-1)/2), myCenterY, myCenterZ); + segRecs[i]->setCenter(myCenterX + (myWidth/segs) * ( (float)i - (float)(segs)/2) + segRecs[i]->getWidth()/2, myCenterY, myCenterZ); + segBorders[i]->setRotationPoint(myCenterX, myCenterY, myCenterZ); + segRecs[i]->setRotationPoint(myCenterX, myCenterY, myCenterZ); + segBorders[i]->setYawPitchRoll(myCurrentYaw, myCurrentPitch, myCurrentRoll); + segRecs[i]->setYawPitchRoll(myCurrentYaw, myCurrentPitch, myCurrentRoll); + segRecs[i]->draw(shader); + segBorders[i]->draw(shader); + } +} -// } + /*! + * \brief Updates a ProgressBar segment with a new value. + * \details This function updates the segment seg of the ProgressBar to represent + * the new value newV. If newV is less than the segment's minimum value, the segment + * is set to its minimum value. If newV is more than the segment's maximum value, the segment + * is set to its maximum value. + * \param newValue The value to set the segment to. + * \param segnum The segment whose value to update. A value of -1 indicates the current thread number. + * \note The minimum value for a segment is calculated as minV + (maxV-minV)*seg/segs + * \note The maximum value for a segment is calculated as minV + (maxV-minV)*(seg+1)/segs + */ +void ProgressBar::update(float newValue, int segnum) { + if (segnum == -1) + segnum = omp_get_thread_num(); + float d = max-min; + float start = min + (d * segnum)/segs; + float end = start + d/segs; + clamp(newValue,start,end); + float percent = (newValue-start) / (end-start); + segRecs[segnum]->setWidth(percent*(myWidth/segs)); +} + + +} diff --git a/src/TSGL/ProgressBar.h b/src/TSGL/ProgressBar.h index 936bf89e0..1a2f7eb80 100755 --- a/src/TSGL/ProgressBar.h +++ b/src/TSGL/ProgressBar.h @@ -1,60 +1,61 @@ -// /* -// * ProgressBar.h extends Shape and provides a class for drawing a progress bar to a Canvas. -// */ - -// #ifndef PROGRESSBAR_H -// #define PROGRESSBAR_H - -// #include - -// #include "Polyline.h" -// #include "Rectangle.h" - -// namespace tsgl { - -// /*! \class ProgressBar -// * \brief Draws and updates a progress bar. -// * \details ProgressBar is a class for holding vertex data for multiple rectangles forming a progress bar. -// * ProgressBar is formed of multiple segments, each of which is thread-safe and updated individually -// * with the update() method. A ProgressBar can be drawn to the screen using Canvas::drawProgress(). -// */ -// class ProgressBar { -// private: -// float *startX, *endX; -// float min, max; -// int xx, yy, myWidth, myHeight, segs; -// public: - -// ProgressBar(int x, int y, int width, int height, float minValue, float maxValue, unsigned numSegments); - -// ~ProgressBar(); - -// void update(float newValue, int segnum = -1); - -// Polyline* getBorder(int index); - -// Rectangle* getRect(int index); - -// /*! -// * \brief Accessor for the ProgressBar's number of segments -// * \return The number of segments in the ProgressBar. -// */ -// int getSegs() { return segs; } - -// /*! -// * \brief Accessor for a segment's x position -// * \param i Index of the segment -// * \return The x-coordinate of the left edge of segment i in the ProgressBar. -// */ -// int getSegX(int i) { return startX[i]; } - -// /*! -// * \brief Accessor for a segment's y position -// * \return The y-coordinate of the top edge of the ProgressBar. -// */ -// int getSegY() { return yy; } -// }; - -// } - -// #endif /* PROGRESSBAR_H */ +/* + * ProgressBar.h extends Shape and provides a class for drawing a progress bar to a Canvas. + */ + +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +#include + +#include "Polyline.h" +#include "Rectangle.h" +#include "Drawable.h" + +namespace tsgl { + +/*! \class ProgressBar + * \brief Draws and updates a progress bar. + * \details ProgressBar is a class for holding vertex data for multiple rectangles forming a progress bar. + * ProgressBar is formed of multiple segments, each of which is thread-safe and updated individually + * with the update() method. A ProgressBar can be drawn to the screen using Canvas::drawProgress(). + */ +class ProgressBar : public Drawable { + private: + Rectangle ** segRecs; + Polyline ** segBorders; + float *startX, *endX; + float min, max; + float myWidth, myHeight; + int segs; + public: + + ProgressBar(float x, float y, float z, float width, float height, float minValue, float maxValue, unsigned numSegments, float yaw, float pitch, float roll); + + ~ProgressBar(); + + void draw(Shader * shader); + + void update(float newValue, int segnum = -1); + + /*! + * \brief Accessor for the ProgressBar's number of segments + * \return The number of segments in the ProgressBar. + */ + int getSegs() { return segs; } + + /*! + * \brief Accessor for the ProgressBar's width in pixels + * \return The pixel width of the ProgressBar. + */ + float getWidth() { return myWidth; } + + /*! + * \brief Accessor for the ProgressBar's height in pixels + * \return The pixel height of the ProgressBar. + */ + float getHeight() { return myHeight; } +}; + +} + +#endif /* PROGRESSBAR_H */ diff --git a/src/TSGL/Spectrogram.cpp b/src/TSGL/Spectrogram.cpp index a0b85ecef..04cd9400d 100644 --- a/src/TSGL/Spectrogram.cpp +++ b/src/TSGL/Spectrogram.cpp @@ -1,183 +1,191 @@ -// #include "Spectrogram.h" +#include "Spectrogram.h" -// namespace tsgl { +namespace tsgl { -// const int Spectrogram::B = 16; -// const float Spectrogram::PI = 3.149f; +const int Spectrogram::B = 16; +const float Spectrogram::PI = 3.149f; -// /*! -// * \brief Explicit Spectrogram constructor method. -// * \details This is the explicit constructor for the Spectrogram class. -// * \param drawMode Method used for displaying spectral data. Can be one of CIRCULAR -// * or HORIZONTAL. -// * \param width The width of the Spectrogram canvas. -// * \param height The height of the Spectrogram canvas. This value is ignored for -// * HORIZONTAL Spectrograms. Setting this to -1 sets the width automatically. -// * \return A new Spectrogram with the specified drawing mode and size. -// */ -// Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { -// for (int i = 0; i < NUM_COLORS; ++i) -// omp_init_lock(&(writelock[i])); -// omp_init_lock(&masterlock); -// myWidth = width; -// myHeight = (height > 0) ? height : width; -// myDrawMode = drawMode; -// if (myDrawMode == HORIZONTAL) -// myHeight = NUM_COLORS; -// else if (myDrawMode == VERTICAL) -// myWidth = NUM_COLORS; + /*! + * \brief Explicit Spectrogram constructor method. + * \details This is the explicit constructor for the Spectrogram class. + * \param drawMode Method used for displaying spectral data. Can be one of CIRCULAR + * or HORIZONTAL. + * \param width The width of the Spectrogram canvas. + * \param height The height of the Spectrogram canvas. This value is ignored for + * HORIZONTAL Spectrograms. Setting this to -1 sets the width automatically. + * \return A new Spectrogram with the specified drawing mode and size. + */ +Spectrogram::Spectrogram(SpectrogramDrawmode drawMode, int width, int height) { + for (int i = 0; i < NUM_COLORS; ++i) { + omp_init_lock(&(writelock[i])); + } + omp_init_lock(&masterlock); + myWidth = width; + myHeight = (height > 0) ? height : width; + myDrawMode = drawMode; + if (myDrawMode == HORIZONTAL) + myHeight = NUM_COLORS; + else if (myDrawMode == VERTICAL) + myWidth = NUM_COLORS; -// can = new Canvas(-1, 0, myWidth, myHeight ,""); -// maxCount = 0; -// count[0] = 0; -// xx[0] = (myWidth)/2; -// yy[0] = (myHeight)/2; -// col[0] = WHITE; -// black[0] = BLACK; -// for (unsigned i = 1; i < NUM_COLORS; ++i) { -// count[i] = 0; -// xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2; -// yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2; -// col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); -// black[i] = col[i] * 0.25f; -// } -// count[NUM_COLORS] = 0; -// xx[NUM_COLORS] = xx[1]; -// yy[NUM_COLORS] = yy[1]; -// col[NUM_COLORS] = col[1]; -// black[NUM_COLORS] = black[1]; -// for (int k = 0; k < NUM_COLORS+1; ++k) { -// maxx[k] = xx[k]; -// maxy[k] = yy[k]; -// } -// can->start(); -// } + can = new Canvas(-1, 0, myWidth, myHeight ,""); + maxCount = 0; + count[0] = 0; + xx[0] = (myWidth)/2; + yy[0] = (myHeight)/2; + col[0] = WHITE; + black[0] = BLACK; + centerX = 0; + centerY = 0; + for (unsigned i = 1; i < NUM_COLORS; ++i) { + count[i] = 0; + xx[i] = (myWidth + myWidth*cos((2*PI*i)/NUM_COLORS))/2 - can->getWindowWidth() / 2; + yy[i] = (myHeight + myHeight*sin((2*PI*i)/NUM_COLORS))/2 - can->getWindowHeight() / 2; + col[i] = ColorHSV(6.0f*i/255.0f,1.0f,1.0f); + black[i] = col[i] * 0.25f; + centerX += xx[i]; + centerY += yy[i]; + } + centerX /= NUM_COLORS; + centerY /= NUM_COLORS; + count[NUM_COLORS] = 0; + xx[NUM_COLORS] = xx[1]; + yy[NUM_COLORS] = yy[1]; + col[NUM_COLORS] = col[1]; + black[NUM_COLORS] = black[1]; + for (int k = 0; k < NUM_COLORS+1; ++k) { + maxx[k] = xx[k]; + maxy[k] = yy[k]; + } + can->start(); +} -// /*! -// * \brief Spectrogram destructor method. -// * \details This is the destructor for the Spectrogram class. -// * \details Frees up memory that was allocated to a Spectrogram instance. -// */ -// Spectrogram::~Spectrogram() { -// for (int i = 0; i < NUM_COLORS; ++i) -// omp_destroy_lock(&(writelock[i])); -// omp_destroy_lock(&masterlock); -// delete can; -// } + /*! + * \brief Spectrogram destructor method. + * \details This is the destructor for the Spectrogram class. + * \details Frees up memory that was allocated to a Spectrogram instance. + */ +Spectrogram::~Spectrogram() { + for (int i = 0; i < NUM_COLORS; ++i) + omp_destroy_lock(&(writelock[i])); + omp_destroy_lock(&masterlock); + delete can; +} -// /*! -// * \brief Updates a spectrogram with new data, using locks for thread safety. -// * \details This function adds the value of weight to the hue specified -// * by index, and adds the value (decay^n)* -// * weight to all hues n steps away from index. -// * \param index Index of the hue to update. Value is taken mod 256. -// * \param weight The value to add to index. -// * \param decay Falloff for weight upon adjacent values. -// */ -// void Spectrogram::updateLocked(int index, float weight, float decay) { -// int i = index % NUM_COLORS; -// omp_set_lock(&(writelock[i])); -// count[i] += weight; -// if (count[i] > maxCount) maxCount = count[i]; -// omp_unset_lock(&(writelock[i])); -// weight *= decay; -// for (int k = 1; k < NUM_COLORS/2; ++k) { -// i = (index + k) % NUM_COLORS; -// omp_set_lock(&(writelock[i])); -// count[i] += weight; -// if (count[i] > maxCount) maxCount = count[i]; -// omp_unset_lock(&(writelock[i])); -// i = (index + NUM_COLORS - k) % NUM_COLORS; -// omp_set_lock(&(writelock[i])); -// count[i] += weight; -// maxCount > count[i] ? true : maxCount = count[i]; -// if (count[i] > maxCount) maxCount = count[i]; -// omp_unset_lock(&(writelock[i])); -// weight *= decay; -// } -// } + /*! + * \brief Updates a spectrogram with new data, using locks for thread safety. + * \details This function adds the value of weight to the hue specified + * by index, and adds the value (decay^n)* + * weight to all hues n steps away from index. + * \param index Index of the hue to update. Value is taken mod 256. + * \param weight The value to add to index. + * \param decay Falloff for weight upon adjacent values. + */ +void Spectrogram::updateLocked(int index, float weight, float decay) { + int i = index % NUM_COLORS; + omp_set_lock(&(writelock[i])); + count[i] += weight; + if (count[i] > maxCount) maxCount = count[i]; + omp_unset_lock(&(writelock[i])); + weight *= decay; + for (int k = 1; k < NUM_COLORS/2; ++k) { + i = (index + k) % NUM_COLORS; + omp_set_lock(&(writelock[i])); + count[i] += weight; + if (count[i] > maxCount) maxCount = count[i]; + omp_unset_lock(&(writelock[i])); + i = (index + NUM_COLORS - k) % NUM_COLORS; + omp_set_lock(&(writelock[i])); + count[i] += weight; + maxCount > count[i] ? true : maxCount = count[i]; + if (count[i] > maxCount) maxCount = count[i]; + omp_unset_lock(&(writelock[i])); + weight *= decay; + } +} -// /*! -// * \brief Updates a spectrogram with new data, using critical sections for thread safety. -// * \details This function adds the value of weight to the hue specified -// * by index, and adds the value (decay^n)* -// * weight to all hues n steps away from index. -// * \param index Index of the hue to update. Value is taken mod 256. -// * \param weight The value to add to index. -// * \param decay Falloff for weight upon adjacent values. -// */ -// void Spectrogram::updateCritical(int index, float weight, float decay) { -// int i = index % NUM_COLORS; -// #pragma omp critical -// { -// count[i] += weight; -// if (count[i] > maxCount) -// maxCount = count[i]; -// weight *= decay; -// for (int k = 1; k < NUM_COLORS/2; ++k) { -// i = (index + k) % NUM_COLORS; -// count[i] += weight; -// if (count[i] > maxCount) -// maxCount = count[i]; -// i = (index + NUM_COLORS - k) % NUM_COLORS; -// count[i] += weight; -// if (count[i] > maxCount) -// maxCount = count[i]; -// weight *= decay; -// } -// } -// } + /*! + * \brief Updates a spectrogram with new data, using critical sections for thread safety. + * \details This function adds the value of weight to the hue specified + * by index, and adds the value (decay^n)* + * weight to all hues n steps away from index. + * \param index Index of the hue to update. Value is taken mod 256. + * \param weight The value to add to index. + * \param decay Falloff for weight upon adjacent values. + */ +void Spectrogram::updateCritical(int index, float weight, float decay) { + int i = index % NUM_COLORS; + #pragma omp critical + { + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + weight *= decay; + for (int k = 1; k < NUM_COLORS/2; ++k) { + i = (index + k) % NUM_COLORS; + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + i = (index + NUM_COLORS - k) % NUM_COLORS; + count[i] += weight; + if (count[i] > maxCount) + maxCount = count[i]; + weight *= decay; + } + } +} -// /*! -// * \brief Updates the image on the spectrogram. -// * \details This function updates the Spectrogram's Canvas with the data since the last -// * call to update() and redraws it. -// * \param ratio The scaling of the visualizer. Accepts values between 0.0f and 1.0f. -// */ -// void Spectrogram::draw(float ratio) { -// if (maxCount > 0) { -// const float DELTA = (2*PI)/NUM_COLORS; -// float localmax = maxCount; -// float invcount = 1.0f/localmax; -// float mult = ratio*myHeight*sqrt(invcount); -// switch (myDrawMode) { -// case RADIAL: -// for (int k = 0; k < MAX_COLOR; ++k) { -// float kroot = mult*sqrt(count[k]); -// xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; -// yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; -// col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); -// } -// xx[NUM_COLORS] = xx[1]; -// yy[NUM_COLORS] = yy[1]; -// col[NUM_COLORS] = col[1]; -// can->drawConvexPolygon(NUM_COLORS+1,maxx,maxy,black,true); -// can->drawConvexPolygon(NUM_COLORS+1,xx,yy,col,true); -// break; -// case HORIZONTAL: -// can->pauseDrawing(); -// for (int k = 0; k < MAX_COLOR; ++k) -// can->drawLine(0,k,(ratio*myWidth*count[k])/localmax,k,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); -// can->resumeDrawing(); -// break; -// case VERTICAL: -// can->pauseDrawing(); -// // can->clear(); -// for (int k = 0; k < MAX_COLOR; ++k) -// can->drawLine(k,myHeight,k,myHeight-(ratio*myHeight*count[k])/localmax,ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); -// can->resumeDrawing(); -// break; -// } -// } -// } + /*! + * \brief Updates the image on the spectrogram. + * \details This function updates the Spectrogram's Canvas with the data since the last + * call to update() and redraws it. + * \param ratio The scaling of the visualizer. Accepts values between 0.0f and 1.0f. + */ +void Spectrogram::draw(float ratio) { + if (maxCount > 0) { + Background * bg = can->getBackground(); + const float DELTA = (2*PI)/NUM_COLORS; + float localmax = maxCount; + float invcount = 1.0f/localmax; + float mult = ratio*myHeight*sqrt(invcount); + switch (myDrawMode) { + case RADIAL: + for (int k = 0; k < MAX_COLOR; ++k) { + float kroot = mult*sqrt(count[k]); + xx[k+1] = (myWidth + kroot*cos(k*DELTA))/2; + yy[k+1] = (myHeight + kroot*sin(k*DELTA))/2; + col[k+1] = ColorHSV(6.0f*k/255.0f,invcount*count[k],1.0f); + } + xx[NUM_COLORS] = xx[1]; + yy[NUM_COLORS] = yy[1]; + col[NUM_COLORS] = col[1]; + bg->drawConvexPolygon(centerX,centerY,0, NUM_COLORS+1,maxx,maxy,0,0,0,black); + bg->drawConvexPolygon(centerX,centerY,0, NUM_COLORS+1,xx,yy,0,0,0,col); + break; + case HORIZONTAL: + can->pauseDrawing(); + for (int k = 0; k < MAX_COLOR; ++k) + bg->drawLine(-can->getWindowWidth()/2,k - can->getWindowHeight()/2,0,(ratio*myWidth*count[k])/localmax - can->getWindowWidth()/2,k - can->getWindowHeight()/2,0, 0,0,0, ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); + can->resumeDrawing(); + break; + case VERTICAL: + can->pauseDrawing(); + // can->clear(); + for (int k = 0; k < MAX_COLOR; ++k) + bg->drawLine(k-can->getWindowWidth()/2,myHeight - can->getWindowHeight()/2,0,k - can->getWindowWidth()/2,myHeight-(ratio*myHeight*count[k])/localmax - can->getWindowHeight()/2,0, 0,0,0, ColorHSV((6.0f*k)/MAX_COLOR,1.0f,1.0f)); + can->resumeDrawing(); + break; + } + } +} -// /*! -// * \brief Finishes the spectrogram. -// * \details This function tells the Spectrogram to free all of its memory and close -// * down its Canvas. -// */ -// void Spectrogram::finish() { -// can->wait(); -// } + /*! + * \brief Finishes the spectrogram. + * \details This function tells the Spectrogram to free all of its memory and close + * down its Canvas. + */ +void Spectrogram::finish() { + can->wait(); +} -// } +} diff --git a/src/TSGL/Spectrogram.h b/src/TSGL/Spectrogram.h index 6ee052c45..fbb9a84ce 100644 --- a/src/TSGL/Spectrogram.h +++ b/src/TSGL/Spectrogram.h @@ -1,56 +1,57 @@ -// /* -// * Spectrogram.h -// */ +/* + * Spectrogram.h + */ -// #ifndef SRC_TSGL_SPECTROGRAM_H_ -// #define SRC_TSGL_SPECTROGRAM_H_ +#ifndef SRC_TSGL_SPECTROGRAM_H_ +#define SRC_TSGL_SPECTROGRAM_H_ -// #include +#include -// #include "Canvas.h" -// #include "Color.h" +#include "Canvas.h" +#include "Color.h" -// namespace tsgl { +namespace tsgl { -// enum SpectrogramDrawmode { -// RADIAL = 0, -// HORIZONTAL = 1, -// VERTICAL = 2 -// }; +enum SpectrogramDrawmode { + RADIAL = 0, + HORIZONTAL = 1, + VERTICAL = 2 +}; -// /*! \class Spectrogram -// * \brief Displays a spectrogram of a given data set. -// * \details Spectrogram is a class for visualizing data as a color spectrum. -// * This data will typically be hues, but Spectrogram will accept any data -// * mapping to an integer value between 0 and 255. -// */ -// class Spectrogram { -// private: -// static const int B; //Border -// static const float PI; +/*! \class Spectrogram + * \brief Displays a spectrogram of a given data set. + * \details Spectrogram is a class for visualizing data as a color spectrum. + * This data will typically be hues, but Spectrogram will accept any data + * mapping to an integer value between 0 and 255. + */ +class Spectrogram { +private: + static const int B; //Border + static const float PI; -// omp_lock_t writelock[NUM_COLORS], masterlock; -// int myHeight, myWidth; -// float maxCount; -// int xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; -// float count[NUM_COLORS+1]; -// ColorFloat col[NUM_COLORS+1], black[NUM_COLORS+1]; -// SpectrogramDrawmode myDrawMode; -// Canvas* can; -// public: -// Spectrogram(SpectrogramDrawmode drawMode, int width, int height = -1); + omp_lock_t writelock[NUM_COLORS], masterlock; + int myHeight, myWidth; + float centerX, centerY; + float maxCount; + float xx[NUM_COLORS+1], yy[NUM_COLORS+1], maxx[NUM_COLORS+1], maxy[NUM_COLORS+1]; + float count[NUM_COLORS+1]; + ColorFloat col[NUM_COLORS+1], black[NUM_COLORS+1]; + SpectrogramDrawmode myDrawMode; + Canvas* can; +public: + Spectrogram(SpectrogramDrawmode drawMode, int width, int height = -1); -// ~Spectrogram(); + ~Spectrogram(); -// void updateLocked(int index, float weight = 1.0f, float decay = 0.8f); + void updateLocked(int index, float weight = 1.0f, float decay = 0.8f); -// void updateCritical(int index, float weight = 1.0f, float decay = 0.8f); + void updateCritical(int index, float weight = 1.0f, float decay = 0.8f); -// void draw(float ratio); + void draw(float ratio); -// void finish(); -// }; + void finish(); +}; -// } +} -// #endif /* SRC_TSGL_SPECTROGRAM_H_ */ +#endif /* SRC_TSGL_SPECTROGRAM_H_ */ diff --git a/src/examples/ArrayBubbleSort/Makefile b/src/examples/ArrayBubbleSort/Makefile index 7c11161b9..1cb0b861b 100644 --- a/src/examples/ArrayBubbleSort/Makefile +++ b/src/examples/ArrayBubbleSort/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/ArrayShakerSort/Makefile b/src/examples/ArrayShakerSort/Makefile index 84859b908..5cea6a256 100644 --- a/src/examples/ArrayShakerSort/Makefile +++ b/src/examples/ArrayShakerSort/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Ballroom/Makefile b/src/examples/Ballroom/Makefile index 0c4dac6ea..0fe293b4b 100644 --- a/src/examples/Ballroom/Makefile +++ b/src/examples/Ballroom/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Clock/Makefile b/src/examples/Clock/Makefile index b2391b03d..f82c1cfa9 100644 --- a/src/examples/Clock/Makefile +++ b/src/examples/Clock/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Conway/Makefile b/src/examples/Conway/Makefile index f70f2aa07..bfd3b8c21 100644 --- a/src/examples/Conway/Makefile +++ b/src/examples/Conway/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/CubeRun/Makefile b/src/examples/CubeRun/Makefile index c5bf5fe6e..ed41858d8 100644 --- a/src/examples/CubeRun/Makefile +++ b/src/examples/CubeRun/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/DiningPhilosophers/Makefile b/src/examples/DiningPhilosophers/Makefile index c19ed7663..6a719dc26 100644 --- a/src/examples/DiningPhilosophers/Makefile +++ b/src/examples/DiningPhilosophers/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = Fork.h philEnums.h \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/DiningPhilosophers3D/Makefile b/src/examples/DiningPhilosophers3D/Makefile index b64aff46b..3e259e69a 100644 --- a/src/examples/DiningPhilosophers3D/Makefile +++ b/src/examples/DiningPhilosophers3D/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = Fork3D.h philEnums.h \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Fireworks/Makefile b/src/examples/Fireworks/Makefile index 069961f52..81095fe32 100644 --- a/src/examples/Fireworks/Makefile +++ b/src/examples/Fireworks/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/ForestFire/Makefile b/src/examples/ForestFire/Makefile index 5a5e3c30a..815d14cb2 100644 --- a/src/examples/ForestFire/Makefile +++ b/src/examples/ForestFire/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Langton/AntFarm.cpp b/src/examples/Langton/AntFarm.cpp index 4d687c184..c4f41e91f 100644 --- a/src/examples/Langton/AntFarm.cpp +++ b/src/examples/Langton/AntFarm.cpp @@ -32,15 +32,16 @@ void AntFarm::addAnt(int x, int y, int r, int g, int b, int d) { } inline void AntFarm::moveAnt(int j) { - if (filled[ants[j]->myX + width * ants[j]->myY]) { + Background * bg = can->getBackground(); + if (filled[(ants[j]->myX + width/2) + width * (ants[j]->myY + height/2)]) { ants[j]->myDir = (ants[j]->myDir + 1) % 4; if (shading) - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed/2, ants[j]->myGreen/2, ants[j]->myBlue/2, ants[j]->myAlpha)); else - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(MAX_COLOR / 2, MAX_COLOR / 2, MAX_COLOR / 2, ants[j]->myAlpha)); } else { ants[j]->myDir = (ants[j]->myDir + 3) % 4; - can->drawPoint(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); + bg->drawPixel(ants[j]->myX, ants[j]->myY, ColorInt(ants[j]->myRed, ants[j]->myGreen, ants[j]->myBlue, ants[j]->myAlpha)); } } @@ -58,7 +59,7 @@ void AntFarm::moveAnts() { moveAnt(j); } for (int j = 0; j < size; j++) { - filled[ants[j]->myX + width * ants[j]->myY] ^= true; + filled[(ants[j]->myX + width/2) + width * (ants[j]->myY + height/2)] ^= true; ants[j]->move(); } } diff --git a/src/examples/Langton/LangtonAnt.cpp b/src/examples/Langton/LangtonAnt.cpp index 0d1621cf9..a3591647d 100644 --- a/src/examples/Langton/LangtonAnt.cpp +++ b/src/examples/Langton/LangtonAnt.cpp @@ -18,16 +18,16 @@ LangtonAnt::LangtonAnt(int x, int y, int r, int g, int b, int d, AntFarm* p) { void LangtonAnt::move() { switch (myDir) { case UP: - myY = (myY > 0) ? myY - 1 : myFarm->height - 1; + myY = (myY < myFarm->height/2 - 1) ? myY + 1 : -myFarm->height/2; break; case RIGHT: - myX = (myX < myFarm->width - 1) ? myX + 1 : 0; + myX = (myX < myFarm->width/2 - 1) ? myX + 1 : -myFarm->width/2; break; case DOWN: - myY = (myY < myFarm->height - 1) ? myY + 1 : 0; + myY = (myY > -myFarm->height/2) ? myY - 1 : myFarm->height/2 - 1; break; case LEFT: - myX = (myX > 0) ? myX - 1 : myFarm->width - 1; + myX = (myX > -myFarm->width/2) ? myX - 1 : myFarm->width/2 - 1; break; default: break; diff --git a/src/examples/Langton/Makefile b/src/examples/Langton/Makefile index 475a54b37..1a1a8d34b 100644 --- a/src/examples/Langton/Makefile +++ b/src/examples/Langton/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Langton/testLangton.cpp b/src/examples/Langton/testLangton.cpp index d9d6acd57..7a7df87ae 100644 --- a/src/examples/Langton/testLangton.cpp +++ b/src/examples/Langton/testLangton.cpp @@ -34,11 +34,13 @@ void alphaLangtonFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants bool paused = false; + Background * bg = can.getBackground(); + AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); Timer pulse(28.72 / 60); double time = pulse.getTime(); @@ -52,8 +54,8 @@ void alphaLangtonFunction(Canvas& can) { can.bindToButton(TSGL_ENTER, TSGL_PRESS, [&paused]() { paused = !paused; }); - can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&can]() { - can.clearProcedural(); + can.bindToButton(TSGL_SPACE, TSGL_PRESS, [&bg]() { + bg->clear(); }); while (can.isOpen()) { @@ -62,7 +64,7 @@ void alphaLangtonFunction(Canvas& can) { for (int i = 0; i < IPF; i++) farm.moveAnts(); if (pulse.pastPeriod()) - can.clearProcedural(); + bg->clear(); } } } @@ -88,7 +90,7 @@ void langtonFunction(Canvas& can) { WH = can.getWindowHeight(); // Window height AntFarm farm(WW,WH,4,&can); farm.setParallel(false); - farm.addAnt(WW / 2,WH / 2,MAX_COLOR,0,0,0); + farm.addAnt(0,0,MAX_COLOR,0,0,0); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class for (int i = 0; i < IPF; i++) { @@ -114,10 +116,10 @@ void langtonColonyFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); farm.setShading(true); while (can.isOpen()) { can.sleep(); //Removed the timer and replaced it with an internal timer in the Canvas class @@ -138,10 +140,10 @@ void langtonRainbowFunction(Canvas& can) { R = WH / 6; // How far apart to space the ants AntFarm farm(WW,WH,4,&can); - farm.addAnt(WW / 2 - R,WH / 2,MAX_COLOR,0,0,0); - farm.addAnt(WW / 2,WH / 2 - R,0,0,MAX_COLOR,1); - farm.addAnt(WW / 2 + R,WH / 2,0,MAX_COLOR,0,2); - farm.addAnt(WW / 2,WH / 2 + R,MAX_COLOR,0,MAX_COLOR,3); + farm.addAnt(-R,0,MAX_COLOR,0,0,0); + farm.addAnt(0,R,0,0,MAX_COLOR,1); + farm.addAnt(R,0,0,MAX_COLOR,0,2); + farm.addAnt(0,-R,MAX_COLOR,0,MAX_COLOR,3); farm.setShading(true); for (int j = 0; j < 4; j++) farm.ants[j]->setAlpha(64); diff --git a/src/examples/Makefile b/src/examples/Makefile index 527df333e..89ba01523 100644 --- a/src/examples/Makefile +++ b/src/examples/Makefile @@ -13,6 +13,7 @@ SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ DiningPhilosophers3D/. \ Fireworks/. \ ForestFire/. \ + Langton/. \ MergeSort/. \ NewtonPendulum/. \ Pong/. \ @@ -23,7 +24,6 @@ SUBDIRS_TO_BUILD := ArrayBubbleSort/. \ ThreadedArrayBubbleSort/. \ ThreadedArrayOperations/. \ ThreadedSolarSystem/. \ -# Langton/. \ # Mandelbrot/. \ # ParallelPandemic/. \ # ProducerConsumer/. \ diff --git a/src/examples/Mandelbrot/Makefile b/src/examples/Mandelbrot/Makefile index f09acd988..42fe81c72 100644 --- a/src/examples/Mandelbrot/Makefile +++ b/src/examples/Mandelbrot/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/MergeSort/Makefile b/src/examples/MergeSort/Makefile index 7844f8fb9..9510582a6 100644 --- a/src/examples/MergeSort/Makefile +++ b/src/examples/MergeSort/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/NewtonPendulum/Makefile b/src/examples/NewtonPendulum/Makefile index 299fefdbb..26a9c8a81 100644 --- a/src/examples/NewtonPendulum/Makefile +++ b/src/examples/NewtonPendulum/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = \ @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/Pandemic/Makefile b/src/examples/Pandemic/Makefile index 73f09c86b..ee82ab18f 100644 --- a/src/examples/Pandemic/Makefile +++ b/src/examples/Pandemic/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = statusEnums.h @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/ParallelPandemic/Makefile b/src/examples/ParallelPandemic/Makefile index 783328409..0752cb9e7 100644 --- a/src/examples/ParallelPandemic/Makefile +++ b/src/examples/ParallelPandemic/Makefile @@ -9,6 +9,7 @@ RM = rm -f -r # Directory this example is contained in MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) DIR := $(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +UNAME := $(shell uname) # Dependencies _DEPS = statusEnums.h @@ -29,15 +30,15 @@ NOWARN = -Wno-unused-parameter -Wno-unused-function -Wno-narrowing \ -Wno-sizeof-array-argument -Wno-sign-compare -Wno-unused-variable ifeq ($(UNAME), Linux) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), CYGWIN_NT-10.0) -GL_FLAGS = -lGLU -lglut -lGL +GL_FLAGS := -lGLU -lglut -lGL BREW := endif ifeq ($(UNAME), Darwin) -GL_FLAGS = -framework OpenGL -lglut +GL_FLAGS := -framework OpenGL -lglut BREW := -lomp -I"$(brew --prefix libomp)/include" endif diff --git a/src/examples/ParallelPandemic/obj/Person.o b/src/examples/ParallelPandemic/obj/Person.o index 16e7499c9da43987eb9e858a8b4aba194efceade..56089da1e482eb77f891623f05fc85fcde948285 100644 GIT binary patch literal 742996 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 z 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

_n2cQiErehlON(5UI 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

^<2peH@VQdG5>~l!_#IgMWPN+?U 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%0A{4J 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