From b38e870d6be22a377bf7b0fb5048801886ebaa77 Mon Sep 17 00:00:00 2001 From: Matt Strapp Date: Mon, 27 Sep 2021 21:44:53 -0500 Subject: do ws2 --- dev/MinGfx/src/gfxmath.cc | 274 ++++---- dev/MinGfx/src/gfxmath.h | 192 +++--- dev/MinGfx/src/quaternion.cc | 522 +++++++------- dev/MinGfx/src/quick_shapes.cc | 1466 ++++++++++++++++++++-------------------- dev/MinGfx/src/ray.h | 332 ++++----- 5 files changed, 1393 insertions(+), 1393 deletions(-) (limited to 'dev/MinGfx') diff --git a/dev/MinGfx/src/gfxmath.cc b/dev/MinGfx/src/gfxmath.cc index 28cfedf..19d99ef 100644 --- a/dev/MinGfx/src/gfxmath.cc +++ b/dev/MinGfx/src/gfxmath.cc @@ -1,137 +1,137 @@ -/* - Copyright (c) 2017,2018 Regents of the University of Minnesota. - All Rights Reserved. - See corresponding header file for details. - */ - -#include "gfxmath.h" - -#define _USE_MATH_DEFINES -#include -#include - -#include "ray.h" - - -namespace mingfx { - -const float GfxMath::PI = 3.14159265359f; -const float GfxMath::TWO_PI = 6.28318530718f; -const float GfxMath::HALF_PI = 1.57079632679f; - -float GfxMath::sin(float a) { -#ifdef WIN32 - return std::sinf(a); -#else - return std::sin(a); -#endif -} - -float GfxMath::cos(float a) { -#ifdef WIN32 - return std::cosf(a); -#else - return std::cos(a); -#endif -} - -float GfxMath::tan(float a) { -#ifdef WIN32 - return std::tanf(a); -#else - return std::tan(a); -#endif -} - -float GfxMath::asin(float a) { -#ifdef WIN32 - return std::asinf(a); -#else - return std::asin(a); -#endif -} - -float GfxMath::acos(float a) { -#ifdef WIN32 - return std::acosf(a); -#else - return std::acos(a); -#endif -} - -float GfxMath::atan(float a) { -#ifdef WIN32 - return std::atanf(a); -#else - return std::atan(a); -#endif -} - -float GfxMath::atan2(float a, float b) { -#ifdef WIN32 - return std::atan2f(a, b); -#else - return std::atan2(a, b); -#endif -} - -float GfxMath::Clamp(float x, float a, float b) { - return std::min(std::max(x, a), b); -} - -float GfxMath::ToRadians(float degrees) { - return degrees * GfxMath::PI / 180.0f; -} - -float GfxMath::ToDegrees(float radians) { - return radians * 180.0f / GfxMath::PI; -} - -Vector3 GfxMath::ToRadians(Vector3 degrees) { - return Vector3(ToRadians(degrees[0]), ToRadians(degrees[1]), ToRadians(degrees[2])); -} - -Vector3 GfxMath::ToDegrees(Vector3 radians) { - return Vector3(ToDegrees(radians[0]), ToDegrees(radians[1]), ToDegrees(radians[2])); -} - -float GfxMath::Lerp(float a, float b, float alpha) { - return (1.0f-alpha)*a + alpha*b; -} - -int GfxMath::iLerp(int a, int b, float alpha) { - return (int)std::round((1.0f-alpha)*(float)a + alpha*(float)b); -} - -Point3 GfxMath::ScreenToNearPlane(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint) { - Matrix4 filmPtToWorld = (P*V).Inverse(); - return filmPtToWorld * Point3(ndcPoint[0], ndcPoint[1], -1.0); -} - - -Point3 GfxMath::ScreenToWorld(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint, float zValue) { - Matrix4 filmPtToWorld = (P*V).Inverse(); - float zneg1topos1 = zValue*2.0f - 1.0f; - return filmPtToWorld * Point3(ndcPoint[0], ndcPoint[1], zneg1topos1); -} - - -Point3 GfxMath::ScreenToDepthPlane(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint, float planeDepth) { - Point3 pNear = ScreenToNearPlane(V, P, ndcPoint); - - Matrix4 camMat = V.Inverse(); - Point3 eye = camMat.ColumnToPoint3(3); - Vector3 look = -camMat.ColumnToVector3(2); - - Ray r(eye, pNear - eye); - - Point3 p3D; - float t; - if (!r.IntersectPlane(eye + planeDepth*look, -look, &t, &p3D)) { - std::cerr << "filmplane2D_to_plane3D() error -- no intersection found!" << std::endl; - } - return p3D; -} - - -} // end namespace +/* + Copyright (c) 2017,2018 Regents of the University of Minnesota. + All Rights Reserved. + See corresponding header file for details. + */ + +#include "gfxmath.h" + +#define _USE_MATH_DEFINES +#include +#include + +#include "ray.h" + + +namespace mingfx { + +const float GfxMath::PI = 3.14159265359f; +const float GfxMath::TWO_PI = 6.28318530718f; +const float GfxMath::HALF_PI = 1.57079632679f; + +float GfxMath::sin(float a) { +#ifdef WIN32 + return std::sinf(a); +#else + return std::sin(a); +#endif +} + +float GfxMath::cos(float a) { +#ifdef WIN32 + return std::cosf(a); +#else + return std::cos(a); +#endif +} + +float GfxMath::tan(float a) { +#ifdef WIN32 + return std::tanf(a); +#else + return std::tan(a); +#endif +} + +float GfxMath::asin(float a) { +#ifdef WIN32 + return std::asinf(a); +#else + return std::asin(a); +#endif +} + +float GfxMath::acos(float a) { +#ifdef WIN32 + return std::acosf(a); +#else + return std::acos(a); +#endif +} + +float GfxMath::atan(float a) { +#ifdef WIN32 + return std::atanf(a); +#else + return std::atan(a); +#endif +} + +float GfxMath::atan2(float a, float b) { +#ifdef WIN32 + return std::atan2f(a, b); +#else + return std::atan2(a, b); +#endif +} + +float GfxMath::Clamp(float x, float a, float b) { + return std::min(std::max(x, a), b); +} + +float GfxMath::ToRadians(float degrees) { + return degrees * GfxMath::PI / 180.0f; +} + +float GfxMath::ToDegrees(float radians) { + return radians * 180.0f / GfxMath::PI; +} + +Vector3 GfxMath::ToRadians(Vector3 degrees) { + return Vector3(ToRadians(degrees[0]), ToRadians(degrees[1]), ToRadians(degrees[2])); +} + +Vector3 GfxMath::ToDegrees(Vector3 radians) { + return Vector3(ToDegrees(radians[0]), ToDegrees(radians[1]), ToDegrees(radians[2])); +} + +float GfxMath::Lerp(float a, float b, float alpha) { + return (1.0f-alpha)*a + alpha*b; +} + +int GfxMath::iLerp(int a, int b, float alpha) { + return (int)std::round((1.0f-alpha)*(float)a + alpha*(float)b); +} + +Point3 GfxMath::ScreenToNearPlane(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint) { + Matrix4 filmPtToWorld = (P*V).Inverse(); + return filmPtToWorld * Point3(ndcPoint[0], ndcPoint[1], -1.0); +} + + +Point3 GfxMath::ScreenToWorld(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint, float zValue) { + Matrix4 filmPtToWorld = (P*V).Inverse(); + float zneg1topos1 = zValue*2.0f - 1.0f; + return filmPtToWorld * Point3(ndcPoint[0], ndcPoint[1], zneg1topos1); +} + + +Point3 GfxMath::ScreenToDepthPlane(const Matrix4 &V, const Matrix4 &P, const Point2 &ndcPoint, float planeDepth) { + Point3 pNear = ScreenToNearPlane(V, P, ndcPoint); + + Matrix4 camMat = V.Inverse(); + Point3 eye = camMat.ColumnToPoint3(3); + Vector3 look = -camMat.ColumnToVector3(2); + + Ray r(eye, pNear - eye); + + Point3 p3D; + float t; + if (!r.IntersectPlane(eye + planeDepth*look, -look, &t, &p3D)) { + std::cerr << "filmplane2D_to_plane3D() error -- no intersection found!" << std::endl; + } + return p3D; +} + + +} // end namespace diff --git a/dev/MinGfx/src/gfxmath.h b/dev/MinGfx/src/gfxmath.h index 86c1061..3240072 100644 --- a/dev/MinGfx/src/gfxmath.h +++ b/dev/MinGfx/src/gfxmath.h @@ -1,97 +1,97 @@ -/* - This file is part of the MinGfx Project. - - Copyright (c) 2017,2018 Regents of the University of Minnesota. - All Rights Reserved. - - Original Author(s) of this File: - Dan Keefe, 2018, University of Minnesota - - Author(s) of Significant Updates/Modifications to the File: - ... - */ - -#ifndef SRC_GFXMATH_H_ -#define SRC_GFXMATH_H_ - -#include "point2.h" -#include "point3.h" -#include "vector3.h" -#include "matrix4.h" - -namespace mingfx { - - -/** This class holds a variety of static math functions that are useful to have - defined with creating graphics programs. - */ -class GfxMath { -public: - - /// MinGfx specific implementations of trigonometric functions included to - /// solve compilation issues between different platforms. - static float sin(float a); - - static float cos(float a); - - static float tan(float a); - - static float asin(float a); - - static float acos(float a); - - static float atan(float a); - - static float atan2(float a, float b); - - /// Returns a if x is less than a and b if x is greater than b. - static float Clamp(float x, float a, float b); - - static float ToRadians(float degrees); - - static float ToDegrees(float radians); - - static Vector3 ToRadians(Vector3 degrees); - - static Vector3 ToDegrees(Vector3 radians); - - static float Lerp(float a, float b, float alpha); - - static int iLerp(int a, int b, float alpha); - - /// Converts a 2D point on the filmplane represented in Normalized Device - /// Coorindates, which means (-1,1) for the top left corner of the screen and - /// (1,-1) for the bottom right corner, to a 3D point that lies on the camera's - /// near plane. Useful for converting mouse coordinates into a 3D point. - /// Remember that this uses NORMALIZED device coordinates for the screenPt, - /// not pixels. GraphicsApp and most other graphics engines report mouse move - /// events in pixels, so you need to convert these to normalized device coordinates - /// first. If you are using GraphicsApp, you can do this with: - /// Point2 normPos = graphicsApp->pixels_to_normalized_coordinates(mousePos); - static Point3 ScreenToNearPlane(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt); - - /// Similar to filmplane2D_to_nearplane3D() but here rather than using the - /// nearplane, you specify the depth of the plane to use as a distance away - /// from the camera's focal point. - static Point3 ScreenToDepthPlane(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt, float planeDepth); - - /// Converts a 2D point on the filmplane represented in Normalized Device - /// Coorindates, which means (-1,1) for the top left corner of the screen and - /// (1,-1) for the bottom right corner, to a 3D point in the world. The depth - /// buffer value under the pixel must be supplied. If you are using GraphicsApp, - /// you can use the mouse pos in pixels to get the required arguments like this: - /// Point2 normPos = graphicsApp->pixels_to_normalized_coordinates(mousePos); - /// float normZ = graphicsApp->z_value_at_pixel(mousePos); - static Point3 ScreenToWorld(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt, float normalizedZ); - - - static const float PI; - static const float TWO_PI; - static const float HALF_PI; -}; - - - -} // end namespace - +/* + This file is part of the MinGfx Project. + + Copyright (c) 2017,2018 Regents of the University of Minnesota. + All Rights Reserved. + + Original Author(s) of this File: + Dan Keefe, 2018, University of Minnesota + + Author(s) of Significant Updates/Modifications to the File: + ... + */ + +#ifndef SRC_GFXMATH_H_ +#define SRC_GFXMATH_H_ + +#include "point2.h" +#include "point3.h" +#include "vector3.h" +#include "matrix4.h" + +namespace mingfx { + + +/** This class holds a variety of static math functions that are useful to have + defined with creating graphics programs. + */ +class GfxMath { +public: + + /// MinGfx specific implementations of trigonometric functions included to + /// solve compilation issues between different platforms. + static float sin(float a); + + static float cos(float a); + + static float tan(float a); + + static float asin(float a); + + static float acos(float a); + + static float atan(float a); + + static float atan2(float a, float b); + + /// Returns a if x is less than a and b if x is greater than b. + static float Clamp(float x, float a, float b); + + static float ToRadians(float degrees); + + static float ToDegrees(float radians); + + static Vector3 ToRadians(Vector3 degrees); + + static Vector3 ToDegrees(Vector3 radians); + + static float Lerp(float a, float b, float alpha); + + static int iLerp(int a, int b, float alpha); + + /// Converts a 2D point on the filmplane represented in Normalized Device + /// Coorindates, which means (-1,1) for the top left corner of the screen and + /// (1,-1) for the bottom right corner, to a 3D point that lies on the camera's + /// near plane. Useful for converting mouse coordinates into a 3D point. + /// Remember that this uses NORMALIZED device coordinates for the screenPt, + /// not pixels. GraphicsApp and most other graphics engines report mouse move + /// events in pixels, so you need to convert these to normalized device coordinates + /// first. If you are using GraphicsApp, you can do this with: + /// Point2 normPos = graphicsApp->pixels_to_normalized_coordinates(mousePos); + static Point3 ScreenToNearPlane(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt); + + /// Similar to filmplane2D_to_nearplane3D() but here rather than using the + /// nearplane, you specify the depth of the plane to use as a distance away + /// from the camera's focal point. + static Point3 ScreenToDepthPlane(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt, float planeDepth); + + /// Converts a 2D point on the filmplane represented in Normalized Device + /// Coorindates, which means (-1,1) for the top left corner of the screen and + /// (1,-1) for the bottom right corner, to a 3D point in the world. The depth + /// buffer value under the pixel must be supplied. If you are using GraphicsApp, + /// you can use the mouse pos in pixels to get the required arguments like this: + /// Point2 normPos = graphicsApp->pixels_to_normalized_coordinates(mousePos); + /// float normZ = graphicsApp->z_value_at_pixel(mousePos); + static Point3 ScreenToWorld(const Matrix4 &viewMatrix, const Matrix4 &projMatrix, const Point2 &normalizedScreenPt, float normalizedZ); + + + static const float PI; + static const float TWO_PI; + static const float HALF_PI; +}; + + + +} // end namespace + #endif \ No newline at end of file diff --git a/dev/MinGfx/src/quaternion.cc b/dev/MinGfx/src/quaternion.cc index 24830c8..42723f1 100644 --- a/dev/MinGfx/src/quaternion.cc +++ b/dev/MinGfx/src/quaternion.cc @@ -1,261 +1,261 @@ -/* -Copyright (c) 2017,2018 Regents of the University of Minnesota. -All Rights Reserved. -See corresponding header file for details. -*/ - -#define _USE_MATH_DEFINES -#include "quaternion.h" - -#include "gfxmath.h" - -namespace mingfx { - - -Quaternion::Quaternion() { - q[0] = 0.0; - q[1] = 0.0; - q[2] = 0.0; - q[3] = 1.0; -} - -Quaternion::Quaternion(float qx, float qy, float qz, float qw) { - q[0] = qx; - q[1] = qy; - q[2] = qz; - q[3] = qw; -} - -Quaternion::Quaternion(float *ptr) { - q[0] = ptr[0]; - q[1] = ptr[1]; - q[2] = ptr[2]; - q[3] = ptr[3]; -} - -Quaternion::Quaternion(const Quaternion& other) { - q[0] = other[0]; - q[1] = other[1]; - q[2] = other[2]; - q[3] = other[3]; -} - -Quaternion::~Quaternion() { -} - -bool Quaternion::operator==(const Quaternion& other) const { - return (fabs(other[0] - q[0]) < MINGFX_MATH_EPSILON && - fabs(other[1] - q[1]) < MINGFX_MATH_EPSILON && - fabs(other[2] - q[2]) < MINGFX_MATH_EPSILON && - fabs(other[3] - q[3]) < MINGFX_MATH_EPSILON); -} - -bool Quaternion::operator!=(const Quaternion& other) const { - return (fabs(other[0] - q[0]) >= MINGFX_MATH_EPSILON || - fabs(other[1] - q[1]) >= MINGFX_MATH_EPSILON || - fabs(other[2] - q[2]) >= MINGFX_MATH_EPSILON || - fabs(other[3] - q[3]) >= MINGFX_MATH_EPSILON); -} - -Quaternion& Quaternion::operator=(const Quaternion& other) { - q[0] = other[0]; - q[1] = other[1]; - q[2] = other[2]; - q[3] = other[3]; - return *this; -} - -float Quaternion::operator[](const int i) const { - if ((i>=0) && (i<=3)) { - return q[i]; - } - else { - // this is an error! - return 0.0; - } -} - -float& Quaternion::operator[](const int i) { - return q[i]; -} - - -const float * Quaternion::value_ptr() const { - return q; -} - -Quaternion Quaternion::Slerp(const Quaternion &other, float alpha) const { - // https://en.wikipedia.org/wiki/Slerp - - Quaternion v0 = *this; - Quaternion v1 = other; - - // Only unit quaternions are valid rotations. - // Normalize to avoid undefined behavior. - v0.Normalize(); - v1.Normalize(); - - // Compute the cosine of the angle between the two vectors. - float dot = v0.Dot(v1); - - // If the dot product is negative, the quaternions - // have opposite handed-ness and slerp won't take - // the shorter path. Fix by reversing one quaternion. - if (dot < 0.0f) { - v1 = -v1; - dot = -dot; - } - - const double DOT_THRESHOLD = 0.9995; - if (dot > DOT_THRESHOLD) { - // If the inputs are too close for comfort, linearly interpolate - // and normalize the result. - - Quaternion result = v0 + alpha*(v1 - v0); - result.Normalize(); - return result; - } - - GfxMath::Clamp(dot, -1, 1); // Robustness: Stay within domain of acos() - float theta_0 = GfxMath::acos(dot); // theta_0 = angle between input vectors - float theta = theta_0 * alpha; // theta = angle between v0 and result - - float s0 = GfxMath::cos(theta) - dot - * GfxMath::sin(theta) / GfxMath::sin(theta_0); // == sin(theta_0 - theta) / sin(theta_0) - float s1 = GfxMath::sin(theta) / GfxMath::sin(theta_0); - - return (s0 * v0) + (s1 * v1); -} - -Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float alpha) { - return a.Slerp(b, alpha); -} - - -std::ostream & operator<< ( std::ostream &os, const Quaternion &q) { - return os << "<" << q[0] << ", " << q[1] << ", " << q[2] << ", " << q[3] << ")"; -} - -std::istream & operator>> ( std::istream &is, Quaternion &q) { - // format: - char dummy; - return is >> dummy >> q[0] >> dummy >> q[1] >> dummy >> q[2] >> dummy >> q[3] >> dummy; -} - - -float Quaternion::Dot(const Quaternion& other) const { - return q[0]*other[0] + q[1]*other[1] + q[2]*other[2] + q[3]*other[3]; - -} - -float Quaternion::Length() const { - return sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); -} - -void Quaternion::Normalize() { - float sizeSq = + q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; - if (sizeSq < MINGFX_MATH_EPSILON) { - return; // do nothing to zero quats - } - float scaleFactor = (float)1.0/(float)sqrt(sizeSq); - q[0] *= scaleFactor; - q[1] *= scaleFactor; - q[2] *= scaleFactor; - q[3] *= scaleFactor; -} - -Quaternion Quaternion::ToUnit() const { - Quaternion qtmp(*this); - qtmp.Normalize(); - return qtmp; -} - -/// Returns the conjugate of the quaternion. -Quaternion Quaternion::Conjugate() const { - return Quaternion(-q[0], -q[1], -q[2], q[3]); -} - - -Quaternion Quaternion::FromAxisAngle(const Vector3 &axis, float angle) { - // [qx, qy, qz, qw] = [sin(a/2) * vx, sin(a/2)* vy, sin(a/2) * vz, cos(a/2)] - float x = GfxMath::sin(angle/2.0) * axis[0]; - float y = GfxMath::sin(angle/2.0) * axis[1]; - float z = GfxMath::sin(angle/2.0) * axis[2]; - float w = GfxMath::cos(angle/2.0); - return Quaternion(x,y,z,w); -} - - -Quaternion Quaternion::FromEulerAnglesZYX(const Vector3 &angles) { - Quaternion rot_x = Quaternion::FromAxisAngle(Vector3::UnitX(), angles[0]); - Quaternion rot_y = Quaternion::FromAxisAngle(Vector3::UnitY(), angles[1]); - Quaternion rot_z = Quaternion::FromAxisAngle(Vector3::UnitZ(), angles[2]); - return rot_z * rot_y * rot_x; -} - -Vector3 Quaternion::ToEulerAnglesZYX() const { - // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles - - Vector3 angles; - - // roll (x-axis rotation) - float sinr = +2.0f * (w() * x() + y() * z()); - float cosr = +1.0f - 2.0f * (x() * x() + y() * y()); - angles[0] = std::atan2(sinr, cosr); - - // pitch (y-axis rotation) - float sinp = +2.0f * (w() * y() - z() * x()); - if (std::fabs(sinp) >= 1.f) - angles[1] = std::copysign(GfxMath::HALF_PI, sinp); // use 90 degrees if out of range - else - angles[1] = std::asin(sinp); - - // yaw (z-axis rotation) - float siny = +2.0f * (w() * z() + x() * y()); - float cosy = +1.0f - 2.0f * (y() * y() + z() * z()); - angles[2] = std::atan2(siny, cosy); - - return angles; -} - - -Quaternion operator*(const Quaternion& q1, const Quaternion& q2) { - float real1 = q1[3]; - Vector3 imag1 = Vector3(q1[0], q1[1], q1[2]); - - float real2 = q2[3]; - Vector3 imag2 = Vector3(q2[0], q2[1], q2[2]); - - float real = real1*real2 - imag1.Dot(imag2); - Vector3 imag = real1*imag2 + real2*imag1 + imag1.Cross(imag2); - - return Quaternion(imag[0], imag[1], imag[2], real); -} - - -Quaternion operator/(const Quaternion& q, const float s) { - const float invS = 1.0f / s; - return Quaternion(q[0]*invS, q[1]*invS, q[2]*invS, q[3]*invS); -} - -Quaternion operator*(const float s, const Quaternion& q) { - return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s); -} - -Quaternion operator*(const Quaternion& q, const float s) { - return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s); -} - -Quaternion operator-(const Quaternion& q) { - return Quaternion(-q[0], -q[1], -q[2], -q[3]); -} - -Quaternion operator+(const Quaternion& q1, const Quaternion& q2) { - return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]); -} - -Quaternion operator-(const Quaternion& q1, const Quaternion& q2) { - return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]); -} - -} // end namespace +/* +Copyright (c) 2017,2018 Regents of the University of Minnesota. +All Rights Reserved. +See corresponding header file for details. +*/ + +#define _USE_MATH_DEFINES +#include "quaternion.h" + +#include "gfxmath.h" + +namespace mingfx { + + +Quaternion::Quaternion() { + q[0] = 0.0; + q[1] = 0.0; + q[2] = 0.0; + q[3] = 1.0; +} + +Quaternion::Quaternion(float qx, float qy, float qz, float qw) { + q[0] = qx; + q[1] = qy; + q[2] = qz; + q[3] = qw; +} + +Quaternion::Quaternion(float *ptr) { + q[0] = ptr[0]; + q[1] = ptr[1]; + q[2] = ptr[2]; + q[3] = ptr[3]; +} + +Quaternion::Quaternion(const Quaternion& other) { + q[0] = other[0]; + q[1] = other[1]; + q[2] = other[2]; + q[3] = other[3]; +} + +Quaternion::~Quaternion() { +} + +bool Quaternion::operator==(const Quaternion& other) const { + return (fabs(other[0] - q[0]) < MINGFX_MATH_EPSILON && + fabs(other[1] - q[1]) < MINGFX_MATH_EPSILON && + fabs(other[2] - q[2]) < MINGFX_MATH_EPSILON && + fabs(other[3] - q[3]) < MINGFX_MATH_EPSILON); +} + +bool Quaternion::operator!=(const Quaternion& other) const { + return (fabs(other[0] - q[0]) >= MINGFX_MATH_EPSILON || + fabs(other[1] - q[1]) >= MINGFX_MATH_EPSILON || + fabs(other[2] - q[2]) >= MINGFX_MATH_EPSILON || + fabs(other[3] - q[3]) >= MINGFX_MATH_EPSILON); +} + +Quaternion& Quaternion::operator=(const Quaternion& other) { + q[0] = other[0]; + q[1] = other[1]; + q[2] = other[2]; + q[3] = other[3]; + return *this; +} + +float Quaternion::operator[](const int i) const { + if ((i>=0) && (i<=3)) { + return q[i]; + } + else { + // this is an error! + return 0.0; + } +} + +float& Quaternion::operator[](const int i) { + return q[i]; +} + + +const float * Quaternion::value_ptr() const { + return q; +} + +Quaternion Quaternion::Slerp(const Quaternion &other, float alpha) const { + // https://en.wikipedia.org/wiki/Slerp + + Quaternion v0 = *this; + Quaternion v1 = other; + + // Only unit quaternions are valid rotations. + // Normalize to avoid undefined behavior. + v0.Normalize(); + v1.Normalize(); + + // Compute the cosine of the angle between the two vectors. + float dot = v0.Dot(v1); + + // If the dot product is negative, the quaternions + // have opposite handed-ness and slerp won't take + // the shorter path. Fix by reversing one quaternion. + if (dot < 0.0f) { + v1 = -v1; + dot = -dot; + } + + const double DOT_THRESHOLD = 0.9995; + if (dot > DOT_THRESHOLD) { + // If the inputs are too close for comfort, linearly interpolate + // and normalize the result. + + Quaternion result = v0 + alpha*(v1 - v0); + result.Normalize(); + return result; + } + + GfxMath::Clamp(dot, -1, 1); // Robustness: Stay within domain of acos() + float theta_0 = GfxMath::acos(dot); // theta_0 = angle between input vectors + float theta = theta_0 * alpha; // theta = angle between v0 and result + + float s0 = GfxMath::cos(theta) - dot + * GfxMath::sin(theta) / GfxMath::sin(theta_0); // == sin(theta_0 - theta) / sin(theta_0) + float s1 = GfxMath::sin(theta) / GfxMath::sin(theta_0); + + return (s0 * v0) + (s1 * v1); +} + +Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float alpha) { + return a.Slerp(b, alpha); +} + + +std::ostream & operator<< ( std::ostream &os, const Quaternion &q) { + return os << "<" << q[0] << ", " << q[1] << ", " << q[2] << ", " << q[3] << ")"; +} + +std::istream & operator>> ( std::istream &is, Quaternion &q) { + // format: + char dummy; + return is >> dummy >> q[0] >> dummy >> q[1] >> dummy >> q[2] >> dummy >> q[3] >> dummy; +} + + +float Quaternion::Dot(const Quaternion& other) const { + return q[0]*other[0] + q[1]*other[1] + q[2]*other[2] + q[3]*other[3]; + +} + +float Quaternion::Length() const { + return sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); +} + +void Quaternion::Normalize() { + float sizeSq = + q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; + if (sizeSq < MINGFX_MATH_EPSILON) { + return; // do nothing to zero quats + } + float scaleFactor = (float)1.0/(float)sqrt(sizeSq); + q[0] *= scaleFactor; + q[1] *= scaleFactor; + q[2] *= scaleFactor; + q[3] *= scaleFactor; +} + +Quaternion Quaternion::ToUnit() const { + Quaternion qtmp(*this); + qtmp.Normalize(); + return qtmp; +} + +/// Returns the conjugate of the quaternion. +Quaternion Quaternion::Conjugate() const { + return Quaternion(-q[0], -q[1], -q[2], q[3]); +} + + +Quaternion Quaternion::FromAxisAngle(const Vector3 &axis, float angle) { + // [qx, qy, qz, qw] = [sin(a/2) * vx, sin(a/2)* vy, sin(a/2) * vz, cos(a/2)] + float x = GfxMath::sin(angle/2.0) * axis[0]; + float y = GfxMath::sin(angle/2.0) * axis[1]; + float z = GfxMath::sin(angle/2.0) * axis[2]; + float w = GfxMath::cos(angle/2.0); + return Quaternion(x,y,z,w); +} + + +Quaternion Quaternion::FromEulerAnglesZYX(const Vector3 &angles) { + Quaternion rot_x = Quaternion::FromAxisAngle(Vector3::UnitX(), angles[0]); + Quaternion rot_y = Quaternion::FromAxisAngle(Vector3::UnitY(), angles[1]); + Quaternion rot_z = Quaternion::FromAxisAngle(Vector3::UnitZ(), angles[2]); + return rot_z * rot_y * rot_x; +} + +Vector3 Quaternion::ToEulerAnglesZYX() const { + // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles + + Vector3 angles; + + // roll (x-axis rotation) + float sinr = +2.0f * (w() * x() + y() * z()); + float cosr = +1.0f - 2.0f * (x() * x() + y() * y()); + angles[0] = std::atan2(sinr, cosr); + + // pitch (y-axis rotation) + float sinp = +2.0f * (w() * y() - z() * x()); + if (std::fabs(sinp) >= 1.f) + angles[1] = std::copysign(GfxMath::HALF_PI, sinp); // use 90 degrees if out of range + else + angles[1] = std::asin(sinp); + + // yaw (z-axis rotation) + float siny = +2.0f * (w() * z() + x() * y()); + float cosy = +1.0f - 2.0f * (y() * y() + z() * z()); + angles[2] = std::atan2(siny, cosy); + + return angles; +} + + +Quaternion operator*(const Quaternion& q1, const Quaternion& q2) { + float real1 = q1[3]; + Vector3 imag1 = Vector3(q1[0], q1[1], q1[2]); + + float real2 = q2[3]; + Vector3 imag2 = Vector3(q2[0], q2[1], q2[2]); + + float real = real1*real2 - imag1.Dot(imag2); + Vector3 imag = real1*imag2 + real2*imag1 + imag1.Cross(imag2); + + return Quaternion(imag[0], imag[1], imag[2], real); +} + + +Quaternion operator/(const Quaternion& q, const float s) { + const float invS = 1.0f / s; + return Quaternion(q[0]*invS, q[1]*invS, q[2]*invS, q[3]*invS); +} + +Quaternion operator*(const float s, const Quaternion& q) { + return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s); +} + +Quaternion operator*(const Quaternion& q, const float s) { + return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s); +} + +Quaternion operator-(const Quaternion& q) { + return Quaternion(-q[0], -q[1], -q[2], -q[3]); +} + +Quaternion operator+(const Quaternion& q1, const Quaternion& q2) { + return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]); +} + +Quaternion operator-(const Quaternion& q1, const Quaternion& q2) { + return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]); +} + +} // end namespace diff --git a/dev/MinGfx/src/quick_shapes.cc b/dev/MinGfx/src/quick_shapes.cc index 01f187a..e0e6888 100644 --- a/dev/MinGfx/src/quick_shapes.cc +++ b/dev/MinGfx/src/quick_shapes.cc @@ -1,733 +1,733 @@ -/* - Copyright (c) 2017,2018 Regents of the University of Minnesota. - All Rights Reserved. - See corresponding header file for details. - */ - -#include "quick_shapes.h" -#include "platform.h" - -#include -#include -#include - -#include "gfxmath.h" - -namespace mingfx { - - - -#define PI 3.14159265359f -#define TWOPI 6.28318530718f - - - -// Helper datastructure for building shapes algorithmically -class Vertex { -public: - Vertex(GLfloat xx, GLfloat yy, GLfloat zz, GLfloat nnx, GLfloat nny, GLfloat nnz) : - x(xx), y(yy), z(zz), nx(nnx), ny(nny), nz(nnz) {} - - GLfloat x; - GLfloat y; - GLfloat z; - GLfloat nx; - GLfloat ny; - GLfloat nz; -}; - - - - -QuickShapes::QuickShapes() { -} - -QuickShapes::~QuickShapes() { -} - - - - -// ------------ CUBE ------------ - - -void QuickShapes::initCube() { - GLfloat vertices[] = { - 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,-1.0f, 1.0f, // v0-v1-v2 (front) - -1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v2-v3-v0 - - 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f,-1.0f, // v0-v3-v4 (right) - 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, // v4-v5-v0 - - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v0-v5-v6 (top) - -1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v6-v1-v0 - - -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, -1.0f,-1.0f,-1.0f, // v1-v6-v7 (left) - -1.0f,-1.0f,-1.0f, -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // v7-v2-v1.0 - - -1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f, 1.0f, // v7-v4-v3 (bottom) - 1.0f,-1.0f, 1.0f, -1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, // v3-v2-v7 - - 1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v4-v7-v6 (back) - -1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f // v6-v5-v4 - }; - - GLfloat normals[] = { - 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2 (front) - 0, 0, 1, 0, 0, 1, 0, 0, 1, // v2-v3-v0 - - 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4 (right) - 1, 0, 0, 1, 0, 0, 1, 0, 0, // v4-v5-v0 - - 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6 (top) - 0, 1, 0, 0, 1, 0, 0, 1, 0, // v6-v1-v0 - - -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7 (left) - -1, 0, 0, -1, 0, 0, -1, 0, 0, // v7-v2-v1 - - 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3 (bottom) - 0,-1, 0, 0,-1, 0, 0,-1, 0, // v3-v2-v7 - - 0, 0,-1, 0, 0,-1, 0, 0,-1, // v4-v7-v6 (back) - 0, 0,-1, 0, 0,-1, 0, 0,-1 // v6-v5-v4 - }; - - cubeMesh_.SetVertices(vertices, 36); - cubeMesh_.SetNormals(normals, 36); - cubeMesh_.UpdateGPUMemory(); -} - - -void QuickShapes::DrawCube(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color) -{ - if (cubeMesh_.num_vertices() == 0) { - initCube(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = emptyTex_; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &cubeMesh_, defaultMaterial_); -} - - - - -// ------------ SQUARE ------------ - - -void QuickShapes::initSquare() { - GLfloat vertices[] = { - 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 0.0f,-1.0f, // v0-v5-v6 (top) - -1.0f, 0.0f,-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f // v6-v1-v0 - }; - - GLfloat normals[] = { - 0, 1, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 0 - }; - - GLfloat texcoords[] = { - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f - }; - - squareMesh_.SetVertices(vertices, 6); - squareMesh_.SetNormals(normals, 6); - squareMesh_.SetTexCoords(0, texcoords, 6); - squareMesh_.UpdateGPUMemory(); -} - - -void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color) -{ - if (squareMesh_.num_vertices() == 0) { - initSquare(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = emptyTex_; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); -} - - -void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color, - const Texture2D &tex) -{ - if (squareMesh_.num_vertices() == 0) { - initSquare(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = tex; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); -} - - - - - -// ------------ CYLINDER ------------ - - -void QuickShapes::initCyl() { - - std::vector verts; - - Vertex top(0,1,0, 0,1,0); - Vertex bot(0,-1,0, 0,-1,0); - - const int nslices = 20; - for (int s=1; s vertices; - std::vector normals; - for (int i=0; i verts; - - Vertex top(0,1,0, 0,1,0); - Vertex bot(0,-1,0, 0,-1,0); - - const int nslices = 20; - for (int s=1; s vertices; - std::vector normals; - for (int i = 0; i < verts.size(); i++) { - vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); - normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); - } - - coneMesh_.SetVertices(vertices); - coneMesh_.SetNormals(normals); - coneMesh_.UpdateGPUMemory(); -} - - -void QuickShapes::DrawCone(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color) -{ - if (coneMesh_.num_vertices() == 0) { - initCone(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = emptyTex_; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &coneMesh_, defaultMaterial_); -} - - - - - -// ------------ SPHERE ------------ - - -void QuickShapes::initSph() { - - std::vector verts; - - Vertex top(0,1,0, 0,1,0); - Vertex bot(0,-1,0, 0,-1,0); - - const int nslices = 40; - const int nstacks = 40; - for (int s=1; s vertices; - std::vector normals; - for (int i = 0; i < verts.size(); i++) { - vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); - normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); - } - sphereMesh_.SetVertices(vertices); - sphereMesh_.SetNormals(normals); - sphereMesh_.UpdateGPUMemory(); -} - - -void QuickShapes::DrawSphere(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color) -{ - if (sphereMesh_.num_vertices() == 0) { - initSph(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = emptyTex_; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &sphereMesh_, defaultMaterial_); -} - - - - -// ------------ BRUSH ------------ - - -void QuickShapes::initBrush() { - - // Raw vertices -- points that make up the brush geometry - const GLfloat v[19][3] = { - { 0.5f, 0.0f, 0.0f}, // 0 - {-0.5f, 0.0f, 0.0f}, // 1 - - { 0.5f, 0.1f, 0.25f}, // 2 - {-0.5f, 0.1f, 0.25f}, // 3 - { 0.5f, 0.1f, 0.75f}, // 4 - {-0.5f, 0.1f, 0.75f}, // 5 - { 0.1f, 0.06f, 1.0f}, // 6 - {-0.1f, 0.06f, 1.0f}, // 7 - { 0.15f, 0.1f, 1.75f}, // 8 - {-0.15f, 0.1f, 1.75f}, // 9 - - { 0.0f, 0.0f, 1.85f}, // 10 - - { 0.5f, -0.1f, 0.25f}, // 11 - {-0.5f, -0.1f, 0.25f}, // 12 - { 0.5f, -0.1f, 0.75f}, // 13 - {-0.5f, -0.1f, 0.75f}, // 14 - { 0.1f, -0.06f, 1.0f}, // 15 - {-0.1f, -0.06f, 1.0f}, // 16 - { 0.15f, -0.1f, 1.75f}, // 17 - {-0.15f, -0.1f, 1.75f} // 18 - }; - - - // Vertices arranged into triangles - const GLfloat verts[34][3][3] = { - // top - {{v[0][0], v[0][1], v[0][2]}, {v[1][0], v[1][1], v[1][2]}, {v[2][0], v[2][1], v[2][2]}}, - {{v[1][0], v[1][1], v[1][2]}, {v[3][0], v[3][1], v[3][2]}, {v[2][0], v[2][1], v[2][2]}}, - - {{v[2][0], v[2][1], v[2][2]}, {v[3][0], v[3][1], v[3][2]}, {v[4][0], v[4][1], v[4][2]}}, - {{v[3][0], v[3][1], v[3][2]}, {v[5][0], v[5][1], v[5][2]}, {v[4][0], v[4][1], v[4][2]}}, - - {{v[4][0], v[4][1], v[4][2]}, {v[5][0], v[5][1], v[5][2]}, {v[6][0], v[6][1], v[6][2]}}, - {{v[5][0], v[5][1], v[5][2]}, {v[7][0], v[7][1], v[7][2]}, {v[6][0], v[6][1], v[6][2]}}, - - {{v[6][0], v[6][1], v[6][2]}, {v[7][0], v[7][1], v[7][2]}, {v[8][0], v[8][1], v[8][2]}}, - {{v[7][0], v[7][1], v[7][2]}, {v[9][0], v[9][1], v[9][2]}, {v[8][0], v[8][1], v[8][2]}}, - - {{v[8][0], v[8][1], v[8][2]}, {v[9][0], v[9][1], v[9][2]}, {v[10][0], v[10][1], v[10][2]}}, - - // bottom - {{v[0][0], v[0][1], v[0][2]}, {v[12][0], v[12][1], v[12][2]}, {v[1][0], v[1][1], v[1][2]}}, - {{v[11][0], v[11][1], v[11][2]}, {v[12][0], v[12][1], v[12][2]}, {v[0][0], v[0][1], v[0][2]}}, - - {{v[11][0], v[11][1], v[11][2]}, {v[14][0], v[14][1], v[14][2]}, {v[12][0], v[12][1], v[12][2]}}, - {{v[13][0], v[13][1], v[13][2]}, {v[14][0], v[14][1], v[14][2]}, {v[11][0], v[11][1], v[11][2]}}, - - {{v[13][0], v[13][1], v[13][2]}, {v[16][0], v[16][1], v[16][2]}, {v[14][0], v[14][1], v[14][2]}}, - {{v[15][0], v[15][1], v[15][2]}, {v[16][0], v[16][1], v[16][2]}, {v[13][0], v[13][1], v[13][2]}}, - - {{v[15][0], v[15][1], v[15][2]}, {v[18][0], v[18][1], v[18][2]}, {v[16][0], v[16][1], v[16][2]}}, - {{v[17][0], v[17][1], v[17][2]}, {v[18][0], v[18][1], v[18][2]}, {v[15][0], v[15][1], v[15][2]}}, - - {{v[18][0], v[18][1], v[18][2]}, {v[17][0], v[17][1], v[17][2]}, {v[10][0], v[10][1], v[10][2]}}, - - // one side - {{v[11][0], v[11][1], v[11][2]}, {v[0][0], v[0][1], v[0][2]}, {v[2][0], v[2][1], v[2][2]}}, - - {{v[11][0], v[11][1], v[11][2]}, {v[2][0], v[2][1], v[2][2]}, {v[4][0], v[4][1], v[4][2]}}, - {{v[4][0], v[4][1], v[4][2]}, {v[13][0], v[13][1], v[13][2]}, {v[11][0], v[11][1], v[11][2]}}, - - {{v[13][0], v[13][1], v[13][2]}, {v[4][0], v[4][1], v[4][2]}, {v[6][0], v[6][1], v[6][2]}}, - {{v[6][0], v[6][1], v[6][2]}, {v[15][0], v[15][1], v[15][2]}, {v[13][0], v[13][1], v[13][2]}}, - - {{v[15][0], v[15][1], v[15][2]}, {v[6][0], v[6][1], v[6][2]}, {v[8][0], v[8][1], v[8][2]}}, - {{v[8][0], v[8][1], v[8][2]}, {v[17][0], v[17][1], v[17][2]}, {v[15][0], v[15][1], v[15][2]}}, - - {{v[17][0], v[17][1], v[17][2]}, {v[8][0], v[8][1], v[8][2]}, {v[10][0], v[10][1], v[10][2]}}, - - // other side - {{v[3][0], v[3][1], v[3][2]}, {v[1][0], v[1][1], v[1][2]}, {v[12][0], v[12][1], v[12][2]}}, - - {{v[3][0], v[3][1], v[3][2]}, {v[12][0], v[12][1], v[12][2]}, {v[14][0], v[14][1], v[14][2]}}, - {{v[14][0], v[14][1], v[14][2]}, {v[5][0], v[5][1], v[5][2]}, {v[3][0], v[3][1], v[3][2]}}, - - {{v[5][0], v[5][1], v[5][2]}, {v[14][0], v[14][1], v[14][2]}, {v[16][0], v[16][1], v[16][2]}}, - {{v[16][0], v[16][1], v[16][2]}, {v[7][0], v[7][1], v[7][2]}, {v[5][0], v[5][1], v[5][2]}}, - - {{v[7][0], v[7][1], v[7][2]}, {v[16][0], v[16][1], v[16][2]}, {v[18][0], v[18][1], v[18][2]}}, - {{v[18][0], v[18][1], v[18][2]}, {v[9][0], v[9][1], v[9][2]}, {v[7][0], v[7][1], v[7][2]}}, - - {{v[9][0], v[9][1], v[9][2]}, {v[18][0], v[18][1], v[18][2]}, {v[10][0], v[10][1], v[10][2]}} - - }; - - - // Normals defined so as to make each face of the brush a flat surface - const GLfloat norms[34][3][3] = { - // top - {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, - {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, - - {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, - {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, - - {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, - {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, - - {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, - {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, - - {{0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}}, - - // bottom - {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, - {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, - - {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, - {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, - - {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, - {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, - - {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, - {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, - - {{0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}}, - - // one side - {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, - - {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, - {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, - - {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, - {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, - - {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, - {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, - - {{0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}}, - - // other side - {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, - - {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, - {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, - - {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, - {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, - - {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, - {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, - - {{-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}} - }; - - brushMesh_.SetVertices((float*)verts, 102); - brushMesh_.SetNormals((float*)norms, 102); - brushMesh_.UpdateGPUMemory(); -} - - -void QuickShapes::DrawBrush(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, const Color &color) -{ - if (brushMesh_.num_vertices() == 0) { - initBrush(); - } - defaultMaterial_.ambient_reflectance = color; - defaultMaterial_.diffuse_reflectance = color; - defaultMaterial_.surface_texture = emptyTex_; - defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &brushMesh_, defaultMaterial_); -} - - - -// ---------------- - - -void QuickShapes::DrawLineSegment(const Matrix4 &modelMatrix, - const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, - const Color &color, - const Point3 &p1, - const Point3 &p2, - float radius) -{ - Matrix4 S = Matrix4::Scale(Vector3(radius, 0.5f*(p2-p1).Length(), radius)); - Vector3 y = (p2-p1).ToUnit(); - Vector3 z = Vector3(1,0,0).Cross(y).ToUnit(); - if (z == Vector3(0,0,0)) { - z = Vector3(0,0,1).Cross(y).ToUnit(); - } - Vector3 x = y.Cross(z); - Matrix4 R = Matrix4::FromRowMajorElements( - x[0], y[0], z[0], 0, - x[1], y[1], z[1], 0, - x[2], y[2], z[2], 0, - 0, 0, 0, 1 - ); - Matrix4 T = Matrix4::Translation(0.5 * Vector3(p1[0]+p2[0], p1[1]+p2[1], p1[2]+p2[2])); - - Matrix4 M = T * R * S; - - DrawCylinder(modelMatrix * M, viewMatrix, projectionMatrix, color); -} - - - -void QuickShapes::DrawLines(const Matrix4 &modelMatrix, - const Matrix4 &viewMatrix, - const Matrix4 &projectionMatrix, - const Color &color, - const std::vector &points, - LinesType ltype, - float radius) -{ - if (ltype == LinesType::LINES) { - for (size_t i=0; iDraw(); - - // Deactivate the shader program - fullscreenShader_.StopProgram(); - - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); -} - - -DefaultShader* QuickShapes::default_shader() { - return &defaultShader_; -} - - -DefaultShader::MaterialProperties* QuickShapes::material() { - return &defaultMaterial_; -} - - -} // end namespace +/* + Copyright (c) 2017,2018 Regents of the University of Minnesota. + All Rights Reserved. + See corresponding header file for details. + */ + +#include "quick_shapes.h" +#include "platform.h" + +#include +#include +#include + +#include "gfxmath.h" + +namespace mingfx { + + + +#define PI 3.14159265359f +#define TWOPI 6.28318530718f + + + +// Helper datastructure for building shapes algorithmically +class Vertex { +public: + Vertex(GLfloat xx, GLfloat yy, GLfloat zz, GLfloat nnx, GLfloat nny, GLfloat nnz) : + x(xx), y(yy), z(zz), nx(nnx), ny(nny), nz(nnz) {} + + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat nx; + GLfloat ny; + GLfloat nz; +}; + + + + +QuickShapes::QuickShapes() { +} + +QuickShapes::~QuickShapes() { +} + + + + +// ------------ CUBE ------------ + + +void QuickShapes::initCube() { + GLfloat vertices[] = { + 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,-1.0f, 1.0f, // v0-v1-v2 (front) + -1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v2-v3-v0 + + 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f,-1.0f, // v0-v3-v4 (right) + 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, // v4-v5-v0 + + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v0-v5-v6 (top) + -1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v6-v1-v0 + + -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, -1.0f,-1.0f,-1.0f, // v1-v6-v7 (left) + -1.0f,-1.0f,-1.0f, -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // v7-v2-v1.0 + + -1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f, 1.0f, // v7-v4-v3 (bottom) + 1.0f,-1.0f, 1.0f, -1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, // v3-v2-v7 + + 1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v4-v7-v6 (back) + -1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f // v6-v5-v4 + }; + + GLfloat normals[] = { + 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2 (front) + 0, 0, 1, 0, 0, 1, 0, 0, 1, // v2-v3-v0 + + 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4 (right) + 1, 0, 0, 1, 0, 0, 1, 0, 0, // v4-v5-v0 + + 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6 (top) + 0, 1, 0, 0, 1, 0, 0, 1, 0, // v6-v1-v0 + + -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7 (left) + -1, 0, 0, -1, 0, 0, -1, 0, 0, // v7-v2-v1 + + 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3 (bottom) + 0,-1, 0, 0,-1, 0, 0,-1, 0, // v3-v2-v7 + + 0, 0,-1, 0, 0,-1, 0, 0,-1, // v4-v7-v6 (back) + 0, 0,-1, 0, 0,-1, 0, 0,-1 // v6-v5-v4 + }; + + cubeMesh_.SetVertices(vertices, 36); + cubeMesh_.SetNormals(normals, 36); + cubeMesh_.UpdateGPUMemory(); +} + + +void QuickShapes::DrawCube(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color) +{ + if (cubeMesh_.num_vertices() == 0) { + initCube(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = emptyTex_; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &cubeMesh_, defaultMaterial_); +} + + + + +// ------------ SQUARE ------------ + + +void QuickShapes::initSquare() { + GLfloat vertices[] = { + 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 0.0f,-1.0f, // v0-v5-v6 (top) + -1.0f, 0.0f,-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f // v6-v1-v0 + }; + + GLfloat normals[] = { + 0, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 1, 0 + }; + + GLfloat texcoords[] = { + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f + }; + + squareMesh_.SetVertices(vertices, 6); + squareMesh_.SetNormals(normals, 6); + squareMesh_.SetTexCoords(0, texcoords, 6); + squareMesh_.UpdateGPUMemory(); +} + + +void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color) +{ + if (squareMesh_.num_vertices() == 0) { + initSquare(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = emptyTex_; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); +} + + +void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color, + const Texture2D &tex) +{ + if (squareMesh_.num_vertices() == 0) { + initSquare(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = tex; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); +} + + + + + +// ------------ CYLINDER ------------ + + +void QuickShapes::initCyl() { + + std::vector verts; + + Vertex top(0,1,0, 0,1,0); + Vertex bot(0,-1,0, 0,-1,0); + + const int nslices = 20; + for (int s=1; s vertices; + std::vector normals; + for (int i=0; i verts; + + Vertex top(0,1,0, 0,1,0); + Vertex bot(0,-1,0, 0,-1,0); + + const int nslices = 20; + for (int s=1; s vertices; + std::vector normals; + for (int i = 0; i < verts.size(); i++) { + vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); + normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); + } + + coneMesh_.SetVertices(vertices); + coneMesh_.SetNormals(normals); + coneMesh_.UpdateGPUMemory(); +} + + +void QuickShapes::DrawCone(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color) +{ + if (coneMesh_.num_vertices() == 0) { + initCone(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = emptyTex_; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &coneMesh_, defaultMaterial_); +} + + + + + +// ------------ SPHERE ------------ + + +void QuickShapes::initSph() { + + std::vector verts; + + Vertex top(0,1,0, 0,1,0); + Vertex bot(0,-1,0, 0,-1,0); + + const int nslices = 40; + const int nstacks = 40; + for (int s=1; s vertices; + std::vector normals; + for (int i = 0; i < verts.size(); i++) { + vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); + normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); + } + sphereMesh_.SetVertices(vertices); + sphereMesh_.SetNormals(normals); + sphereMesh_.UpdateGPUMemory(); +} + + +void QuickShapes::DrawSphere(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color) +{ + if (sphereMesh_.num_vertices() == 0) { + initSph(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = emptyTex_; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &sphereMesh_, defaultMaterial_); +} + + + + +// ------------ BRUSH ------------ + + +void QuickShapes::initBrush() { + + // Raw vertices -- points that make up the brush geometry + const GLfloat v[19][3] = { + { 0.5f, 0.0f, 0.0f}, // 0 + {-0.5f, 0.0f, 0.0f}, // 1 + + { 0.5f, 0.1f, 0.25f}, // 2 + {-0.5f, 0.1f, 0.25f}, // 3 + { 0.5f, 0.1f, 0.75f}, // 4 + {-0.5f, 0.1f, 0.75f}, // 5 + { 0.1f, 0.06f, 1.0f}, // 6 + {-0.1f, 0.06f, 1.0f}, // 7 + { 0.15f, 0.1f, 1.75f}, // 8 + {-0.15f, 0.1f, 1.75f}, // 9 + + { 0.0f, 0.0f, 1.85f}, // 10 + + { 0.5f, -0.1f, 0.25f}, // 11 + {-0.5f, -0.1f, 0.25f}, // 12 + { 0.5f, -0.1f, 0.75f}, // 13 + {-0.5f, -0.1f, 0.75f}, // 14 + { 0.1f, -0.06f, 1.0f}, // 15 + {-0.1f, -0.06f, 1.0f}, // 16 + { 0.15f, -0.1f, 1.75f}, // 17 + {-0.15f, -0.1f, 1.75f} // 18 + }; + + + // Vertices arranged into triangles + const GLfloat verts[34][3][3] = { + // top + {{v[0][0], v[0][1], v[0][2]}, {v[1][0], v[1][1], v[1][2]}, {v[2][0], v[2][1], v[2][2]}}, + {{v[1][0], v[1][1], v[1][2]}, {v[3][0], v[3][1], v[3][2]}, {v[2][0], v[2][1], v[2][2]}}, + + {{v[2][0], v[2][1], v[2][2]}, {v[3][0], v[3][1], v[3][2]}, {v[4][0], v[4][1], v[4][2]}}, + {{v[3][0], v[3][1], v[3][2]}, {v[5][0], v[5][1], v[5][2]}, {v[4][0], v[4][1], v[4][2]}}, + + {{v[4][0], v[4][1], v[4][2]}, {v[5][0], v[5][1], v[5][2]}, {v[6][0], v[6][1], v[6][2]}}, + {{v[5][0], v[5][1], v[5][2]}, {v[7][0], v[7][1], v[7][2]}, {v[6][0], v[6][1], v[6][2]}}, + + {{v[6][0], v[6][1], v[6][2]}, {v[7][0], v[7][1], v[7][2]}, {v[8][0], v[8][1], v[8][2]}}, + {{v[7][0], v[7][1], v[7][2]}, {v[9][0], v[9][1], v[9][2]}, {v[8][0], v[8][1], v[8][2]}}, + + {{v[8][0], v[8][1], v[8][2]}, {v[9][0], v[9][1], v[9][2]}, {v[10][0], v[10][1], v[10][2]}}, + + // bottom + {{v[0][0], v[0][1], v[0][2]}, {v[12][0], v[12][1], v[12][2]}, {v[1][0], v[1][1], v[1][2]}}, + {{v[11][0], v[11][1], v[11][2]}, {v[12][0], v[12][1], v[12][2]}, {v[0][0], v[0][1], v[0][2]}}, + + {{v[11][0], v[11][1], v[11][2]}, {v[14][0], v[14][1], v[14][2]}, {v[12][0], v[12][1], v[12][2]}}, + {{v[13][0], v[13][1], v[13][2]}, {v[14][0], v[14][1], v[14][2]}, {v[11][0], v[11][1], v[11][2]}}, + + {{v[13][0], v[13][1], v[13][2]}, {v[16][0], v[16][1], v[16][2]}, {v[14][0], v[14][1], v[14][2]}}, + {{v[15][0], v[15][1], v[15][2]}, {v[16][0], v[16][1], v[16][2]}, {v[13][0], v[13][1], v[13][2]}}, + + {{v[15][0], v[15][1], v[15][2]}, {v[18][0], v[18][1], v[18][2]}, {v[16][0], v[16][1], v[16][2]}}, + {{v[17][0], v[17][1], v[17][2]}, {v[18][0], v[18][1], v[18][2]}, {v[15][0], v[15][1], v[15][2]}}, + + {{v[18][0], v[18][1], v[18][2]}, {v[17][0], v[17][1], v[17][2]}, {v[10][0], v[10][1], v[10][2]}}, + + // one side + {{v[11][0], v[11][1], v[11][2]}, {v[0][0], v[0][1], v[0][2]}, {v[2][0], v[2][1], v[2][2]}}, + + {{v[11][0], v[11][1], v[11][2]}, {v[2][0], v[2][1], v[2][2]}, {v[4][0], v[4][1], v[4][2]}}, + {{v[4][0], v[4][1], v[4][2]}, {v[13][0], v[13][1], v[13][2]}, {v[11][0], v[11][1], v[11][2]}}, + + {{v[13][0], v[13][1], v[13][2]}, {v[4][0], v[4][1], v[4][2]}, {v[6][0], v[6][1], v[6][2]}}, + {{v[6][0], v[6][1], v[6][2]}, {v[15][0], v[15][1], v[15][2]}, {v[13][0], v[13][1], v[13][2]}}, + + {{v[15][0], v[15][1], v[15][2]}, {v[6][0], v[6][1], v[6][2]}, {v[8][0], v[8][1], v[8][2]}}, + {{v[8][0], v[8][1], v[8][2]}, {v[17][0], v[17][1], v[17][2]}, {v[15][0], v[15][1], v[15][2]}}, + + {{v[17][0], v[17][1], v[17][2]}, {v[8][0], v[8][1], v[8][2]}, {v[10][0], v[10][1], v[10][2]}}, + + // other side + {{v[3][0], v[3][1], v[3][2]}, {v[1][0], v[1][1], v[1][2]}, {v[12][0], v[12][1], v[12][2]}}, + + {{v[3][0], v[3][1], v[3][2]}, {v[12][0], v[12][1], v[12][2]}, {v[14][0], v[14][1], v[14][2]}}, + {{v[14][0], v[14][1], v[14][2]}, {v[5][0], v[5][1], v[5][2]}, {v[3][0], v[3][1], v[3][2]}}, + + {{v[5][0], v[5][1], v[5][2]}, {v[14][0], v[14][1], v[14][2]}, {v[16][0], v[16][1], v[16][2]}}, + {{v[16][0], v[16][1], v[16][2]}, {v[7][0], v[7][1], v[7][2]}, {v[5][0], v[5][1], v[5][2]}}, + + {{v[7][0], v[7][1], v[7][2]}, {v[16][0], v[16][1], v[16][2]}, {v[18][0], v[18][1], v[18][2]}}, + {{v[18][0], v[18][1], v[18][2]}, {v[9][0], v[9][1], v[9][2]}, {v[7][0], v[7][1], v[7][2]}}, + + {{v[9][0], v[9][1], v[9][2]}, {v[18][0], v[18][1], v[18][2]}, {v[10][0], v[10][1], v[10][2]}} + + }; + + + // Normals defined so as to make each face of the brush a flat surface + const GLfloat norms[34][3][3] = { + // top + {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, + {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, + + {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, + {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, + + {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, + {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, + + {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, + {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, + + {{0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}}, + + // bottom + {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, + {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, + + {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, + {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, + + {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, + {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, + + {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, + {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, + + {{0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}}, + + // one side + {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + + {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + + {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, + {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, + + {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + + {{0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}}, + + // other side + {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, + + {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, + {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, + + {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, + {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, + + {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, + {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, + + {{-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}} + }; + + brushMesh_.SetVertices((float*)verts, 102); + brushMesh_.SetNormals((float*)norms, 102); + brushMesh_.UpdateGPUMemory(); +} + + +void QuickShapes::DrawBrush(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, const Color &color) +{ + if (brushMesh_.num_vertices() == 0) { + initBrush(); + } + defaultMaterial_.ambient_reflectance = color; + defaultMaterial_.diffuse_reflectance = color; + defaultMaterial_.surface_texture = emptyTex_; + defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &brushMesh_, defaultMaterial_); +} + + + +// ---------------- + + +void QuickShapes::DrawLineSegment(const Matrix4 &modelMatrix, + const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, + const Color &color, + const Point3 &p1, + const Point3 &p2, + float radius) +{ + Matrix4 S = Matrix4::Scale(Vector3(radius, 0.5f*(p2-p1).Length(), radius)); + Vector3 y = (p2-p1).ToUnit(); + Vector3 z = Vector3(1,0,0).Cross(y).ToUnit(); + if (z == Vector3(0,0,0)) { + z = Vector3(0,0,1).Cross(y).ToUnit(); + } + Vector3 x = y.Cross(z); + Matrix4 R = Matrix4::FromRowMajorElements( + x[0], y[0], z[0], 0, + x[1], y[1], z[1], 0, + x[2], y[2], z[2], 0, + 0, 0, 0, 1 + ); + Matrix4 T = Matrix4::Translation(0.5 * Vector3(p1[0]+p2[0], p1[1]+p2[1], p1[2]+p2[2])); + + Matrix4 M = T * R * S; + + DrawCylinder(modelMatrix * M, viewMatrix, projectionMatrix, color); +} + + + +void QuickShapes::DrawLines(const Matrix4 &modelMatrix, + const Matrix4 &viewMatrix, + const Matrix4 &projectionMatrix, + const Color &color, + const std::vector &points, + LinesType ltype, + float radius) +{ + if (ltype == LinesType::LINES) { + for (size_t i=0; iDraw(); + + // Deactivate the shader program + fullscreenShader_.StopProgram(); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); +} + + +DefaultShader* QuickShapes::default_shader() { + return &defaultShader_; +} + + +DefaultShader::MaterialProperties* QuickShapes::material() { + return &defaultMaterial_; +} + + +} // end namespace diff --git a/dev/MinGfx/src/ray.h b/dev/MinGfx/src/ray.h index d1b41b6..4bc3a8c 100644 --- a/dev/MinGfx/src/ray.h +++ b/dev/MinGfx/src/ray.h @@ -1,166 +1,166 @@ -/* - This file is part of the MinGfx Project. - - Copyright (c) 2017,2018 Regents of the University of Minnesota. - All Rights Reserved. - - Original Author(s) of this File: - Dan Keefe, 2018, University of Minnesota - - Author(s) of Significant Updates/Modifications to the File: - ... - */ - -#ifndef SRC_RAY_H_ -#define SRC_RAY_H_ - -#include - -#include "aabb.h" -#include "point3.h" -#include "vector3.h" -#include "mesh.h" - - -namespace mingfx { - - -/** Stores the mathematical object of a ray that begins at an origin (a 3D - point) and points in a direction (a unit 3D vector). Rays can intersect - a variety of other computer graphics objects, such as planes, triangles, - spheres, 3D meshes, etc. These intersections can be tested with the - Intersect...() methods. The Ray can also be transformed by a Matrix4. - Example: - ~~~ - // Create a pick ray from the mouse position - void MyGraphicsApp::OnLeftMouseDown(const Point2 &mouse_in_2d_pixels) { - Point2 mouse_in_2d_ndc = PixelsToNormalizedDeviceCoords(mouse_in_2d_pixels); - Point3 mouse_in_3d = GfxMath::ScreenToNearPlane(view_matrix, proj_matrix, mouse_in_2d_ndc); - Matrix4 camera_matrix = view_matrix.Inverse(); - Point3 eye = camera_matrix.ColumnToPoint3(3); - - Ray pick_ray(eye, mouse_in_3d - eye); - - // check to see if the ray intersects a sphere - float t; - Point3 p; - if (pick_ray.IntersectSphere(Point3(0,0,0), 2.0, &t, &p)) { - std::cout << "Mouse pointing at sphere! Intersection point = " << p << std::endl; - } - } - ~~~ - */ -class Ray { -public: - - /// Defaults to a ray at the origin and pointing in the -Z direction - Ray(); - - /// Creates a ray from a 3D origin and direction - Ray(const Point3 &origin, const Vector3 &direction); - - /// Ray destructor - virtual ~Ray(); - - /// Check for "equality", taking floating point imprecision into account - bool operator==(const Ray& other) const; - - /// Check for "inequality", taking floating point imprecision into account - bool operator!=(const Ray& other) const; - - /// Returns the length of the direction vector - float Length() const; - - /** Checks to see if the ray intersects a plane defined by a point and a normal. - If there was an intersection, true is returned, iTime is set to the intersection - time, and iPoint is set to the intersection point. The plane is considered - to be 1-sided. That is the intersection will only occur if the ray hits the - plane from its front side as determined by the plane's normal. - */ - bool IntersectPlane(const Point3 &planePt, const Vector3 &planeNormal, - float *iTime, Point3 *iPoint) const; - - /** Checks to see if the ray intersects a triangle defined by the vertices v1, v2, and v3. - The vertices must be provided in counter-clockwise order so that the normal of the - triangle can be determined via the right-hand rule. The intersection will only happen - if the ray hits the front side of the triangle. If there was an intersection, - true is returned, iTime is set to the intersection time, and iPoint is set to the intersection point. - */ - bool IntersectTriangle(const Point3 &v1, const Point3 &v2, const Point3 &v3, - float *iTime, Point3 *iPoint) const; - - /** Checks to see if the ray intersects a quad defined by the vertices v1, v2, v3, and v4. - The vertices must be provided in counter-clockwise order so that the normal of the - triangle can be determined via the right-hand rule. The intersection will only happen - if the ray hits the front side of the triangle. If there was an intersection, - true is returned, iTime is set to the intersection time, and iPoint is set to the intersection point. - */ - bool IntersectQuad(const Point3 &v1, const Point3 &v2, const Point3 &v3, const Point3 &v4, - float *iTime, Point3 *iPoint) const; - - /** Checks to see if the ray intersects a sphere defined by a center point and a radius. - If there was an intersection, true is returned, iTime is set to the intersection time, - and iPoint is set to the intersection point. - */ - bool IntersectSphere(const Point3 ¢er, float radius, - float *iTime, Point3 *iPoint) const; - - /** Checks to see if the ray intersects a triangle mesh. This is a brute-force - check over each triangle in the mesh. If there was an intersection, true is returned, - iTime is set to the intersection time, iPoint is set to the intersection point, - and iTriangleID is set to the ID of the closest intersected triangle along the ray. - */ - bool IntersectMesh(const Mesh &mesh, float *iTime, - Point3 *iPoint, int *iTriangleID) const; - - /** Checks to see if the ray intersects a triangle mesh. This uses a BVH - (Bounding Volume Hierarchy) to accelerate the ray-triangle intersection tests. - Each mesh can optionally store a BVH. If a BVH has already been calculated - for the mesh (done with Mesh::CalculateBVH()), then this function will be - much faster than the brute-force IntersectMesh() function. If a BVH has - not already been calculated for the mesh, the first call to FastIntersectMesh() - will trigger the mesh to create a BVH (not a fast operation) but then - subsequent calls to FastIntersectMesh() will be fast. - */ - bool FastIntersectMesh(Mesh *mesh, float *iTime, - Point3 *iPoint, int *iTriangleID) const; - - /** Checks to see if the ray intersects an AABB (Axis-Aligned Bounding Box). - Typically, this is the first step of a more detailed intersection test and - we don't care about the actual point of intersection, just whether it - intersects or not. So, we don't bother calculating the iPoint. We get the - iTime for free though, so we do return that. You can calc the iPoint if - you want using: - ~~~ - float t; - if (ray.IntersectAABB(box, &t)) { - Point3 iPoint = ray.origin() + t*ray.direction(); - } - ~~~ - */ - bool IntersectAABB(const AABB &box, float *iTime) const; - - /// Returns the origin - Point3 origin() const; - - /// Returns the direction - Vector3 direction() const; - - /// Sets a new origin and direction - void set(Point3 newOrigin, Vector3 newDir); - -private: - Point3 p_; - Vector3 d_; -}; - - -// --- Stream operators --- - -std::ostream & operator<< ( std::ostream &os, const Ray &r); -std::istream & operator>> ( std::istream &is, Ray &r); - - -} // end namespace - -#endif +/* + This file is part of the MinGfx Project. + + Copyright (c) 2017,2018 Regents of the University of Minnesota. + All Rights Reserved. + + Original Author(s) of this File: + Dan Keefe, 2018, University of Minnesota + + Author(s) of Significant Updates/Modifications to the File: + ... + */ + +#ifndef SRC_RAY_H_ +#define SRC_RAY_H_ + +#include + +#include "aabb.h" +#include "point3.h" +#include "vector3.h" +#include "mesh.h" + + +namespace mingfx { + + +/** Stores the mathematical object of a ray that begins at an origin (a 3D + point) and points in a direction (a unit 3D vector). Rays can intersect + a variety of other computer graphics objects, such as planes, triangles, + spheres, 3D meshes, etc. These intersections can be tested with the + Intersect...() methods. The Ray can also be transformed by a Matrix4. + Example: + ~~~ + // Create a pick ray from the mouse position + void MyGraphicsApp::OnLeftMouseDown(const Point2 &mouse_in_2d_pixels) { + Point2 mouse_in_2d_ndc = PixelsToNormalizedDeviceCoords(mouse_in_2d_pixels); + Point3 mouse_in_3d = GfxMath::ScreenToNearPlane(view_matrix, proj_matrix, mouse_in_2d_ndc); + Matrix4 camera_matrix = view_matrix.Inverse(); + Point3 eye = camera_matrix.ColumnToPoint3(3); + + Ray pick_ray(eye, mouse_in_3d - eye); + + // check to see if the ray intersects a sphere + float t; + Point3 p; + if (pick_ray.IntersectSphere(Point3(0,0,0), 2.0, &t, &p)) { + std::cout << "Mouse pointing at sphere! Intersection point = " << p << std::endl; + } + } + ~~~ + */ +class Ray { +public: + + /// Defaults to a ray at the origin and pointing in the -Z direction + Ray(); + + /// Creates a ray from a 3D origin and direction + Ray(const Point3 &origin, const Vector3 &direction); + + /// Ray destructor + virtual ~Ray(); + + /// Check for "equality", taking floating point imprecision into account + bool operator==(const Ray& other) const; + + /// Check for "inequality", taking floating point imprecision into account + bool operator!=(const Ray& other) const; + + /// Returns the length of the direction vector + float Length() const; + + /** Checks to see if the ray intersects a plane defined by a point and a normal. + If there was an intersection, true is returned, iTime is set to the intersection + time, and iPoint is set to the intersection point. The plane is considered + to be 1-sided. That is the intersection will only occur if the ray hits the + plane from its front side as determined by the plane's normal. + */ + bool IntersectPlane(const Point3 &planePt, const Vector3 &planeNormal, + float *iTime, Point3 *iPoint) const; + + /** Checks to see if the ray intersects a triangle defined by the vertices v1, v2, and v3. + The vertices must be provided in counter-clockwise order so that the normal of the + triangle can be determined via the right-hand rule. The intersection will only happen + if the ray hits the front side of the triangle. If there was an intersection, + true is returned, iTime is set to the intersection time, and iPoint is set to the intersection point. + */ + bool IntersectTriangle(const Point3 &v1, const Point3 &v2, const Point3 &v3, + float *iTime, Point3 *iPoint) const; + + /** Checks to see if the ray intersects a quad defined by the vertices v1, v2, v3, and v4. + The vertices must be provided in counter-clockwise order so that the normal of the + triangle can be determined via the right-hand rule. The intersection will only happen + if the ray hits the front side of the triangle. If there was an intersection, + true is returned, iTime is set to the intersection time, and iPoint is set to the intersection point. + */ + bool IntersectQuad(const Point3 &v1, const Point3 &v2, const Point3 &v3, const Point3 &v4, + float *iTime, Point3 *iPoint) const; + + /** Checks to see if the ray intersects a sphere defined by a center point and a radius. + If there was an intersection, true is returned, iTime is set to the intersection time, + and iPoint is set to the intersection point. + */ + bool IntersectSphere(const Point3 ¢er, float radius, + float *iTime, Point3 *iPoint) const; + + /** Checks to see if the ray intersects a triangle mesh. This is a brute-force + check over each triangle in the mesh. If there was an intersection, true is returned, + iTime is set to the intersection time, iPoint is set to the intersection point, + and iTriangleID is set to the ID of the closest intersected triangle along the ray. + */ + bool IntersectMesh(const Mesh &mesh, float *iTime, + Point3 *iPoint, int *iTriangleID) const; + + /** Checks to see if the ray intersects a triangle mesh. This uses a BVH + (Bounding Volume Hierarchy) to accelerate the ray-triangle intersection tests. + Each mesh can optionally store a BVH. If a BVH has already been calculated + for the mesh (done with Mesh::CalculateBVH()), then this function will be + much faster than the brute-force IntersectMesh() function. If a BVH has + not already been calculated for the mesh, the first call to FastIntersectMesh() + will trigger the mesh to create a BVH (not a fast operation) but then + subsequent calls to FastIntersectMesh() will be fast. + */ + bool FastIntersectMesh(Mesh *mesh, float *iTime, + Point3 *iPoint, int *iTriangleID) const; + + /** Checks to see if the ray intersects an AABB (Axis-Aligned Bounding Box). + Typically, this is the first step of a more detailed intersection test and + we don't care about the actual point of intersection, just whether it + intersects or not. So, we don't bother calculating the iPoint. We get the + iTime for free though, so we do return that. You can calc the iPoint if + you want using: + ~~~ + float t; + if (ray.IntersectAABB(box, &t)) { + Point3 iPoint = ray.origin() + t*ray.direction(); + } + ~~~ + */ + bool IntersectAABB(const AABB &box, float *iTime) const; + + /// Returns the origin + Point3 origin() const; + + /// Returns the direction + Vector3 direction() const; + + /// Sets a new origin and direction + void set(Point3 newOrigin, Vector3 newDir); + +private: + Point3 p_; + Vector3 d_; +}; + + +// --- Stream operators --- + +std::ostream & operator<< ( std::ostream &os, const Ray &r); +std::istream & operator>> ( std::istream &is, Ray &r); + + +} // end namespace + +#endif -- cgit v1.2.3