Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+182
View File
@@ -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
+80
View File
@@ -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
+189
View File
@@ -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;
+196
View File
@@ -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;
}
}
};
+13
View File
@@ -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
+37
View File
@@ -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;
}
};
+271
View File
@@ -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);
+113
View File
@@ -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;
+142
View File
@@ -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;
}
};
+30
View File
@@ -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;
};
+11
View File
@@ -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;
}
+34
View File
@@ -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;
+241
View File
@@ -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;
+346
View File
@@ -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;
+11
View File
@@ -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
+248
View File
@@ -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);
};
+174
View File
@@ -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;
+292
View File
@@ -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;
+46
View File
@@ -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;
+11
View File
@@ -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) {}
};