Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H 1
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace BiPatch {
|
||||
|
||||
class Vector {
|
||||
double d[3];
|
||||
|
||||
public:
|
||||
|
||||
inline Vector (double x, double y, double z=0);
|
||||
inline Vector(const Vector& v);
|
||||
inline Vector();
|
||||
inline double length() const;
|
||||
inline double length2() const;
|
||||
inline Vector& operator=(const Vector& v);
|
||||
inline bool operator==(const Vector& v) const;
|
||||
inline Vector operator*(double s) const;
|
||||
inline Vector operator*(const Vector& v) const;
|
||||
inline Vector operator/(const Vector& v) const;
|
||||
inline Vector& operator*=(double s);
|
||||
Vector operator/(double s) const;
|
||||
inline Vector operator+(const Vector& v) const;
|
||||
inline Vector& operator+=(const Vector& v);
|
||||
inline Vector operator-() const;
|
||||
inline Vector operator-(const Vector& v) const;
|
||||
Vector& operator-=(const Vector& v);
|
||||
inline double normalize();
|
||||
Vector normal() const;
|
||||
inline Vector cross(const Vector& v) const;
|
||||
inline double dot(const Vector& v) const;
|
||||
inline void x(double xx) { d[0]=xx; }
|
||||
inline double x() const;
|
||||
inline void y(double yy) { d[1]=yy; }
|
||||
inline double y() const;
|
||||
inline void z(double zz) { d[2]=zz; }
|
||||
inline double z() const;
|
||||
inline double minComponent() const;
|
||||
inline bool operator != (const Vector& v) const;
|
||||
inline double* ptr() const {return (double*)&d[0];}
|
||||
|
||||
void make_ortho(Vector&v1, Vector&v2)
|
||||
{
|
||||
Vector v0(this->cross(Vector(1,0,0)));
|
||||
if(v0.length2() == 0){
|
||||
v0=this->cross(this->cross(Vector(0,1,0)));
|
||||
}
|
||||
v1=this->cross(v0);
|
||||
v1.normalize();
|
||||
v2=this->cross(v1);
|
||||
v2.normalize();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline Vector::Vector(double x, double y, double z) {
|
||||
d[0]=x;
|
||||
d[1]=y;
|
||||
d[2]=z;
|
||||
}
|
||||
|
||||
inline Vector::Vector(const Vector& v) {
|
||||
d[0]=v.d[0];
|
||||
d[1]=v.d[1];
|
||||
d[2]=v.d[2];
|
||||
}
|
||||
|
||||
inline Vector::Vector() {
|
||||
}
|
||||
|
||||
|
||||
inline double Vector::length() const {
|
||||
return sqrt(length2());
|
||||
}
|
||||
|
||||
inline double Vector::length2() const {
|
||||
return d[0]*d[0]+d[1]*d[1]+d[2]*d[2];
|
||||
}
|
||||
|
||||
inline Vector& Vector::operator=(const Vector& v) {
|
||||
d[0]=v.d[0];
|
||||
d[1]=v.d[1];
|
||||
d[2]=v.d[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline Vector Vector::operator*(double s) const {
|
||||
return Vector(d[0]*s, d[1]*s, d[2]*s);
|
||||
}
|
||||
|
||||
inline Vector operator*(double s, const Vector& v) {
|
||||
return v*s;
|
||||
}
|
||||
|
||||
inline Vector Vector::operator*(const Vector& v) const {
|
||||
return Vector(d[0]*v.d[0], d[1]*v.d[1], d[2]*v.d[2]);
|
||||
}
|
||||
|
||||
inline Vector Vector::operator/(const Vector& v) const {
|
||||
return Vector(d[0]/v.d[0], d[1]/v.d[1], d[2]/v.d[2]);
|
||||
}
|
||||
|
||||
inline Vector Vector::operator+(const Vector& v) const {
|
||||
return Vector(d[0]+v.d[0], d[1]+v.d[1], d[2]+v.d[2]);
|
||||
}
|
||||
|
||||
inline Vector& Vector::operator+=(const Vector& v) {
|
||||
d[0]+=v.d[0];
|
||||
d[1]+=v.d[1];
|
||||
d[2]+=v.d[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector& Vector::operator*=(double s) {
|
||||
d[0]*=s;
|
||||
d[1]*=s;
|
||||
d[2]*=s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector Vector::operator-() const {
|
||||
return Vector(-d[0], -d[1], -d[2]);
|
||||
}
|
||||
|
||||
inline Vector Vector::operator-(const Vector& v) const {
|
||||
return Vector(d[0]-v.d[0], d[1]-v.d[1], d[2]-v.d[2]);
|
||||
}
|
||||
|
||||
|
||||
inline double Vector::normalize() {
|
||||
double l=length();
|
||||
if(l != 0)
|
||||
{
|
||||
d[0]/=l;
|
||||
d[1]/=l;
|
||||
d[2]/=l;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
inline Vector Vector::cross(const Vector& v) const {
|
||||
return Vector(d[1]*v.d[2]-d[2]*v.d[1],
|
||||
d[2]*v.d[0]-d[0]*v.d[2],
|
||||
d[0]*v.d[1]-d[1]*v.d[0]);
|
||||
}
|
||||
|
||||
inline double Vector::dot(const Vector& v) const {
|
||||
return d[0]*v.d[0]+d[1]*v.d[1]+d[2]*v.d[2];
|
||||
}
|
||||
|
||||
|
||||
inline double Vector::x() const {
|
||||
return d[0];
|
||||
}
|
||||
|
||||
inline double Vector::y() const {
|
||||
return d[1];
|
||||
}
|
||||
|
||||
inline double Vector::z() const {
|
||||
return d[2];
|
||||
}
|
||||
|
||||
inline double Vector::minComponent() const {
|
||||
return (d[0]<d[1] && d[0]<d[2])?d[0]:d[1]<d[2]?d[1]:d[2];
|
||||
}
|
||||
|
||||
inline bool Vector::operator != (const Vector& v) const {
|
||||
return d[0] != v.d[0] || d[1] != v.d[1] || d[2] != v.d[2];
|
||||
}
|
||||
|
||||
inline bool Vector::operator == (const Vector& v) const {
|
||||
return d[0] == v.d[0] && d[1] == v.d[1] && d[2] == v.d[2];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
//created by Shaun David Ramsey and Kristin Potter copyright (c) 2003
|
||||
//email ramsey()cs.utah.edu with any quesitons
|
||||
/*
|
||||
This copyright notice is available at:
|
||||
http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Copyright (c) 2003 Shaun David Ramsey, Kristin Potter, Charles Hansen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sel copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include "Vector.h"
|
||||
#define ray_epsilon 1e-4 // some small epsilon for flt pt
|
||||
//#define twoplanes true // comment out this line to use raypatch
|
||||
#ifndef twoplanes // if we're not using patch-twoplanes intersection
|
||||
#define raypatch true //then use ray-patch intersections
|
||||
#endif
|
||||
|
||||
#ifndef BILINEAR_H
|
||||
#define BILINEAR_H
|
||||
|
||||
|
||||
namespace BiPatch {
|
||||
|
||||
//find roots of ax^2+bx+c=0 in the interval min,max.
|
||||
// place the roots in u[2] and return how many roots found
|
||||
int QuadraticRoot(double a, double b, double c,
|
||||
double min, double max,double *u);
|
||||
|
||||
// Bilinear patch class
|
||||
class BilinearPatch
|
||||
{
|
||||
// The four points defining the patch
|
||||
Vector P00, P01, P10, P11;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
BilinearPatch(Vector Pt00, Vector Pt01, Vector Pt10, Vector Pt11);
|
||||
// Destructor
|
||||
~BilinearPatch(){}
|
||||
Vector getP00(){return P00;}
|
||||
// Return the point P01
|
||||
Vector getP01(){return P01;}
|
||||
// Return the point P10
|
||||
Vector getP10(){return P10;}
|
||||
// Return the point P11
|
||||
Vector getP11(){return P11;}
|
||||
// Find the tangent (du)
|
||||
Vector TanU( double v);
|
||||
// Find the tangent (dv)
|
||||
Vector TanV( double u);
|
||||
// Find dudv
|
||||
Vector Normal( double u, double v);
|
||||
// Evaluate the surface of the patch at u,v
|
||||
Vector SrfEval( double u, double v);
|
||||
// Find the local closest point to spacept
|
||||
bool RayPatchIntersection( Vector r, Vector d, Vector &uv);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
#pragma once
|
||||
#include "vec3.h"
|
||||
#include "line3d.h"
|
||||
#include "matrix.h"
|
||||
#include "sse.h"
|
||||
#include <algorithm>
|
||||
|
||||
//Axis-Aligned Bounding Box
|
||||
template<class T>
|
||||
struct AABBox {
|
||||
vec3<T> minimum, maximum;
|
||||
|
||||
AABBox() {}
|
||||
AABBox(const AABBox& other) : minimum(other.minimum), maximum(other.maximum) {}
|
||||
AABBox(const vec3<T>& start) : minimum(start), maximum(start) {}
|
||||
AABBox(const vec3<T>& minvec, const vec3<T>& maxvec) : minimum(minvec), maximum(maxvec) {}
|
||||
AABBox(T minX, T minY, T minZ, T maxX, T maxY, T maxZ) : minimum(minX, minY, minZ), maximum(maxX, maxY, maxZ) {}
|
||||
AABBox(const line3d<T>& line) : minimum(line.start), maximum(line.end) { fix(); }
|
||||
|
||||
AABBox(const line3d<T>& line, double width) : minimum(line.start), maximum(line.end) {
|
||||
fix();
|
||||
minimum -= vec3d(width);
|
||||
maximum += vec3d(width);
|
||||
}
|
||||
|
||||
inline static AABBox fromCircle(const vec3<T>& center, T radius) {
|
||||
return AABBox(center.x - radius, center.y - radius, center.z - radius,
|
||||
center.x + radius, center.y + radius, center.z + radius);
|
||||
}
|
||||
|
||||
bool operator==(const AABBox& other) const {
|
||||
return minimum == other.minimum && maximum != other.maximum;
|
||||
}
|
||||
|
||||
bool operator!=(const AABBox& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
vec3<T> getSize() const {
|
||||
return maximum - minimum;
|
||||
}
|
||||
|
||||
vec3<T> getCenter() const {
|
||||
return (minimum + maximum) * 0.5;
|
||||
}
|
||||
|
||||
bool overlaps(const vec3<T>& point) const {
|
||||
return (point.x >= minimum.x && point.x <= maximum.x &&
|
||||
point.y >= minimum.y && point.y <= maximum.y &&
|
||||
point.z >= minimum.z && point.z <= maximum.z);
|
||||
}
|
||||
|
||||
bool isWithin(const AABBox& other) const {
|
||||
return minimum.x >= other.minimum.x &&
|
||||
minimum.y >= other.minimum.y &&
|
||||
minimum.z >= other.minimum.z &&
|
||||
maximum.x <= other.maximum.x &&
|
||||
maximum.y <= other.maximum.y &&
|
||||
maximum.z <= other.maximum.z;
|
||||
}
|
||||
|
||||
bool overlaps(const vec3<T>& center, double radius) const {
|
||||
if(overlaps(center))
|
||||
return true;
|
||||
vec3<T> axisDist;
|
||||
|
||||
if(center.x < minimum.x)
|
||||
axisDist.x = minimum.x - center.x;
|
||||
else if(center.x > maximum.x)
|
||||
axisDist.x = maximum.x - center.x;
|
||||
|
||||
if(axisDist.x > radius)
|
||||
return false;
|
||||
|
||||
if(center.y < minimum.y)
|
||||
axisDist.y = minimum.y - center.y;
|
||||
else if(center.y > maximum.y)
|
||||
axisDist.y = maximum.y - center.y;
|
||||
|
||||
if(axisDist.y > radius)
|
||||
return false;
|
||||
|
||||
if(center.z < minimum.z)
|
||||
axisDist.z = minimum.z - center.z;
|
||||
else if(center.z > maximum.z)
|
||||
axisDist.z = maximum.z - center.z;
|
||||
|
||||
if(axisDist.z > radius)
|
||||
return false;
|
||||
|
||||
return axisDist.getLengthSQ() <= radius * radius;
|
||||
}
|
||||
|
||||
bool overlaps(const AABBox& other) const {
|
||||
if( minimum.x > other.maximum.x ||
|
||||
minimum.z > other.maximum.z ||
|
||||
maximum.x < other.minimum.x ||
|
||||
maximum.z < other.minimum.z ||
|
||||
minimum.y > other.maximum.y ||
|
||||
maximum.y < other.minimum.y )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Resets the bounding box to bound around a single point (0,0,0 by default)
|
||||
void reset(vec3<T> initialize = vec3<T>(0,0,0)) {
|
||||
minimum = initialize;
|
||||
maximum = initialize;
|
||||
}
|
||||
|
||||
void reset(const AABBox& initialize) {
|
||||
minimum = initialize.minimum;
|
||||
maximum = initialize.maximum;
|
||||
}
|
||||
|
||||
void reset(const line3d<T>& initialize) {
|
||||
minimum = initialize.start;
|
||||
maximum = initialize.end;
|
||||
fix();
|
||||
}
|
||||
|
||||
//Expands the bounding box to contain a point
|
||||
void addPoint(const vec3<T>& point) {
|
||||
#define BBOX_POINTDIM(dim) if(point.dim < minimum.dim) minimum.dim = point.dim;\
|
||||
else if(point.dim > maximum.dim) maximum.dim = point.dim;
|
||||
|
||||
BBOX_POINTDIM(x);
|
||||
BBOX_POINTDIM(y);
|
||||
BBOX_POINTDIM(z);
|
||||
}
|
||||
|
||||
void addBox(const AABBox& box) {
|
||||
#define BBOX_BOXDIM(dim) if(box.minimum.dim < minimum.dim) minimum.dim = box.minimum.dim;\
|
||||
if(box.maximum.dim > maximum.dim) maximum.dim = box.maximum.dim;
|
||||
|
||||
BBOX_BOXDIM(x);
|
||||
BBOX_BOXDIM(y);
|
||||
BBOX_BOXDIM(z);
|
||||
}
|
||||
|
||||
void addLine(const line3d<T>& line) {
|
||||
addPoint(line.start);
|
||||
addPoint(line.end);
|
||||
}
|
||||
|
||||
//Flips any bounds where Minimum > Maximum
|
||||
void fix() {
|
||||
if(minimum.x > maximum.x) {
|
||||
T temp = maximum.x;
|
||||
maximum.x = minimum.x;
|
||||
minimum.x = temp;
|
||||
}
|
||||
|
||||
if(minimum.y > maximum.y) {
|
||||
T temp = maximum.y;
|
||||
maximum.y = minimum.y;
|
||||
minimum.y = temp;
|
||||
}
|
||||
|
||||
if(minimum.z > maximum.z) {
|
||||
T temp = maximum.z;
|
||||
maximum.z = minimum.z;
|
||||
minimum.z = temp;
|
||||
}
|
||||
}
|
||||
|
||||
//Get a rectangle size after a projection
|
||||
vec3d getProjectedSize(const Matrix& transform) const {
|
||||
AABBox result;
|
||||
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
vec3d point;
|
||||
point.x = (i & 1) ? minimum.x : maximum.x;
|
||||
point.y = (i & 2) ? minimum.y : maximum.y;
|
||||
point.z = (i & 4) ? minimum.z : maximum.z;
|
||||
point = transform * point;
|
||||
|
||||
if(i == 0)
|
||||
result.reset(point);
|
||||
else
|
||||
result.addPoint(point);
|
||||
}
|
||||
|
||||
return result.getSize();
|
||||
}
|
||||
};
|
||||
|
||||
typedef AABBox<double> AABBoxd;
|
||||
typedef AABBox<float> AABBoxf;
|
||||
@@ -0,0 +1,196 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
struct ColorRGB {
|
||||
unsigned char r : 8;
|
||||
unsigned char g : 8;
|
||||
unsigned char b : 8;
|
||||
|
||||
ColorRGB() : r(255), g(255), b(255) {}
|
||||
ColorRGB(unsigned char R, unsigned char G, unsigned char B) : r(R), g(G), b(B) {}
|
||||
};
|
||||
|
||||
struct Color {
|
||||
union {
|
||||
unsigned int color;
|
||||
struct {
|
||||
unsigned char r : 8;
|
||||
unsigned char g : 8;
|
||||
unsigned char b : 8;
|
||||
unsigned char a : 8;
|
||||
};
|
||||
};
|
||||
|
||||
Color() : color(0xffffffff) {}
|
||||
Color(unsigned int col) { set(col); }
|
||||
Color(unsigned char grey) : r(grey), g(grey), b(grey), a(255) {}
|
||||
Color(unsigned char R, unsigned char G, unsigned char B) : r(R), g(G), b(B), a(0xff) {}
|
||||
Color(unsigned char R, unsigned char G, unsigned char B, unsigned char A) : r(R), g(G), b(B), a(A) {}
|
||||
|
||||
Color(ColorRGB rgb) : r(rgb.r), g(rgb.g), b(rgb.b), a(255) {}
|
||||
|
||||
void set(unsigned int col) {
|
||||
r = (col & 0xff000000) >> 24;
|
||||
g = (col & 0x00ff0000) >> 16;
|
||||
b = (col & 0x0000ff00) >> 8;
|
||||
a = (col & 0x000000ff);
|
||||
}
|
||||
|
||||
Color getInterpolated(const Color& other, float pct) const {
|
||||
if(pct <= 0)
|
||||
return *this;
|
||||
else if(pct >= 1)
|
||||
return other;
|
||||
else {
|
||||
return Color(
|
||||
(unsigned char)(float(r) + float(other.r - r) * pct),
|
||||
(unsigned char)(float(g) + float(other.g - g) * pct),
|
||||
(unsigned char)(float(b) + float(other.b - b) * pct),
|
||||
(unsigned char)(float(a) + float(other.a - a) * pct) );
|
||||
}
|
||||
}
|
||||
|
||||
Color operator*(const Color& other) const {
|
||||
return Color(
|
||||
(unsigned char)(float(r) / 255.f * float(other.r)),
|
||||
(unsigned char)(float(g) / 255.f * float(other.g)),
|
||||
(unsigned char)(float(b) / 255.f * float(other.b)),
|
||||
(unsigned char)(float(a) / 255.f * float(other.a)) );
|
||||
}
|
||||
};
|
||||
|
||||
struct Colorf {
|
||||
float r, g, b, a;
|
||||
|
||||
Colorf() : r(1), g(1), b(1), a(1) {}
|
||||
Colorf(float R, float G, float B) : r(R), g(G), b(B), a(1) {}
|
||||
Colorf(float R, float G, float B, float A) : r(R), g(G), b(B), a(A) {}
|
||||
|
||||
bool operator!=(const Colorf& other) const {
|
||||
return r != other.r || g != other.g || b != other.b || a != other.a;
|
||||
}
|
||||
|
||||
operator Color() const {
|
||||
return Color(
|
||||
(r >= 1.f ? 255 : (r <= 0.f ? 0 : (unsigned char)(r * 255.f))),
|
||||
(g >= 1.f ? 255 : (g <= 0.f ? 0 : (unsigned char)(g * 255.f))),
|
||||
(b >= 1.f ? 255 : (b <= 0.f ? 0 : (unsigned char)(b * 255.f))),
|
||||
(a >= 1.f ? 255 : (a <= 0.f ? 0 : (unsigned char)(a * 255.f)))
|
||||
);
|
||||
}
|
||||
|
||||
explicit Colorf(const Color& c)
|
||||
: r(float(c.r) / 255.f), g(float(c.g) / 255.f), b(float(c.b) / 255.f), a(float(c.a) / 255.f)
|
||||
{}
|
||||
|
||||
void operator=(const Color& c) {
|
||||
float ratio = 1/255.f;
|
||||
r = float(c.r) * ratio;
|
||||
g = float(c.g) * ratio;
|
||||
b = float(c.b) * ratio;
|
||||
a = float(c.a) * ratio;
|
||||
}
|
||||
|
||||
Colorf operator*(float factor) const {
|
||||
return Colorf(r * factor, g * factor, b * factor, a * factor);
|
||||
}
|
||||
|
||||
Colorf& operator*=(float factor) {
|
||||
r *= factor;
|
||||
g *= factor;
|
||||
b *= factor;
|
||||
a *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Colorf& operator+=(const Colorf& other) {
|
||||
r += other.r;
|
||||
g += other.g;
|
||||
b += other.b;
|
||||
a += other.a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Returns the maximal value of the color channels
|
||||
//For colors in the [0,1] range, this is the Value of that color
|
||||
float getValue() const {
|
||||
float V = r;
|
||||
if(g>V) V=g;
|
||||
if(b>V) V=b;
|
||||
return V;
|
||||
}
|
||||
|
||||
//Returns the saturation of the color
|
||||
float getSaturation() const {
|
||||
float M = r; if(g>M) M=g; if(b>M) M=b;
|
||||
float m = r; if(g<m) m=g; if(b<m) m=b;
|
||||
float Chroma = M-m;
|
||||
|
||||
if(Chroma == 0)
|
||||
return 0;
|
||||
else
|
||||
return Chroma/M;
|
||||
}
|
||||
|
||||
//Returns the hue of the color, in degrees in the range [0,360)
|
||||
//Greys return as 0
|
||||
float getHue() const {
|
||||
float M = r; if(g>M) M=g; if(b>M) M=b;
|
||||
float m = r; if(g<m) m=g; if(b<m) m=b;
|
||||
float Chroma = M-m;
|
||||
|
||||
if(Chroma == 0)
|
||||
return 0;
|
||||
|
||||
float hue;
|
||||
|
||||
if(M == r) {
|
||||
hue = (g-b)/Chroma;
|
||||
if(hue < 0)
|
||||
hue += 6.f;
|
||||
}
|
||||
else if(M == g) {
|
||||
hue = 2.f + (b-r)/Chroma;
|
||||
}
|
||||
else { //M == b
|
||||
hue = 4.f + (r-g)/Chroma;
|
||||
}
|
||||
|
||||
return hue * 60.f;
|
||||
}
|
||||
|
||||
//Sets this color to the RGB[0,1] representation of the HSV values
|
||||
//Alpha is unaffected
|
||||
//Hue must be in [0,360)
|
||||
void fromHSV(float hue, float saturation, float value) {
|
||||
//Generate necessary values
|
||||
float Chroma = saturation * value;
|
||||
float X = Chroma * (1.f - fabs(fmod(hue/60.f,2.f) - 1.f));
|
||||
float m = value - Chroma;
|
||||
|
||||
//Correct color ranges and set channels to the maximal value
|
||||
Chroma += m;
|
||||
X += m;
|
||||
|
||||
r = Chroma;
|
||||
g = Chroma;
|
||||
b = Chroma;
|
||||
|
||||
//Pick the lower channels according to the hue
|
||||
unsigned h = unsigned(hue/60.f);
|
||||
switch(h) {
|
||||
case 0:
|
||||
g=X; b=m; break;
|
||||
case 1:
|
||||
r=X; b=m; break;
|
||||
case 2:
|
||||
b=X; r=m; break;
|
||||
case 3:
|
||||
g=X; r=m; break;
|
||||
case 4:
|
||||
r=X; g=m; break;
|
||||
case 5:
|
||||
b=X; g=m; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#ifdef M_PIl
|
||||
const double e = M_El;
|
||||
const double pi = M_PIl;
|
||||
const double twopi = M_PIl * 2;
|
||||
#else
|
||||
const double e = M_E;
|
||||
const double pi = M_PI;
|
||||
const double twopi = M_PI * 2;
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "plane.h"
|
||||
#include "line3d.h"
|
||||
#include "aabbox.h"
|
||||
|
||||
struct frustum {
|
||||
//Planes are: Near, Left, Right, Top, Bottom, Far
|
||||
planed planes[6];
|
||||
AABBoxd bound;
|
||||
|
||||
frustum() {}
|
||||
|
||||
frustum(const line3dd& topLeft, const line3dd& topRight, const line3dd& botLeft, const line3dd& botRight) {
|
||||
planes[0] = planed(topLeft.start, botLeft.start, topRight.start);
|
||||
planes[1] = planed(topLeft.start, topLeft.end, botLeft.start);
|
||||
planes[2] = planed(topRight.end, topRight.start, botRight.start);
|
||||
planes[3] = planed(topLeft.start, topRight.start, topRight.end);
|
||||
planes[4] = planed(botRight.start, botLeft.start, botRight.end);
|
||||
planes[5] = planed(topLeft.end, topRight.end, botLeft.end);
|
||||
|
||||
bound.reset(topLeft);
|
||||
bound.addLine(topRight);
|
||||
bound.addLine(botLeft);
|
||||
bound.addLine(botRight);
|
||||
}
|
||||
|
||||
void operator=(const frustum& other) {
|
||||
memcpy(this, &other, sizeof(frustum));
|
||||
}
|
||||
|
||||
bool overlaps(const vec3d& center, double radius) const {
|
||||
for(unsigned i = 0; i < 6; ++i)
|
||||
if(planes[i].distanceFromPlane(center) <= -radius)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,271 @@
|
||||
#pragma once
|
||||
#include "color.h"
|
||||
#include "vec2.h"
|
||||
#include "rect.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
|
||||
enum ColorFormat {
|
||||
FMT_Grey,
|
||||
FMT_Alpha,
|
||||
FMT_RGB,
|
||||
FMT_RGBA,
|
||||
FMT_INVALID
|
||||
};
|
||||
|
||||
enum ColorDepth {
|
||||
DEPTH_Grey = sizeof(unsigned char),
|
||||
DEPTH_Alpha = sizeof(unsigned char),
|
||||
DEPTH_RGB = sizeof(ColorRGB),
|
||||
DEPTH_RGBA = sizeof(Color)
|
||||
};
|
||||
|
||||
//Color depths by format (e.g. ColorDepths[FMT_RGB] == DEPTH_RGB)
|
||||
extern unsigned ColorDepths[4];
|
||||
|
||||
//Standard image in 32-bit RGBA format
|
||||
struct Image {
|
||||
union {
|
||||
unsigned char* grey;
|
||||
ColorRGB* rgb;
|
||||
Color* rgba;
|
||||
};
|
||||
|
||||
ColorFormat format;
|
||||
unsigned int width, height;
|
||||
|
||||
unsigned char& get_alpha(unsigned int x, unsigned int y) {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char get_alpha(unsigned int x, unsigned int y) const {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char& get_grey(unsigned int x, unsigned int y) {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char get_grey(unsigned int x, unsigned int y) const {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
ColorRGB& get_rgb(unsigned int x, unsigned int y) {
|
||||
return rgb[x + (y * width)];
|
||||
}
|
||||
|
||||
ColorRGB get_rgb(unsigned int x, unsigned int y) const {
|
||||
return rgb[x + (y * width)];
|
||||
}
|
||||
|
||||
Color& get_rgba(unsigned int x, unsigned int y) {
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
|
||||
Color get_rgba(unsigned int x, unsigned int y) const {
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
|
||||
Color get(unsigned int x, unsigned int y) const {
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
return grey[x + (y * width)];
|
||||
case FMT_RGB:
|
||||
return rgb[x + (y * width)];
|
||||
case FMT_RGBA:
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
return Color();
|
||||
}
|
||||
|
||||
Color getTexel(float x, float y) {
|
||||
float ipart;
|
||||
float u = std::modf(x,&ipart), v = std::modf(y,&ipart);
|
||||
if(u < 0)
|
||||
u = 1.f + u;
|
||||
u *= (float)width;
|
||||
if(v < 0)
|
||||
v = 1.f + v;
|
||||
v *= (float)height;
|
||||
|
||||
int x1 = (int)u;
|
||||
int x2 = (x1 + 1) % (int)width;
|
||||
int y1 = (int)v;
|
||||
int y2 = (y1 + 1) % (int)height;
|
||||
|
||||
Color upper = get(x1,y1).getInterpolated(get(x2,y1), std::modf(u,&ipart));
|
||||
Color lower = get(x1,y2).getInterpolated(get(x2,y2), std::modf(u,&ipart));
|
||||
|
||||
return upper.getInterpolated(lower, std::modf(v,&ipart));
|
||||
}
|
||||
|
||||
Color getTexel(const vec2f& pos) {
|
||||
return getTexel(pos.x, pos.y);
|
||||
}
|
||||
|
||||
static Image* random(const vec2u& resolution, int(int,int));
|
||||
|
||||
//Returns an image that is a sphere-distortion-corrected version of this one
|
||||
Image* sphereDistort() const;
|
||||
|
||||
//Returns a half-resolution version of this image
|
||||
//If the image is too small, returns 0
|
||||
Image* makeMipmap() const;
|
||||
|
||||
Image* crop(const rect<unsigned>& bound) const;
|
||||
|
||||
Image() : width(0), height(0), rgba(0) {}
|
||||
|
||||
Image(const Image& other) : width(0), height(0), rgba(0) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void operator=(const Image& other) {
|
||||
if(other.width != width || other.height != height || other.format != format) {
|
||||
width = other.width;
|
||||
height = other.height;
|
||||
format = other.format;
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey;
|
||||
grey = new unsigned char[width*height];
|
||||
break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb;
|
||||
rgb = new ColorRGB[width*height];
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba;
|
||||
rgba = new Color[width*height];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
memcpy(grey, other.grey, width*height*sizeof(unsigned char));
|
||||
break;
|
||||
case FMT_RGB:
|
||||
memcpy(rgb, other.rgb, width*height*sizeof(ColorRGB));
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
memcpy(rgba, other.rgba, width*height*sizeof(Color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Image(unsigned int Width, unsigned int Height, ColorFormat Format)
|
||||
: width(Width), height(Height), format(Format), rgba(0)
|
||||
{
|
||||
if(width > 0 && height > 0) {
|
||||
switch(Format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image(unsigned int Width, unsigned int Height, ColorFormat Format, unsigned char defaultLevel)
|
||||
: width(Width), height(Height), format(Format), rgba(0)
|
||||
{
|
||||
if(width > 0 && height > 0) {
|
||||
switch(Format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
|
||||
if(grey)
|
||||
memset(grey, defaultLevel, Width * Height * ColorDepths[format]);
|
||||
}
|
||||
}
|
||||
|
||||
void makeRGBA(const Image& other) {
|
||||
resize(other.width, other.height, FMT_RGBA);
|
||||
switch(other.format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i) {
|
||||
Color& col = rgba[i];
|
||||
col.r = other.grey[i];
|
||||
col.g = col.r;
|
||||
col.b = col.r;
|
||||
col.a = 0xff;
|
||||
}
|
||||
break;
|
||||
case FMT_RGB:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i) {
|
||||
Color& col = rgba[i];
|
||||
ColorRGB& ocol = other.rgb[i];
|
||||
col.r = ocol.r;
|
||||
col.g = ocol.g;
|
||||
col.b = ocol.b;
|
||||
col.a = 0xff;
|
||||
}
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i)
|
||||
rgba[i] = other.rgba[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(unsigned Width, unsigned Height, ColorFormat newFormat = FMT_INVALID) {
|
||||
if(newFormat == FMT_INVALID)
|
||||
newFormat = format;
|
||||
|
||||
width = Width;
|
||||
height = Height;
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey; break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb; break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba; break;
|
||||
}
|
||||
if(width > 0 && height > 0) {
|
||||
format = newFormat;
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Image() {
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey; break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb; break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Attempts to load the file according to the extension. If the file cannot be loaded, 0 is returned.
|
||||
Image* loadImage(const char* filename);
|
||||
bool saveImage(const Image* img, const char* filename, bool flip = false);
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
#include "vec3.h"
|
||||
|
||||
template<class T>
|
||||
struct line3d {
|
||||
vec3<T> start, end;
|
||||
|
||||
line3d() {};
|
||||
line3d(const vec3<T>& Start, const vec3<T>& End) : start(Start), end(End) {}
|
||||
|
||||
double getLength() const {
|
||||
return start.distanceTo(end);
|
||||
}
|
||||
|
||||
double getLengthSQ() const {
|
||||
return start.distanceToSQ(end);
|
||||
}
|
||||
|
||||
vec3<T> getDirection() const {
|
||||
return (end-start).normalized();
|
||||
}
|
||||
|
||||
vec3<T> getCenter() const {
|
||||
return (end+start) / 2;
|
||||
}
|
||||
|
||||
bool intersectX(vec3<T>& point, T x = 0.0, bool segment = true) const {
|
||||
vec3<T> dir = end - start;
|
||||
if(dir.x == 0)
|
||||
return false;
|
||||
double pct = (x - start.x) / dir.x;
|
||||
if(segment && (pct < 0 || pct > 1))
|
||||
return false;
|
||||
point = start + dir * pct;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersectY(vec3<T>& point, T y = 0.0, bool segment = true) const {
|
||||
vec3<T> dir = end - start;
|
||||
if(dir.y == 0)
|
||||
return false;
|
||||
double pct = (y - start.y) / dir.y;
|
||||
if(segment && (pct < 0 || pct > 1))
|
||||
return false;
|
||||
point = start + dir * pct;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersectZ(vec3<T>& point, T z = 0.0, bool segment = true) const {
|
||||
vec3<T> dir = end - start;
|
||||
if(dir.z == 0)
|
||||
return false;
|
||||
double pct = (z - start.z) / dir.z;
|
||||
if(segment && (pct < 0 || pct > 1))
|
||||
return false;
|
||||
point = start + dir * pct;
|
||||
return true;
|
||||
}
|
||||
|
||||
vec3<T> getClosestPoint(const vec3<T>& p, bool wholeLine = true) const {
|
||||
auto ps = p - start;
|
||||
auto es = end - start;
|
||||
|
||||
auto lenSQ = getLengthSQ();
|
||||
auto psDot = ps.dot(es);
|
||||
|
||||
auto t = psDot / lenSQ;
|
||||
|
||||
if(!wholeLine) {
|
||||
if(t <= 0.0)
|
||||
return start;
|
||||
else if(t >= 1.0)
|
||||
return end;
|
||||
}
|
||||
|
||||
return start + (es * t);
|
||||
}
|
||||
|
||||
bool intersectTriangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, vec3d& output) const {
|
||||
vec3d direction = end - start;
|
||||
vec3d edge1 = v2 - v1;
|
||||
vec3d edge2 = v3 - v1;
|
||||
|
||||
vec3d p = direction.cross(edge2);
|
||||
double det = edge1.dot(p);
|
||||
if(det > -0.00001 && det < 0.00001)
|
||||
return false;
|
||||
|
||||
det = 1.0 / det;
|
||||
|
||||
vec3d t = start - v1;
|
||||
double u = t.dot(p) * det;
|
||||
if(u < 0.0 || u > 1.0)
|
||||
return false;
|
||||
|
||||
vec3d q = t.cross(edge1);
|
||||
double v = direction.dot(q) * det;
|
||||
if(v < 0.0 || u + v > 1.0)
|
||||
return false;
|
||||
|
||||
double w = edge2.dot(q) * det;
|
||||
if(w > 0.0001) {
|
||||
output = start + direction * w;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef line3d<int> line3di;
|
||||
typedef line3d<float> line3df;
|
||||
typedef line3d<double> line3dd;
|
||||
@@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
#include "constants.h"
|
||||
#include <memory.h>
|
||||
#include "vec3.h"
|
||||
#include "vec4.h"
|
||||
|
||||
const double _identityMatrixData[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
|
||||
//A 4x4 Matrix
|
||||
struct Matrix {
|
||||
double m[16];
|
||||
|
||||
void setScale(vec3<double>& scale) {
|
||||
m[0] = scale.x;
|
||||
m[5] = scale.y;
|
||||
m[10] = scale.z;
|
||||
}
|
||||
|
||||
void scaleUniformly(double scale) {
|
||||
m[0] *= scale; m[4] *= scale; m[8] *= scale;
|
||||
m[1] *= scale; m[5] *= scale; m[9] *= scale;
|
||||
m[2] *= scale; m[6] *= scale; m[10] *= scale;
|
||||
}
|
||||
|
||||
void setTranslation(vec3<double>& translation) {
|
||||
m[12] = translation.x;
|
||||
m[13] = translation.y;
|
||||
m[14] = translation.z;
|
||||
}
|
||||
|
||||
vec3<double> getTranslation() const {
|
||||
return vec3<double>(m[12],m[13],m[14]);
|
||||
}
|
||||
|
||||
double& operator[](unsigned i) {
|
||||
return m[i];
|
||||
}
|
||||
|
||||
const double& operator[](unsigned i) const {
|
||||
return m[i];
|
||||
}
|
||||
|
||||
void operator=(const Matrix& b) {
|
||||
memcpy(m, b.m, sizeof(m));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
vec3<T> rotate(const vec3<T>& b) const {
|
||||
vec3<T> r;
|
||||
r.x= (m[0]*b.x) + (m[4]*b.y) + (m[8]*b.z);
|
||||
r.y= (m[1]*b.x) + (m[5]*b.y) + (m[9]*b.z);
|
||||
r.z= (m[2]*b.x) + (m[6]*b.y) + (m[10]*b.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
vec3<T> operator*(const vec3<T>& b) const {
|
||||
vec3<T> r;
|
||||
r.x= (m[0]*b.x) + (m[4]*b.y) + (m[8]*b.z) + m[12];
|
||||
r.y= (m[1]*b.x) + (m[5]*b.y) + (m[9]*b.z) + m[13];
|
||||
r.z= (m[2]*b.x) + (m[6]*b.y) + (m[10]*b.z) + m[14];
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
vec4<T> operator*(const vec4<T>& b) const {
|
||||
vec4<T> r;
|
||||
r.x= (m[0]*b.x) + (m[4]*b.y) + (m[8]*b.z) + (m[12]*b.w);
|
||||
r.y= (m[1]*b.x) + (m[5]*b.y) + (m[9]*b.z) + (m[13]*b.w);
|
||||
r.z= (m[2]*b.x) + (m[6]*b.y) + (m[10]*b.z) + (m[14]*b.w);
|
||||
r.w= (m[2]*b.x) + (m[6]*b.y) + (m[10]*b.z) + (m[15]*b.w);
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix operator*(const Matrix& b) const {
|
||||
Matrix r;
|
||||
r[0]= (m[0]*b[0]) + (m[4]*b[1]) + (m[8]*b[2]) + (m[12]*b[3]);
|
||||
r[1]= (m[1]*b[0]) + (m[5]*b[1]) + (m[9]*b[2]) + (m[13]*b[3]);
|
||||
r[2]= (m[2]*b[0]) + (m[6]*b[1]) + (m[10]*b[2]) + (m[14]*b[3]);
|
||||
r[3]= (m[3]*b[0]) + (m[7]*b[1]) + (m[11]*b[2]) + (m[15]*b[3]);
|
||||
|
||||
r[4]= (m[0]*b[4]) + (m[4]*b[5]) + (m[8]*b[6]) + (m[12]*b[7]);
|
||||
r[5]= (m[1]*b[4]) + (m[5]*b[5]) + (m[9]*b[6]) + (m[13]*b[7]);
|
||||
r[6]= (m[2]*b[4]) + (m[6]*b[5]) + (m[10]*b[6]) + (m[14]*b[7]);
|
||||
r[7]= (m[3]*b[4]) + (m[7]*b[5]) + (m[11]*b[6]) + (m[15]*b[7]);
|
||||
|
||||
r[8]= (m[0]*b[8]) + (m[4]*b[9]) + (m[8]*b[10]) + (m[12]*b[11]);
|
||||
r[9]= (m[1]*b[8]) + (m[5]*b[9]) + (m[9]*b[10]) + (m[13]*b[11]);
|
||||
r[10]= (m[2]*b[8]) + (m[6]*b[9]) + (m[10]*b[10]) + (m[14]*b[11]);
|
||||
r[11]= (m[3]*b[8]) + (m[7]*b[9]) + (m[11]*b[10]) + (m[15]*b[11]);
|
||||
|
||||
r[12]= (m[0]*b[12]) + (m[4]*b[13]) + (m[8]*b[14]) + (m[12]*b[15]);
|
||||
r[13]= (m[1]*b[12]) + (m[5]*b[13]) + (m[9]*b[14]) + (m[13]*b[15]);
|
||||
r[14]= (m[2]*b[12]) + (m[6]*b[13]) + (m[10]*b[14]) + (m[14]*b[15]);
|
||||
r[15]= (m[3]*b[12]) + (m[7]*b[13]) + (m[11]*b[14]) + (m[15]*b[15]);
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix& operator*=(const Matrix& b) {
|
||||
*this = *this * b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix() {
|
||||
memcpy(m, _identityMatrixData, sizeof(_identityMatrixData));
|
||||
}
|
||||
|
||||
Matrix(const Matrix& b) {
|
||||
memcpy(m, b.m, sizeof(m));
|
||||
}
|
||||
|
||||
static Matrix projection(double fov, double aspect, double znear, double zfar) {
|
||||
double ymax = znear * tan(fov * pi / 360.0);
|
||||
double xmax = ymax * aspect;
|
||||
|
||||
double w = xmax + xmax;
|
||||
double h = ymax + ymax;
|
||||
|
||||
Matrix m;
|
||||
m[0] = (2.0 * znear) / w;
|
||||
//m[1] = 0;
|
||||
//m[2] = 0;
|
||||
//m[3] = 0;
|
||||
|
||||
//m[4] = 0;
|
||||
m[5] = (2.0 * znear) / h;
|
||||
//m[6] = 0;
|
||||
//m[7] = 0;
|
||||
|
||||
//m[8] = 0;
|
||||
//m[9] = 0;
|
||||
m[10] = (-zfar - znear) / (zfar - znear);
|
||||
m[11] = -1.0;
|
||||
|
||||
//m[12] = 0;
|
||||
//m[13] = 0;
|
||||
m[14] = (-2.0 * znear * zfar) / (zfar - znear);
|
||||
m[15] = 0;
|
||||
|
||||
return m;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "vertex.h"
|
||||
#include "vec4.h"
|
||||
#include "color.h"
|
||||
#include <vector>
|
||||
|
||||
struct Mesh {
|
||||
public:
|
||||
struct Face {
|
||||
unsigned short a, b, c;
|
||||
|
||||
Face() : a(0), b(0), c(0) {};
|
||||
|
||||
Face(unsigned short A, unsigned short B, unsigned short C)
|
||||
: a(A), b(B), c(C) {};
|
||||
|
||||
Face(const Face& other) {
|
||||
a = other.a;
|
||||
b = other.b;
|
||||
c = other.c;
|
||||
};
|
||||
};
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<Face> faces;
|
||||
|
||||
std::vector<vec4f> tangents;
|
||||
std::vector<Colorf> colors;
|
||||
std::vector<vec4f> uvs2;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
template <class T>
|
||||
T max_(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T min_(T a, T b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "vec3.h"
|
||||
|
||||
template<class T>
|
||||
struct plane {
|
||||
vec3<T> dir;
|
||||
T dist;
|
||||
|
||||
plane() : dist(0) {}
|
||||
|
||||
plane(const vec3<T>& direction, T distance) : dir(direction), dist(distance) {
|
||||
}
|
||||
|
||||
plane(const vec3<T>& point, const vec3<T>& direction) : dir(direction), dist((T)point.dot(direction)) {
|
||||
}
|
||||
|
||||
//Creates a plane from a triangle specified in clockwise order (looking at the plane)
|
||||
plane(const vec3<T>& vertA, const vec3<T>& vertB, const vec3<T>& vertC) {
|
||||
vec3<T> legOne = vertA - vertB, legTwo = vertC - vertB;
|
||||
|
||||
dir = legOne.cross(legTwo).normalized();
|
||||
dist = (T)dir.dot(vertA);
|
||||
}
|
||||
|
||||
double distanceFromPlane(const vec3<T>& point) const {
|
||||
return dir.dot(point) - dist;
|
||||
}
|
||||
|
||||
bool pointInFront(const vec3<T>& point) const {
|
||||
return distanceFromPlane(point) >= 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef plane<double> planed;
|
||||
@@ -0,0 +1,241 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
#include "vec3.h"
|
||||
#include "matrix.h"
|
||||
|
||||
//4 Dimensional Vector structure
|
||||
template<class T = double>
|
||||
struct quaternion {
|
||||
vec3<T> xyz;
|
||||
T w;
|
||||
|
||||
quaternion operator*(const quaternion& o) const {
|
||||
return quaternion(
|
||||
o.xyz*w + xyz*o.w + xyz.cross(o.xyz),
|
||||
(T)((double)(w*o.w) - xyz.dot(o.xyz))
|
||||
);
|
||||
}
|
||||
|
||||
quaternion& operator*=(const quaternion& o) {
|
||||
*this = *this * o;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3<T> operator*(const vec3<T>& p) const {
|
||||
return (*this * quaternion(p,0) * inverted()).xyz;
|
||||
}
|
||||
|
||||
bool operator==(const quaternion& other) const {
|
||||
return xyz == other.xyz && w == other.w;
|
||||
}
|
||||
|
||||
quaternion inverted() const {
|
||||
return quaternion(-xyz, w);
|
||||
}
|
||||
|
||||
quaternion& normalize(T len = 1) {
|
||||
double L = double(xyz.getLengthSQ()) + double(w)*double(w);
|
||||
if(L == 0 || L == len)
|
||||
return *this;
|
||||
L = 1.0/sqrt(L);
|
||||
xyz *= (T)L;
|
||||
w *= (T)L;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double dot(const quaternion& other) const {
|
||||
return xyz.dot(other.xyz) + w*other.w;
|
||||
}
|
||||
|
||||
//Spherical Linear Interpolation
|
||||
//Note: Both quaternions must be unit quaternions
|
||||
quaternion slerp(const quaternion& other, T percent) const {
|
||||
if(percent <= 0.0)
|
||||
return *this;
|
||||
else if(percent >= 1.0)
|
||||
return other;
|
||||
|
||||
double _dot = dot(other);
|
||||
double omega = acos(_dot);
|
||||
|
||||
quaternion from;
|
||||
if(_dot < 0.0) {
|
||||
omega = -omega;
|
||||
from = quaternion(-xyz.x, -xyz.y, -xyz.z, -w);
|
||||
}
|
||||
else {
|
||||
from = *this;
|
||||
}
|
||||
|
||||
if(omega > 0.001) {
|
||||
T sinOmega = (T)sin(omega);
|
||||
|
||||
T p0 = (T)sin((1 - percent)*omega)/sinOmega, p1 = (T)sin(percent*omega)/sinOmega;
|
||||
|
||||
quaternion ret;
|
||||
ret.xyz = (from.xyz * p0) + (other.xyz * p1);
|
||||
ret.w = (from.w * p0) + (other.w * p1);
|
||||
|
||||
return ret.normalize();
|
||||
}
|
||||
else {
|
||||
T p0 = (1 - percent), p1 = percent;
|
||||
|
||||
quaternion ret;
|
||||
ret.xyz = (from.xyz * p0) + (other.xyz * p1);
|
||||
ret.w = (from.w * p0) + (other.w * p1);
|
||||
|
||||
return ret.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
void toMatrix(Matrix& mat) const {
|
||||
double X = xyz.x, Y = xyz.y, Z = xyz.z, W = -w;
|
||||
double Xsq = X*X, Ysq = Y*Y, Zsq = Z*Z, Wsq = W*W;
|
||||
|
||||
double XY = X*Y, XZ = X*Z, WX = X*W,
|
||||
YZ = Y*Z, WY = Y*W, WZ = W*Z;
|
||||
|
||||
mat[0] = Wsq + Xsq - Ysq - Zsq;
|
||||
mat[1] = 2.0 * (XY - WZ);
|
||||
mat[2] = 2.0 * (XZ + WY);
|
||||
mat[3] = 0;
|
||||
mat[4] = 2.0 * (XY + WZ);
|
||||
mat[5] = Wsq - Xsq + Ysq - Zsq;
|
||||
mat[6] = 2.0 * (YZ - WX);
|
||||
mat[7] = 0;
|
||||
mat[8] = 2.0 * (XZ - WY);
|
||||
mat[9] = 2.0 * (YZ + WX);
|
||||
mat[10] = Wsq - Xsq - Ysq + Zsq;
|
||||
mat[11] = 0;
|
||||
mat[12] = 0;
|
||||
mat[13] = 0;
|
||||
mat[14] = 0;
|
||||
mat[15] = Wsq + Xsq + Ysq + Zsq;
|
||||
}
|
||||
|
||||
void toTransform(Matrix& mat, const vec3<T>& translation, const double scale) const {
|
||||
const double X = xyz.x, Y = xyz.y, Z = xyz.z, W = -w;
|
||||
const double Xsq = X*X, Ysq = Y*Y, Zsq = Z*Z, Wsq = W*W;
|
||||
|
||||
const double XY = X*Y, XZ = X*Z, WX = X*W,
|
||||
YZ = Y*Z, WY = Y*W, WZ = W*Z;
|
||||
|
||||
const double commonFactor = 2.0 * scale;
|
||||
|
||||
mat[0] = scale * (Wsq + Xsq - Ysq - Zsq);
|
||||
mat[1] = commonFactor * (XY - WZ);
|
||||
mat[2] = commonFactor * (XZ + WY);
|
||||
mat[3] = 0;
|
||||
mat[4] = commonFactor * (XY + WZ);
|
||||
mat[5] = scale * (Wsq - Xsq + Ysq - Zsq);
|
||||
mat[6] = commonFactor * (YZ - WX);
|
||||
mat[7] = 0;
|
||||
mat[8] = commonFactor * (XZ - WY);
|
||||
mat[9] = commonFactor * (YZ + WX);
|
||||
mat[10] = scale * (Wsq - Xsq - Ysq + Zsq);
|
||||
mat[11] = 0;
|
||||
mat[12] = translation.x;
|
||||
mat[13] = translation.y;
|
||||
mat[14] = translation.z;
|
||||
mat[15] = Wsq + Xsq + Ysq + Zsq;
|
||||
}
|
||||
|
||||
void toTransform(Matrix& mat, const vec3<T>& translation, const vec3<T>& scale) const {
|
||||
const double X = xyz.x, Y = xyz.y, Z = xyz.z, W = -w;
|
||||
const double Xsq = X*X, Ysq = Y*Y, Zsq = Z*Z, Wsq = W*W;
|
||||
|
||||
const double XY = X*Y, XZ = X*Z, WX = X*W,
|
||||
YZ = Y*Z, WY = Y*W, WZ = W*Z;
|
||||
|
||||
mat[0] = scale.x * (Wsq + Xsq - Ysq - Zsq);
|
||||
mat[1] = (2.0 * scale.x) * (XY - WZ);
|
||||
mat[2] = (2.0 * scale.x) * (XZ + WY);
|
||||
mat[3] = 0;
|
||||
mat[4] = (2.0 * scale.y) * (XY + WZ);
|
||||
mat[5] = scale.y * (Wsq - Xsq + Ysq - Zsq);
|
||||
mat[6] = (2.0 * scale.y) * (YZ - WX);
|
||||
mat[7] = 0;
|
||||
mat[8] = (2.0 * scale.z) * (XZ - WY);
|
||||
mat[9] = (2.0 * scale.z) * (YZ + WX);
|
||||
mat[10] = scale.z * (Wsq - Xsq - Ysq + Zsq);
|
||||
mat[11] = 0;
|
||||
mat[12] = translation.x;
|
||||
mat[13] = translation.y;
|
||||
mat[14] = translation.z;
|
||||
mat[15] = Wsq + Xsq + Ysq + Zsq;
|
||||
}
|
||||
|
||||
Matrix toMatrix() const {
|
||||
double X = xyz.x, Y = xyz.y, Z = xyz.z, W = -w;
|
||||
double Xsq = X*X, Ysq = Y*Y, Zsq = Z*Z, Wsq = W*W;
|
||||
|
||||
double XY = X*Y, XZ = X*Z, WX = X*W,
|
||||
YZ = Y*Z, WY = Y*W, WZ = W*Z;
|
||||
|
||||
Matrix temp;
|
||||
temp[0] = Wsq + Xsq - Ysq - Zsq;
|
||||
temp[1] = 2.0 * (XY - WZ);
|
||||
temp[2] = 2.0 * (XZ + WY);
|
||||
//3 = 0
|
||||
temp[4] = 2.0 * (XY + WZ);
|
||||
temp[5] = Wsq - Xsq + Ysq - Zsq;
|
||||
temp[6] = 2.0 * (YZ - WX);
|
||||
//7 = 0
|
||||
temp[8] = 2.0 * (XZ - WY);
|
||||
temp[9] = 2.0 * (YZ + WX);
|
||||
temp[10] = Wsq - Xsq - Ysq + Zsq;
|
||||
//8-14 = 0
|
||||
temp[15] = Wsq + Xsq + Ysq + Zsq;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
//Builds a rotation quaternion from the rotation <Angle> radians about the <Axis>
|
||||
static quaternion fromAxisAngle(const vec3<T>& Axis, T Angle) {
|
||||
return quaternion(Axis * sin(Angle * (T)0.5), cos(Angle * (T)0.5));
|
||||
}
|
||||
|
||||
//Builds a rotation that rotates <From> into the direction of <To>
|
||||
static quaternion fromImpliedTransform(const vec3<T>& From, const vec3<T>& To) {
|
||||
double _dot = From.normalized().dot(To.normalized());
|
||||
if(_dot > 1.0)
|
||||
_dot = 1.0;
|
||||
else if(_dot < -1.0)
|
||||
_dot = -1.0;
|
||||
|
||||
double angle = -acos(_dot);
|
||||
vec3<T> axis = From.cross(To).normalized();
|
||||
if(axis.cross(To).dot(From) < 0)
|
||||
angle = -angle;
|
||||
|
||||
return quaternion::fromAxisAngle(axis, (T)angle);
|
||||
}
|
||||
|
||||
//Builds a rotation that rotates <From> into the direction of <To>, maintaining an up vector similar to <Up>
|
||||
static quaternion fromImpliedTransform(const vec3<T>& From, const vec3<T>& To, const vec3<T>& Up) {
|
||||
vec3<T> f = From.normalized(), to = To.normalized();
|
||||
double _dot = f.dot(to);
|
||||
if(_dot > 1.0)
|
||||
_dot = 1.0;
|
||||
else if(_dot < -1.0)
|
||||
_dot = -1.0;
|
||||
|
||||
double angle = -acos(_dot);
|
||||
vec3<T> axis = f.cross(to).normalized();
|
||||
if(axis.cross(to).dot(f) < 0)
|
||||
angle = -angle;
|
||||
|
||||
auto rot = quaternion::fromAxisAngle(axis, (T)angle);
|
||||
return (fromImpliedTransform(rot * Up, to.cross(Up).cross(to)) * rot).normalize();
|
||||
}
|
||||
|
||||
quaternion() : xyz(0), w(1) {}
|
||||
quaternion(T def) : xyz(def), w(def) {}
|
||||
quaternion(vec3<T> XYZ, T W) : xyz(XYZ), w(W) {}
|
||||
quaternion(T X, T Y, T Z, T W) : xyz(X,Y,Z), w(W) {}
|
||||
quaternion(const quaternion<T>& other) : xyz(other.xyz), w(other.w) {}
|
||||
};
|
||||
|
||||
typedef quaternion<float> quaternionf;
|
||||
typedef quaternion<double> quaterniond;
|
||||
@@ -0,0 +1,346 @@
|
||||
#pragma once
|
||||
#include "vec2.h"
|
||||
#include <algorithm>
|
||||
|
||||
template<class T>
|
||||
T _clip(T v, T s, T x1, T x2, T w) {
|
||||
// -_-
|
||||
return (T)(w > 0 ? (double)v+(((double)x2 - (double)x1)/(double)w)*(double)s : (double)v);
|
||||
}
|
||||
|
||||
//Generic rectangle
|
||||
template<class T>
|
||||
struct rect {
|
||||
vec2<T> topLeft;
|
||||
vec2<T> botRight;
|
||||
|
||||
rect() {}
|
||||
rect(vec2<T> a, vec2<T> b) :
|
||||
topLeft(a), botRight(b) {}
|
||||
rect(T x1, T y1, T x2, T y2) :
|
||||
topLeft(x1, y1), botRight(x2, y2) {}
|
||||
|
||||
template<class Q>
|
||||
rect(const rect<Q>& other) {
|
||||
topLeft.x = (T)other.topLeft.x;
|
||||
topLeft.y = (T)other.topLeft.y;
|
||||
botRight.x = (T)other.botRight.x;
|
||||
botRight.y = (T)other.botRight.y;
|
||||
}
|
||||
|
||||
static rect<T> area(T x, T y, T w, T h) {
|
||||
return rect<T>(x, y, x+w, y+h);
|
||||
}
|
||||
|
||||
static rect<T> area(const vec2<T> pos, const vec2<T> size) {
|
||||
return rect<T>(pos.x, pos.y, pos.x+size.width, pos.y+size.height);
|
||||
}
|
||||
|
||||
static rect<T> centered(const vec2<T> around, const vec2<T> size) {
|
||||
return area(around.x - size.x/2, around.y - size.y/2, size.width, size.height);
|
||||
}
|
||||
|
||||
static rect<T> centered(const rect<T>& within, const vec2<T> size) {
|
||||
return centered( vec2<T>((within.topLeft.x + within.botRight.x) / 2, (within.topLeft.y + within.botRight.y) / 2), size);
|
||||
}
|
||||
|
||||
bool operator==(const rect& other) {
|
||||
return topLeft == other.topLeft && botRight == other.botRight;
|
||||
}
|
||||
|
||||
rect& operator=(const rect& other) {
|
||||
topLeft = other.topLeft;
|
||||
botRight = other.botRight;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rect& operator+=(const vec2<T>& other) {
|
||||
topLeft += other;
|
||||
botRight += other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rect operator+(const vec2<T>& other) const {
|
||||
return rect(topLeft+other, botRight+other);
|
||||
}
|
||||
|
||||
rect& operator-=(const vec2<T>& other) {
|
||||
topLeft -= other;
|
||||
botRight -= other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rect operator-(const vec2<T>& other) const {
|
||||
return rect(topLeft-other, botRight-other);
|
||||
}
|
||||
|
||||
vec2<T> getSize() const {
|
||||
return botRight - topLeft;
|
||||
}
|
||||
|
||||
T getWidth() const {
|
||||
return botRight.x - topLeft.x;
|
||||
}
|
||||
|
||||
T getHeight() const {
|
||||
return botRight.y - topLeft.y;
|
||||
}
|
||||
|
||||
vec2<T> getBotLeft() const {
|
||||
return vec2<T>(topLeft.x, botRight.y);
|
||||
}
|
||||
|
||||
vec2<T> getTopRight() const {
|
||||
return vec2<T>(botRight.x, topLeft.y);
|
||||
}
|
||||
|
||||
rect<T> interpolate(const rect<T>& other, double pct) const {
|
||||
return rect<T>(
|
||||
topLeft.x + (T)((double)(other.topLeft.x - topLeft.x) * pct),
|
||||
topLeft.y + (T)((double)(other.topLeft.y - topLeft.y) * pct),
|
||||
botRight.x + (T)((double)(other.botRight.x - botRight.x) * pct),
|
||||
botRight.y + (T)((double)(other.botRight.y - botRight.y) * pct) );
|
||||
}
|
||||
|
||||
vec2<T> getCenter() const {
|
||||
return vec2<T>(
|
||||
topLeft.x + (botRight.x - topLeft.x) / 2,
|
||||
topLeft.y + (botRight.y - topLeft.y) / 2
|
||||
);
|
||||
}
|
||||
|
||||
float distanceTo(const vec2<T>& pos) {
|
||||
if(pos.x < topLeft.x) {
|
||||
if(pos.y < topLeft.y) {
|
||||
//Distance to top left corner
|
||||
float xdist = float(topLeft.x - pos.x);
|
||||
float ydist = float(topLeft.y - pos.y);
|
||||
return sqrt(xdist*xdist + ydist*ydist);
|
||||
}
|
||||
else if(pos.y > botRight.y) {
|
||||
//Distance to bottom left corner
|
||||
float xdist = float(topLeft.x - pos.x);
|
||||
float ydist = float(botRight.y - pos.y);
|
||||
return sqrt(xdist*xdist + ydist*ydist);
|
||||
}
|
||||
else {
|
||||
//Distance to left edge
|
||||
float xdist = float(topLeft.x - pos.x);
|
||||
return xdist;
|
||||
}
|
||||
}
|
||||
else if(pos.x > botRight.x) {
|
||||
if(pos.y < topLeft.y) {
|
||||
//Distance to top right corner
|
||||
float xdist = float(botRight.x - pos.x);
|
||||
float ydist = float(topLeft.y - pos.y);
|
||||
return sqrt(xdist*xdist + ydist*ydist);
|
||||
}
|
||||
else if(pos.y > botRight.y) {
|
||||
//Distance to bottom right corner
|
||||
float xdist = float(botRight.x - pos.x);
|
||||
float ydist = float(botRight.y - pos.y);
|
||||
return sqrt(xdist*xdist + ydist*ydist);
|
||||
}
|
||||
else {
|
||||
//Distance to right edge
|
||||
float xdist = float(pos.x - botRight.x);
|
||||
return xdist;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(pos.y < topLeft.y) {
|
||||
//Distance to top edge
|
||||
float ydist = float(topLeft.y - pos.y);
|
||||
return ydist;
|
||||
}
|
||||
else if(pos.y > botRight.y) {
|
||||
//Distance to bottom edge
|
||||
float ydist = float(pos.y - botRight.y);
|
||||
return ydist;
|
||||
}
|
||||
else {
|
||||
//Inside rectangle
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isWithin(const vec2<T>& pos) const {
|
||||
return pos.x >= topLeft.x && pos.y >= topLeft.y
|
||||
&& pos.x < botRight.x && pos.y < botRight.y;
|
||||
}
|
||||
|
||||
bool isRectInside(const rect<T>& other) const {
|
||||
return ((other.topLeft.x >= topLeft.x && other.topLeft.x < botRight.x)
|
||||
&& (other.botRight.x >= topLeft.x && other.botRight.x < botRight.x))
|
||||
&& ((other.topLeft.y >= topLeft.y && other.topLeft.y < botRight.y)
|
||||
&& (other.botRight.y >= topLeft.y && other.botRight.y < botRight.y));
|
||||
}
|
||||
|
||||
bool overlaps(const rect<T>& other) const {
|
||||
return topLeft.x < other.botRight.x && botRight.x > other.topLeft.x
|
||||
&& topLeft.y < other.botRight.y && botRight.y > other.topLeft.y;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return botRight.x == topLeft.x && botRight.y == topLeft.y;
|
||||
}
|
||||
|
||||
rect<T> padded(T padding) const {
|
||||
return rect<T>(topLeft.x + padding, topLeft.y + padding,
|
||||
botRight.x - padding, botRight.y - padding);
|
||||
}
|
||||
|
||||
rect<T> padded(T horiz, T vert) const {
|
||||
return rect<T>(topLeft.x + horiz, topLeft.y + vert,
|
||||
botRight.x - horiz, botRight.y - vert);
|
||||
}
|
||||
|
||||
rect<T> padded(T x1, T y1, T x2, T y2) const {
|
||||
return rect<T>(topLeft.x + x1, topLeft.y + y1,
|
||||
botRight.x - x2, botRight.y - y2);
|
||||
}
|
||||
|
||||
rect<T> resized(T w = 0, T h = 0, double horizAlign = 0.0, double vertAlign = 0.0) const {
|
||||
rect<T> result = *this;
|
||||
if(w != 0) {
|
||||
double width = getWidth();
|
||||
double diff = (width - w);
|
||||
result.topLeft.x += (T)(diff * horizAlign);
|
||||
result.botRight.x -= (T)(diff * (1.0 - horizAlign));
|
||||
}
|
||||
|
||||
if(h != 0) {
|
||||
double height = getHeight();
|
||||
double diff = (height - h);
|
||||
result.topLeft.y += (T)(diff * vertAlign);
|
||||
result.botRight.y -= (T)(diff * (1.0 - vertAlign));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rect<T> aspectAligned(double aspect, double horizAlign = 0.5, double vertAlign = 0.5) {
|
||||
double height = getHeight();
|
||||
double width = getWidth();
|
||||
|
||||
double aspectWidth = height * aspect;
|
||||
double aspectHeight = width / aspect;
|
||||
|
||||
rect<T> result = *this;
|
||||
|
||||
if(aspectWidth < width) {
|
||||
double diff = (width - aspectWidth);
|
||||
result.topLeft.x += (T)(diff * horizAlign);
|
||||
result.botRight.x -= (T)(diff * (1.0 - horizAlign));
|
||||
}
|
||||
else if(aspectHeight < height) {
|
||||
double diff = (height - aspectHeight);
|
||||
result.topLeft.y += (T)(diff * vertAlign);
|
||||
result.botRight.y -= (T)(diff * (1.0 - vertAlign));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rect<T> clipAgainst(const rect<T>& other) const {
|
||||
return rect<T>(
|
||||
std::max(topLeft.x, other.topLeft.x),
|
||||
std::max(topLeft.y, other.topLeft.y),
|
||||
std::min(botRight.x, other.botRight.x),
|
||||
std::min(botRight.y, other.botRight.y));
|
||||
}
|
||||
|
||||
rect<T> clipProportional(const rect<T>& from, const rect<T>& to) const {
|
||||
vec2<T> size = getSize();
|
||||
vec2<T> otherSize = from.getSize();
|
||||
|
||||
return rect<T>(
|
||||
_clip(topLeft.x, size.width, from.topLeft.x, to.topLeft.x, otherSize.width),
|
||||
_clip(topLeft.y, size.height, from.topLeft.y, to.topLeft.y, otherSize.height),
|
||||
_clip(botRight.x, size.width, from.botRight.x, to.botRight.x, otherSize.width),
|
||||
_clip(botRight.y, size.height, from.botRight.y, to.botRight.y, otherSize.height));
|
||||
}
|
||||
};
|
||||
|
||||
typedef rect<int> recti;
|
||||
typedef rect<float> rectf;
|
||||
typedef rect<double> rectd;
|
||||
|
||||
//Relative position specifier
|
||||
enum RelativePositionType {
|
||||
RPT_Left,
|
||||
RPT_Right,
|
||||
RPT_Top = RPT_Left,
|
||||
RPT_Bottom = RPT_Right,
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct relpos {
|
||||
RelativePositionType type;
|
||||
T pos;
|
||||
double percent;
|
||||
|
||||
relpos() : type(RPT_Left), pos(0), percent(0.0) {
|
||||
}
|
||||
|
||||
void set(RelativePositionType Type, T Pos, double Percent) {
|
||||
type = Type;
|
||||
pos = Pos;
|
||||
percent = Percent;
|
||||
}
|
||||
|
||||
void setOffset(T value) {
|
||||
pos = value;
|
||||
}
|
||||
|
||||
void setPercentage(double value) {
|
||||
percent = value;
|
||||
}
|
||||
|
||||
T evaluate(T from, T to) const {
|
||||
T rp;
|
||||
switch(type) {
|
||||
default:
|
||||
case RPT_Left:
|
||||
rp = from + pos + (T)((double)(to - from) * percent);
|
||||
break;
|
||||
case RPT_Right:
|
||||
rp = to - pos - (T)((double)(to - from) * percent);
|
||||
break;
|
||||
}
|
||||
return rp;
|
||||
}
|
||||
};
|
||||
|
||||
typedef relpos<int> relposi;
|
||||
typedef relpos<float> relposf;
|
||||
typedef relpos<double> relposd;
|
||||
|
||||
//Relative position rectangle
|
||||
template<class T>
|
||||
struct relrect {
|
||||
relpos<T> left, top;
|
||||
relpos<T> right, bottom;
|
||||
|
||||
relrect() {
|
||||
right.type = RPT_Right;
|
||||
bottom.type = RPT_Bottom;
|
||||
}
|
||||
|
||||
recti evaluate(const recti& pos) const {
|
||||
recti out;
|
||||
|
||||
out.topLeft.x = left.evaluate(pos.topLeft.x, pos.botRight.x);
|
||||
out.topLeft.y = top.evaluate(pos.topLeft.y, pos.botRight.y);
|
||||
|
||||
out.botRight.x = right.evaluate(pos.topLeft.x, pos.botRight.x);
|
||||
out.botRight.y = bottom.evaluate(pos.topLeft.y, pos.botRight.y);
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
typedef relrect<int> relrecti;
|
||||
typedef relrect<float> relrectf;
|
||||
typedef relrect<double> relrectd;
|
||||
@@ -0,0 +1,11 @@
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <emmintrin.h>
|
||||
#define HAVE_SSE
|
||||
#define m128d_f64(reg, num) reg._m128d_f64[num]
|
||||
#endif
|
||||
|
||||
#if defined(__GNUG__) && defined(__amd64__)
|
||||
#include <emmintrin.h>
|
||||
#define HAVE_SSE
|
||||
#define m128d_f64(reg, num) reg[num]
|
||||
#endif
|
||||
@@ -0,0 +1,248 @@
|
||||
#pragma once
|
||||
#include "color.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <stack>
|
||||
|
||||
//Get the equivalent character in different case
|
||||
char lowercase(char c);
|
||||
char uppercase(char c);
|
||||
|
||||
//Convert a standard string's case
|
||||
void toLowercase(std::string& str);
|
||||
void toUppercase(std::string& str);
|
||||
|
||||
//Compares c-style strings a and b, ignoring case
|
||||
//Returns 0 if the strings are equal, the the difference of the first unequal character otherwise
|
||||
char strcmp_nocase(const char* a, const char* b);
|
||||
|
||||
//Compares standard strings a and b, ignoring case
|
||||
bool streq_nocase(const std::string& a, const std::string& b);
|
||||
bool streq_nocase(const std::string& str, const std::string& substr, unsigned start, unsigned length = 0);
|
||||
int strfind_nocase(const std::string& str, const std::string& substr, unsigned start = 0);
|
||||
|
||||
//Convert special characters to escape sequences in a string
|
||||
std::string escape(const std::string& text);
|
||||
|
||||
//Convert literal escape sequences in a string
|
||||
std::string unescape(const std::string& text);
|
||||
|
||||
//Escape a case-sensitive string for use on a case-insensitive filesystem
|
||||
std::string escapeCase(const std::string& text);
|
||||
|
||||
//Unescape a case-insensitive filename to a case-sensitive string
|
||||
std::string unescapeCase(const std::string& text);
|
||||
|
||||
//Checks to make sure the string is a valid identifier
|
||||
bool isIdentifier(const std::string& identifier, const char* extraChars = nullptr);
|
||||
void makeIdentifier(std::string& identifier, const char* extraChars = nullptr);
|
||||
|
||||
//Split a line into Key: Value
|
||||
bool splitKeyValue(const std::string& input, std::string& key, std::string& value, const char* split = ":");
|
||||
|
||||
//Do some basic line parsing operations in addition to splitting
|
||||
bool parseKeyValue(std::string& input, std::string& key, std::string& value);
|
||||
|
||||
//Directly read key-value pairs from a file doing some parsing
|
||||
bool readKeyValue(std::ifstream& file, std::string& key, std::string& value);
|
||||
|
||||
//Iterator that reads key/value pairs and parses includes
|
||||
struct DataReader {
|
||||
struct FilePosition {
|
||||
std::ifstream* file;
|
||||
std::string filename;
|
||||
int line;
|
||||
};
|
||||
|
||||
std::stack<FilePosition> files;
|
||||
bool allowLines, fullLine, allowMultiline, inMultiline, squash;
|
||||
bool skipComments, skipEmpty;
|
||||
int indent;
|
||||
std::string line;
|
||||
std::string key, value;
|
||||
|
||||
DataReader();
|
||||
DataReader(const std::string& filename, bool AllowLines = true);
|
||||
~DataReader();
|
||||
void open(const std::string& filename);
|
||||
bool feed(const std::string& line);
|
||||
bool handle();
|
||||
bool operator++(int);
|
||||
std::string position();
|
||||
};
|
||||
|
||||
void skipBOM(std::ifstream& stream);
|
||||
|
||||
struct DataHandler {
|
||||
struct BlockHandler {
|
||||
std::function<bool(std::string&)> openHandler;
|
||||
std::function<void()> closeHandler;
|
||||
std::unordered_map<std::string, std::function<void(std::string&)>> handlers;
|
||||
std::function<void(std::string&)> lineHandlerCB;
|
||||
std::function<void(std::string&,std::string&)> defaultHandlerCB;
|
||||
std::unordered_map<std::string, BlockHandler*> blocks;
|
||||
|
||||
BlockHandler& block(const std::string& name);
|
||||
void openBlock(std::function<bool(std::string&)> cb);
|
||||
void closeBlock(std::function<void()> cb);
|
||||
void lineHandler(std::function<void(std::string&)> cb);
|
||||
void defaultHandler(std::function<void(std::string&, std::string&)> cb);
|
||||
void operator()(const std::string& name, std::function<void(std::string&)> cb);
|
||||
|
||||
~BlockHandler();
|
||||
};
|
||||
DataReader datafile;
|
||||
BlockHandler* curHandler;
|
||||
int curIndent;
|
||||
|
||||
std::stack<std::pair<BlockHandler*, int>> blockStack;
|
||||
BlockHandler defaultBlock;
|
||||
std::function<bool(std::string&)> controller;
|
||||
DataReader::FilePosition* pos;
|
||||
|
||||
BlockHandler& block(const std::string& name);
|
||||
void enterBlock(const std::string& blockName);
|
||||
void lineHandler(std::function<void(std::string&)> cb);
|
||||
void defaultHandler(std::function<void(std::string&, std::string&)> cb);
|
||||
void controlHandler(std::function<bool(std::string&)> cb);
|
||||
void operator()(const std::string& name, std::function<void(std::string&)> cb);
|
||||
|
||||
std::string position();
|
||||
void feed(const std::string& line);
|
||||
void handle();
|
||||
void end();
|
||||
|
||||
void read(const std::string& filename);
|
||||
};
|
||||
|
||||
#define HANDLE_BOOL(handler, key, obj, member) handler(key, [&](std::string& value) {\
|
||||
if(obj)\
|
||||
obj->member = toBool(value);\
|
||||
});
|
||||
|
||||
#define HANDLE_NUM(handler, key, obj, member) handler(key, [&](std::string& value) {\
|
||||
if(obj)\
|
||||
obj->member = toNumber<decltype(obj->member)>(value);\
|
||||
});
|
||||
|
||||
#define HANDLE_ENUM_W(handler, key, obj, member, Enum, ShowErrors) handler(key, [&](std::string& value) {\
|
||||
if(obj) {\
|
||||
auto it = Enum.find(value);\
|
||||
if(it != Enum.end())\
|
||||
obj->member = it->second;\
|
||||
else if(ShowErrors)\
|
||||
error("Unrecognized " key " '%s'", value.c_str());\
|
||||
}\
|
||||
});
|
||||
|
||||
#define HANDLE_ENUM(handler, key, obj, member, Enum) HANDLE_ENUM_W(handler, key, obj, member, Enum, true)
|
||||
|
||||
//Generic string split
|
||||
void split(const std::string& input, std::vector<std::string>& out, char delimit, bool trim = false, bool listEmpty = false);
|
||||
void split(const std::string& input, std::vector<std::string>& out, const char* delimit, bool trim = false, bool listEmpty = false);
|
||||
|
||||
//Splits a string of the format:
|
||||
// front<delim_front>inner<delim_back>back
|
||||
//Back is optional
|
||||
//If both delimeters are not found, returns false and nothing is done to front, inner, or back
|
||||
//If both delimteres are found, returns true and front, inner, and back are set to the corresponding sub-strings without trimming
|
||||
bool split(const std::string& input, std::string& front, char delim_front, std::string& inner, char delim_back, std::string* back = 0);
|
||||
|
||||
//Split a function call into parts
|
||||
bool funcSplit(const std::string& input, std::string& name, std::vector<std::string>& arguments, bool strip = true);
|
||||
|
||||
//Match a string for a set of expressions with wildcards
|
||||
typedef std::vector<std::string> CompiledPattern;
|
||||
void compile_pattern(const char* pattern, CompiledPattern& out);
|
||||
bool match(const char* name, const char* pattern);
|
||||
bool match(const char* name, const CompiledPattern& parts);
|
||||
|
||||
//Trim whitespace from both ends of the string
|
||||
std::string trim(const std::string& input);
|
||||
std::string trim(const std::string& input, const char* trimChars);
|
||||
|
||||
//Replace characters in a string
|
||||
void replaceChar(std::string& str, char replace, char with);
|
||||
std::string& replace(std::string& str, const std::string& replace, const std::string& with);
|
||||
std::string replaced(const std::string& str, const std::string& replace, const std::string& with);
|
||||
std::string& paragraphize(std::string& input, const std::string& parSep, const std::string& lineSep, bool startsParagraph = false);
|
||||
|
||||
//Standardize a number into a string representation
|
||||
std::string standardize(double val, bool showIntegral = false, bool roundUp = false);
|
||||
std::string formatLargeNum(double val);
|
||||
|
||||
//Read number from string
|
||||
template <class T>
|
||||
T toNumber(const std::string& str, T def = 0, std::ios_base& (*base)(std::ios_base&) = std::dec) {
|
||||
std::istringstream is(str);
|
||||
T output;
|
||||
if((is >> base >> output).fail())
|
||||
return def;
|
||||
return output;
|
||||
}
|
||||
|
||||
//Write number to stream
|
||||
template <class T>
|
||||
std::string toString(T num, unsigned precision = 0) {
|
||||
std::stringstream out;
|
||||
out.precision(precision);
|
||||
out << std::fixed;
|
||||
out << num;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
//Write color to string
|
||||
template<>
|
||||
std::string toString(Color color, unsigned precision);
|
||||
|
||||
//Read color from string, two possible formats: "rrggbbaa", "rr gg bb aa"
|
||||
//(alpha is optional in both cases)
|
||||
Color toColor(const std::string& str);
|
||||
|
||||
//Read boolean from string
|
||||
bool toBool(const std::string& str, bool def = false);
|
||||
|
||||
//Convert an amount of bytes to a neatly displayed size
|
||||
std::string toSize(int bytes);
|
||||
|
||||
//Convert to a std::string containing a roman numeral representation of numIn;
|
||||
//Supports numbers up to 999; Appends the result to the given string
|
||||
void romanNumerals(unsigned int numIn, std::string& romanOut);
|
||||
|
||||
//Requires that romanOut points to an array of at least 13 char's
|
||||
void romanNumerals(unsigned int numIn, char* romanOut);
|
||||
|
||||
//Join strings in a vector
|
||||
std::string join(std::vector<std::string>& list, const char* delimiter = "\n", bool delim_final = true);
|
||||
|
||||
//Utilities for manipulating utf-8 text
|
||||
//Return the char position of the count-th unicode
|
||||
//character from char position start
|
||||
int u8pos(const std::string& str, int start, int count = 1);
|
||||
//Return the unicode character at char position pos
|
||||
int u8get(const std::string& str, int pos);
|
||||
//Increments pos to the char position of the next
|
||||
//unicode character, and sets point to the passed character
|
||||
void u8next(const std::string& str, int& pos, int& point);
|
||||
//Decrements pos to the char position of the previous
|
||||
//unicode character, and sets point to the passed character
|
||||
void u8prev(const std::string& str, int& pos, int& point);
|
||||
//Append a unicode code point to a utf-8 string
|
||||
void u8append(std::string& str, int point);
|
||||
//Convert unicode code point to four utf-8 chars
|
||||
int u8(int point);
|
||||
|
||||
//Iterator for utf-8
|
||||
struct u8it {
|
||||
const char* str;
|
||||
u8it(const std::string& Str);
|
||||
u8it(const char* Str);
|
||||
int operator++(int);
|
||||
};
|
||||
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
#include "constants.h"
|
||||
|
||||
template<class T>
|
||||
struct vec2 {
|
||||
union {
|
||||
T x;
|
||||
T width;
|
||||
};
|
||||
|
||||
union {
|
||||
T y;
|
||||
T height;
|
||||
};
|
||||
|
||||
double distanceTo(const vec2<T>& other) const {
|
||||
double tX = (double)(other.x - x);
|
||||
double tY = (double)(other.y - y);
|
||||
|
||||
return sqrt((tX * tX)+(tY * tY));
|
||||
}
|
||||
|
||||
double distanceToSQ(const vec2<T>& other) const {
|
||||
double tX = (double)(other.x - x);
|
||||
double tY = (double)(other.y - y);
|
||||
|
||||
return (tX * tX)+(tY * tY);
|
||||
}
|
||||
|
||||
double length() const {
|
||||
double dx = (double)x;
|
||||
double dy = (double)y;
|
||||
return sqrt((dx*dx) + (dy*dy));
|
||||
}
|
||||
|
||||
double lengthSQ() const {
|
||||
double dx = (double)x;
|
||||
double dy = (double)y;
|
||||
return (dx*dx) + (dy*dy);
|
||||
}
|
||||
|
||||
vec2 operator*(double scalar) const {
|
||||
return vec2<T>((T)((double)x * scalar), (T)((double)y * scalar));
|
||||
}
|
||||
|
||||
vec2& operator*=(double scalar) {
|
||||
x = (T)((double)x * scalar);
|
||||
y = (T)((double)y * scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2 operator/(double scalar) const {
|
||||
return vec2<T>((T)((double)x / scalar), (T)((double)y / scalar));
|
||||
}
|
||||
|
||||
vec2& operator/=(double scalar) {
|
||||
x = (T)((double)x / scalar);
|
||||
y = (T)((double)y / scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2 operator+(const vec2& other) const {
|
||||
return vec2(x+other.x, y+other.y);
|
||||
}
|
||||
|
||||
vec2& operator+=(const vec2& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2 operator-() const {
|
||||
return vec2(-x, -y);
|
||||
}
|
||||
|
||||
vec2 operator-(const vec2& other) const {
|
||||
return vec2(x-other.x, y-other.y);
|
||||
}
|
||||
|
||||
vec2& operator-=(const vec2& other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2& operator=(const vec2& other) {
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set(T X, T Y) {
|
||||
x = X;
|
||||
y = Y;
|
||||
}
|
||||
|
||||
bool operator==(const vec2& other) const {
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
bool operator!=(const vec2& other) const {
|
||||
return x != other.x || y != other.y;
|
||||
}
|
||||
|
||||
double radians() const {
|
||||
return atan2((double)y, (double)x);
|
||||
}
|
||||
|
||||
vec2& normalize(T length = (T)1.0) {
|
||||
double X = x, Y = y,
|
||||
L = (X*X)+(Y*Y);
|
||||
if(L == 0.0)
|
||||
return *this;
|
||||
L = (double)length / sqrt(L);
|
||||
|
||||
x = (T)(X*L);
|
||||
y = (T)(Y*L);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2 normalized(T length = (T)1.0) const {
|
||||
vec2 temp(*this);
|
||||
temp.normalize(length);
|
||||
return temp;
|
||||
}
|
||||
|
||||
double dot(const vec2& other) const {
|
||||
return (double)x*(double)other.x + (double)y*(double)other.y;
|
||||
}
|
||||
|
||||
vec2& rotate(double radians) {
|
||||
double c = cos(radians), s = sin(radians);
|
||||
|
||||
double nX = (double)x * c - (double)y * s;
|
||||
double nY = (double)y * c + (double)x * s;
|
||||
|
||||
x = (T)nX;
|
||||
y = (T)nY;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec2 rotated(double radians) {
|
||||
double c = cos(radians), s = sin(radians);
|
||||
|
||||
double nX = (double)x * c - (double)y * s;
|
||||
double nY = (double)y * c + (double)x * s;
|
||||
|
||||
return vec2((T)nX, (T)nY);
|
||||
}
|
||||
|
||||
double getRotation(const vec2& other) const {
|
||||
double from = radians() + twopi;
|
||||
double to = other.radians() + twopi;
|
||||
double diff = (to - from);
|
||||
if(diff < 0)
|
||||
diff = twopi + diff;
|
||||
return diff;
|
||||
}
|
||||
|
||||
vec2() : x(0), y(0) {}
|
||||
explicit vec2(T def) : x(def), y(def) {}
|
||||
explicit vec2(T X, T Y) : x(X), y(Y) {}
|
||||
|
||||
template<class Q>
|
||||
vec2(const vec2<Q>& other)
|
||||
: x((T)other.x), y((T)other.y) {}
|
||||
};
|
||||
|
||||
typedef vec2<double> vec2d;
|
||||
typedef vec2<float> vec2f;
|
||||
typedef vec2<int> vec2i;
|
||||
typedef vec2<unsigned> vec2u;
|
||||
@@ -0,0 +1,292 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
//3 Dimensional Vector structure
|
||||
template<class T = double>
|
||||
struct vec3 {
|
||||
T x,y,z;
|
||||
|
||||
vec3() : x(0), y(0), z(0) {}
|
||||
explicit vec3(T def) : x(def), y(def), z(def) {}
|
||||
explicit vec3(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
|
||||
|
||||
template<class O>
|
||||
explicit vec3(const vec3<O>& other) : x((T)other.x), y((T)other.y), z((T)other.z) {}
|
||||
|
||||
static vec3 up(T len = (T)1.0) { return vec3(0,len,0); }
|
||||
static vec3 front(T len = (T)1.0) { return vec3(len,0,0); }
|
||||
static vec3 right(T len = (T)1.0) { return vec3(0,0,-len); }
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
|
||||
double distanceTo(const vec3& other) const {
|
||||
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
|
||||
reg0 = _mm_sub_sd(reg0, reg1);
|
||||
__m128d reg2 = _mm_set_sd(y);
|
||||
reg0 = _mm_mul_sd(reg0, reg0);
|
||||
reg1 = _mm_set_sd(other.y);
|
||||
reg1 = _mm_sub_sd(reg2, reg1);
|
||||
__m128d reg3 = _mm_set_sd(z);
|
||||
reg1 = _mm_mul_sd(reg1, reg1);
|
||||
reg2 = _mm_set_sd(other.z);
|
||||
reg0 = _mm_add_sd(reg0, reg1);
|
||||
reg2 = _mm_sub_sd(reg3, reg2);
|
||||
reg2 = _mm_mul_sd(reg2, reg2);
|
||||
reg0 = _mm_add_sd(reg0, reg2);
|
||||
reg0 = _mm_sqrt_sd(reg0, reg0);
|
||||
return reg0.m128d_f64[0];
|
||||
}
|
||||
|
||||
double distanceToSQ(const vec3& other) const {
|
||||
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
|
||||
reg0 = _mm_sub_sd(reg0, reg1);
|
||||
__m128d reg2 = _mm_set_sd(y);
|
||||
reg0 = _mm_mul_sd(reg0, reg0);
|
||||
reg1 = _mm_set_sd(other.y);
|
||||
reg1 = _mm_sub_sd(reg2, reg1);
|
||||
__m128d reg3 = _mm_set_sd(z);
|
||||
reg1 = _mm_mul_sd(reg1, reg1);
|
||||
reg2 = _mm_set_sd(other.z);
|
||||
reg0 = _mm_add_sd(reg0, reg1);
|
||||
reg2 = _mm_sub_sd(reg3, reg2);
|
||||
reg2 = _mm_mul_sd(reg2, reg2);
|
||||
reg0 = _mm_add_sd(reg0, reg2);
|
||||
return reg0.m128d_f64[0];
|
||||
}
|
||||
|
||||
T getLength() const {
|
||||
__m128d reg0 = _mm_set_sd(x);
|
||||
reg0 = _mm_mul_sd(reg0, reg0);
|
||||
__m128d reg1 = _mm_set_sd(y);
|
||||
reg1 = _mm_mul_sd(reg1, reg1);
|
||||
__m128d reg2 = _mm_set_sd(z);
|
||||
reg2 = _mm_mul_sd(reg2, reg2);
|
||||
reg0 = _mm_add_sd(reg0, reg1);
|
||||
reg0 = _mm_add_sd(reg0, reg2);
|
||||
reg0 = _mm_sqrt_sd(reg0, reg0);
|
||||
return reg0.m128d_f64[0];
|
||||
}
|
||||
|
||||
T getLengthSQ() const {
|
||||
__m128d reg0 = _mm_set_sd(x);
|
||||
reg0 = _mm_mul_sd(reg0, reg0);
|
||||
__m128d reg1 = _mm_set_sd(y);
|
||||
reg1 = _mm_mul_sd(reg1, reg1);
|
||||
__m128d reg2 = _mm_set_sd(z);
|
||||
reg2 = _mm_mul_sd(reg2, reg2);
|
||||
reg0 = _mm_add_sd(reg0, reg1);
|
||||
reg0 = _mm_add_sd(reg0, reg2);
|
||||
return reg0.m128d_f64[0];
|
||||
}
|
||||
|
||||
double dot(const vec3& other) const {
|
||||
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
|
||||
reg0 = _mm_mul_sd(reg0, reg1);
|
||||
__m128d reg2 = _mm_set_sd(y);
|
||||
reg1 = _mm_set_sd(other.y);
|
||||
reg1 = _mm_mul_sd(reg2, reg1);
|
||||
__m128d reg3 = _mm_set_sd(z);
|
||||
reg0 = _mm_add_sd(reg0, reg1);
|
||||
reg2 = _mm_set_sd(other.z);
|
||||
reg2 = _mm_mul_sd(reg3, reg2);
|
||||
reg0 = _mm_add_sd(reg0, reg2);
|
||||
return reg0.m128d_f64[0];
|
||||
}
|
||||
#else
|
||||
|
||||
double distanceTo(const vec3& other) const {
|
||||
double tx = x-other.x,
|
||||
ty = y-other.y,
|
||||
tz = z-other.z;
|
||||
return sqrt((tx*tx)+(ty*ty)+(tz*tz));
|
||||
}
|
||||
|
||||
double distanceToSQ(const vec3& other) const {
|
||||
double tx = x-other.x,
|
||||
ty = y-other.y,
|
||||
tz = z-other.z;
|
||||
return ((tx*tx)+(ty*ty)+(tz*tz));
|
||||
}
|
||||
|
||||
T getLength() const {
|
||||
return (T)sqrt((double)(x*x)+(double)(y*y)+(double)(z*z));
|
||||
}
|
||||
|
||||
T getLengthSQ() const {
|
||||
return (x*x)+(y*y)+(z*z);
|
||||
}
|
||||
|
||||
double dot(const vec3& other) const {
|
||||
return (double(x)*double(other.x)) + (double(y)*double(other.y)) + (double(z)*double(other.z));
|
||||
}
|
||||
#endif
|
||||
|
||||
double angleDistance(const vec3& other) const {
|
||||
double _dot = dot(other);
|
||||
if(_dot < -1.0)
|
||||
_dot = -1.0;
|
||||
else if(_dot > 1.0)
|
||||
_dot = 1.0;
|
||||
|
||||
return acos(_dot);
|
||||
}
|
||||
|
||||
vec3 cross(const vec3& other) const {
|
||||
return vec3(
|
||||
(y*other.z)-(z*other.y),
|
||||
(z*other.x)-(x*other.z),
|
||||
(x*other.y)-(y*other.x) );
|
||||
}
|
||||
|
||||
vec3 operator+(const vec3& other) const {
|
||||
return vec3(x+other.x, y+other.y, z+other.z);
|
||||
}
|
||||
|
||||
vec3& operator+=(const vec3& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3 operator-() const {
|
||||
return vec3(-x, -y, -z);
|
||||
}
|
||||
|
||||
vec3 operator-(const vec3& other) const {
|
||||
return vec3(x-other.x, y-other.y, z-other.z);
|
||||
}
|
||||
|
||||
vec3& operator-=(const vec3& other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3 operator*(const vec3& other) const {
|
||||
return vec3(x*other.x, y*other.y, z*other.z);
|
||||
}
|
||||
|
||||
vec3 operator*(double scalar) const {
|
||||
return vec3(T((double)x*scalar), T((double)y*scalar), T((double)z*scalar));
|
||||
}
|
||||
|
||||
vec3& operator*=(double scalar) {
|
||||
x = T((double)x * scalar);
|
||||
y = T((double)y * scalar);
|
||||
z = T((double)z * scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3 operator/(double scalar) const {
|
||||
return vec3(T((double)x/scalar), T((double)y/scalar), T((double)z/scalar));
|
||||
}
|
||||
|
||||
vec3& operator/=(double scalar) {
|
||||
x = T((double)x / scalar);
|
||||
y = T((double)y / scalar);
|
||||
z = T((double)z / scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3& operator=(const vec3& other) {
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
z = other.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const vec3& other) const {
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
|
||||
bool operator!=(const vec3& other) const {
|
||||
return x != other.x || y != other.y || z != other.z;
|
||||
}
|
||||
|
||||
vec3 interpolate(const vec3& other, double pct) const {
|
||||
return *this + (other - *this) * pct;
|
||||
}
|
||||
|
||||
//Spherically interpolate between normalized vectors
|
||||
vec3 slerp(const vec3& other, double pct) const {
|
||||
if(pct >= 1.0)
|
||||
return other;
|
||||
if(pct <= 0.0)
|
||||
return *this;
|
||||
|
||||
double _dot = dot(other);
|
||||
if(_dot > 0.999)
|
||||
return interpolate(other, pct);
|
||||
if(_dot <= -1.0) {
|
||||
//Normally this would reduce to lerp, but we know we want to rotate in some direction instead
|
||||
// We find a vector perpendicular to our endpoints and interpolate based on our progress
|
||||
vec3 temp = cross(vec3::up());
|
||||
if(temp.zero())
|
||||
return other;
|
||||
else if(pct < 0.5)
|
||||
return slerp(temp, pct * 2.0);
|
||||
else
|
||||
return temp.slerp(other, (pct - 0.5) * 2.0);
|
||||
}
|
||||
|
||||
double omega = acos(_dot);
|
||||
if(omega < 0.001)
|
||||
return interpolate(other, pct);
|
||||
|
||||
double sinOmg = sin(omega);
|
||||
return ((*this * sin((1.0 - pct)*omega)/sinOmg) + (other * sin(pct * omega)/sinOmg)).normalized();
|
||||
}
|
||||
|
||||
vec3& normalize(T length = (T)1.0) {
|
||||
double X = x, Y = y, Z = z,
|
||||
L = (X*X)+(Y*Y)+(Z*Z);
|
||||
if(L == 0.0)
|
||||
return *this;
|
||||
L = (double)length / sqrt(L);
|
||||
|
||||
x = (T)(X*L);
|
||||
y = (T)(Y*L);
|
||||
z = (T)(Z*L);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vec3 normalized(T length = (T)1.0) const {
|
||||
vec3 temp(*this);
|
||||
temp.normalize(length);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void set(T X, T Y, T Z) {
|
||||
x = X;
|
||||
y = Y;
|
||||
z = Z;
|
||||
}
|
||||
|
||||
vec3<T> elementMax(const vec3<T>& other) const {
|
||||
return vec3<T>(
|
||||
x > other.x ? x : other.x,
|
||||
y > other.y ? y : other.y,
|
||||
z > other.z ? z : other.z);
|
||||
}
|
||||
|
||||
vec3<T> elementMin(const vec3<T>& other) const {
|
||||
return vec3<T>(
|
||||
x < other.x ? x : other.x,
|
||||
y < other.y ? y : other.y,
|
||||
z < other.z ? z : other.z);
|
||||
}
|
||||
|
||||
bool zero() {
|
||||
return x == 0.0 && y == 0.0 && z == 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef vec3<float> vec3f;
|
||||
typedef vec3<double> vec3d;
|
||||
typedef vec3<int> vec3i;
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
//4 Dimensional Vector structure
|
||||
template<class T = double>
|
||||
struct vec4 {
|
||||
T x,y,z,w;
|
||||
|
||||
vec4() : x(0), y(0), z(0), w(0) {}
|
||||
vec4(T def) : x(def), y(def), z(def), w(def) {}
|
||||
vec4(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {}
|
||||
|
||||
template<class O>
|
||||
explicit vec4(const vec4<O>& other) : x((T)other.x), y((T)other.y), z((T)other.z), w((T)other.w) {}
|
||||
|
||||
vec4& operator=(const vec4& other) {
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
z = other.z;
|
||||
w = other.w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const vec4& other) {
|
||||
return x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
}
|
||||
|
||||
vec4 operator*(T scalar) const {
|
||||
return vec4(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
vec4& operator+=(const vec4& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
w += other.w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool zero() {
|
||||
return x == 0.0 && y == 0.0 && z == 0.0 && w == 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef vec4<float> vec4f;
|
||||
typedef vec4<double> vec4d;
|
||||
typedef vec4<int> vec4i;
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "vec3.h"
|
||||
|
||||
struct Vertex {
|
||||
float u, v;
|
||||
vec3f normal, position;
|
||||
|
||||
Vertex() : u(0), v(0) {}
|
||||
explicit Vertex(const vec3f& pos) : position(pos), normal(pos.normalized()), u(0), v(0) {}
|
||||
explicit Vertex(const vec3f& pos, float U, float V) : position(pos), normal(pos.normalized()), u(U), v(V) {}
|
||||
};
|
||||
Reference in New Issue
Block a user