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
+100
View File
@@ -0,0 +1,100 @@
#Find the correct architecture to build for
ifndef ARCH
ARCH = $(shell getconf LONG_BIT)
endif
#Set correct flags for architecture
ifeq ($(ARCH), 32)
#Global
CXXFLAGS += -m32 -march=core2 -mtune=generic
#Arch name
ARCHNAME = x86
else
#Global
CXXFLAGS += -m64 -march=athlon64 -mtune=generic
#Arch name
ARCHNAME = x64
endif
#Global flags
ifeq ($(origin AR), default)
AR = gcc-ar
endif
BIN = libutil.a
SRCDIR = source/util/source
UNAME = $(shell uname)
ifeq ($(UNAME), Darwin)
OSNAME = osx
else
OSNAME = lin
endif
ifdef DEBUG
OBJDIR = obj_d/$(OSNAME)$(ARCH)/util
BINDIR = obj_d/$(OSNAME)$(ARCH)
CXXFLAGS += -O0 -g
CXXFLAGS += -D_DEBUG
else
OBJDIR = obj/$(OSNAME)$(ARCH)/util
BINDIR = obj/$(OSNAME)$(ARCH)
CXXFLAGS += -Ofast
CXXFLAGS += -DNDEBUG
ifndef NLTO
CXXFLAGS += -flto
else
CXXFLAGS += -fno-lto
endif
endif
ifeq ($(UNAME), Darwin)
CXXFLAGS += -I/usr/local/Cellar/libpng/1.6.12/include
LDFLAGS += -L/usr/local/Cellar/libpng/1.6.12/lib
endif
ifndef CC
CC = g++
endif
CXXFLAGS += -std=c++11
CXXFLAGS += -Wall -Wno-invalid-offsetof -Wno-switch -Wno-reorder
CXXFLAGS += -I./source/util/include -I./source/util/source
#Source code files
SOURCES = \
image.cpp \
str_util.cpp \
bilinear.cpp \
Vector.cpp \
CPP_FILES = $(addprefix $(SRCDIR)/, $(SOURCES))
OBJ_FILES = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.o))
DEP_FILES = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.d))
-include $(DEP_FILES)
compile: $(DEP_FILES) $(BINDIR)/$(BIN)
#Dependency files to take care of header changes
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
@mkdir -p $(dir $@)
@$(CC) $(CXXFLAGS) -MM -MT "$(@:.d=.o)" $< >> $@
#Object files are compiled separately
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
@mkdir -p $(dir $@)
@echo $<
@$(CC) $(CXXFLAGS) $< -c -o $@
#Complete binary compile
$(BINDIR)/$(BIN): $(OBJ_FILES)
@mkdir -p $(BINDIR)
$(AR) rcs $@ $^
clean:
@rm -rf $(OBJDIR)
@rm -f ./.depend
+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) {}
};
+12
View File
@@ -0,0 +1,12 @@
#include "BiPatch/Vector.h"
#include <iostream>
namespace BiPatch {
Vector Vector::normal() const {
Vector v1(*this);
v1.normalize();
return v1;
}
};
+433
View File
@@ -0,0 +1,433 @@
//created by Shaun David Ramsey and Kristin Potter (c) 20003
//email ramsey()cs.utah.edu with questions/comments
/*
The ray bilinear patch intersection software are "Open Source"
according to the MIT License located 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 "BiPatch/bilinear.h"
#include <iostream>
#include <cmath>
#ifdef _MSC_VER
#define copysign _copysign
#endif
namespace BiPatch {
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
// Constructor
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
BilinearPatch::BilinearPatch(Vector Pt00, Vector Pt01, Vector Pt10, Vector Pt11)
{
P00 = Pt00;
P01 = Pt01;
P10 = Pt10;
P11 = Pt11;
}
// What is the x,y,z position of a point at params u and v?
Vector BilinearPatch::SrfEval( double u, double v)
{
Vector respt;
respt.x( ( (1.0 - u) * (1.0 - v) * P00.x() +
(1.0 - u) * v * P01.x() +
u * (1.0 - v) * P10.x() +
u * v * P11.x()));
respt.y( ( (1.0 - u) * (1.0 - v) * P00.y() +
(1.0 - u) * v * P01.y() +
u * (1.0 - v) * P10.y() +
u * v * P11.y()));
respt.z( ( (1.0 - u) * (1.0 - v) * P00.z() +
(1.0 - u) * v * P01.z() +
u * (1.0 - v) * P10.z() +
u * v * P11.z()));
return respt;
}
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
// Find tangent (du)
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
Vector BilinearPatch::TanU( double v)
{
Vector tanu;
tanu.x( ( 1.0 - v ) * (P10.x() - P00.x()) + v * (P11.x() - P01.x()));
tanu.y( ( 1.0 - v ) * (P10.y() - P00.y()) + v * (P11.y() - P01.y()));
tanu.z( ( 1.0 - v ) * (P10.z() - P00.z()) + v * (P11.z() - P01.z()));
return tanu;
}
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
// Find tanget (dv)
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
Vector BilinearPatch::TanV( double u)
{
Vector tanv;
tanv.x( ( 1.0 - u ) * (P01.x() - P00.x()) + u * (P11.x() - P10.x()) );
tanv.y( ( 1.0 - u ) * (P01.y() - P00.y()) + u * (P11.y() - P10.y()) );
tanv.z( ( 1.0 - u ) * (P01.z() - P00.z()) + u * (P11.z() - P10.z()) );
return tanv;
}
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
// Find the normal of the patch
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
Vector BilinearPatch::Normal( double u, double v)
{
Vector tanu,tanv;
tanu = TanU( v );
tanv = TanV( u );
return tanu.cross(tanv);
}
//choose between the best denominator to avoid singularities
//and to get the most accurate root possible
inline double getu(double v, double M1, double M2, double J1,double J2,
double K1, double K2, double R1, double R2)
{
double denom = (v*(M1-M2)+J1-J2);
double d2 = (v*M1+J1);
if(fabs(denom) > fabs(d2)) // which denominator is bigger
{
return (v*(K2-K1)+R2-R1)/denom;
}
return -(v*K1+R1)/d2;
}
// compute t with the best accuracy by using the component
// of the direction that is largest
double computet(Vector dir, Vector orig, Vector srfpos)
{
// if x is bigger than y and z
if(fabs(dir.x()) >= fabs(dir.y()) && fabs(dir.x()) >= fabs(dir.z()))
return (srfpos.x() - orig.x()) / dir.x();
// if y is bigger than x and z
else if(fabs(dir.y()) >= fabs(dir.z())) // && fabs(dir.y()) >= fabs(dir.x()))
return (srfpos.y() - orig.y()) / dir.y();
// otherwise x isn't bigger than both and y isn't bigger than both
else //if(fabs(dir.z()) >= fabs(dir.x()) && fabs(dir.z()) >= fabs(dir.y()))
return (srfpos.z() - orig.z()) / dir.z();
}
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
// RayPatchIntersection
// intersect rays of the form p = r + t q where t is the parameter
// to solve for. With the patch pointed to by *this
// for valid intersections:
// place the u,v intersection point in uv[0] and uv[1] respectively.
// place the t value in uv[2]
// return true to this function
// for invalid intersections - simply return false uv values can be
// anything
//+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+
bool BilinearPatch::RayPatchIntersection(Vector r, Vector q, Vector &uv)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Equation of the patch:
// P(u, v) = (1-u)(1-v)P00 + (1-u)vP01 + u(1-v)P10 + uvP11
// Equation of the ray:
// R(t) = r + tq
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vector pos1, pos2; //Vector pos = ro + t*rd;
int num_sol; // number of solutions to the quadratic
double vsol[2]; // the two roots from quadraticroot
double t2,u; // the t values of the two roots
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Variables for substitition
// a = P11 - P10 - P01 + P00
// b = P10 - P00
// c = P01 - P00
// d = P00 (d is shown below in the #ifdef raypatch area)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Find a w.r.t. x, y, z
double ax = P11.x() - P10.x() - P01.x() + P00.x();
double ay = P11.y() - P10.y() - P01.y() + P00.y();
double az = P11.z() - P10.z() - P01.z() + P00.z();
// Find b w.r.t. x, y, z
double bx = P10.x() - P00.x();
double by = P10.y() - P00.y();
double bz = P10.z() - P00.z();
// Find c w.r.t. x, y, z
double cx = P01.x() - P00.x();
double cy = P01.y() - P00.y();
double cz = P01.z() - P00.z();
double rx = r.x();
double ry = r.y();
double rz = r.z();
// Retrieve the xyz of the q part of ray
double qx = q.x();
double qy = q.y();
double qz = q.z();
#ifdef twoplanes
{
Vector p1n,p2n, dir(qx,qy,qz), orig(rx,ry,rz);
dir.normalize();
dir.make_ortho(p1n,p2n);
double D1 = (p1n.x() * rx + p1n.y() * ry + p1n.z() * rz);
double D2 = (p2n.x() * rx + p2n.y() * ry + p2n.z() * rz);
Vector a(ax,ay,az);
Vector b(bx,by,bz);
Vector c(cx,cy,cz);
Vector d(P00.x(),P00.y(),P00.z());
double M1 = p1n.dot(a);
double M2 = p2n.dot(a);
double J1 = p1n.dot(b);
double J2 = p2n.dot(b);
double K1 = p1n.dot(c);
double K2 = p2n.dot(c);
double R1 = p1n.dot(d)-D1;
double R2 = p2n.dot(d)-D2;
double A = M1*K2-M2*K1;
double B = M1*R2-M2*R1 -J2*K1+J1*K2;
double C = J1*R2-R1*J2;
uv.x(-2); uv.y(-2); uv.z(-2);
num_sol = QuadraticRoot(A,B,C,-ray_epsilon,1+ray_epsilon,vsol);
switch(num_sol)
{
case 0:
return false; // no solutions found
break;
case 1:
uv.y(vsol[0]); //the v value
uv.x(getu(vsol[0],M1,M2,J1,J2,K1,K2,R1,R2));
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon) // u is valid
{
pos1 = SrfEval(uv.x(),uv.y());
uv.z(computet(dir,orig,pos1));
if(uv.z() > 0) //t is valid
return true;
else
return false;
}
return false; // no other soln - so ret false
break;
case 2: // two solutions found
uv.x( getu(vsol[0],M1,M2,J1,J2,K1,K2,R1,R2));
uv.y( vsol[0]);
pos1 = SrfEval(uv.x(),uv.y());
uv.z( computet(dir,orig,pos1));
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon && uv.z() > 0)//valid vars?
{
u = getu(vsol[1],M1,M2,J1,J2,K1,K2,R1,R2);
if(u < 1+ray_epsilon && u > -ray_epsilon) // another valid u
{
pos2 = SrfEval(u, vsol[1]);
t2 = computet(dir,orig,pos2);
if(t2 < 0 || uv.z() <= t2) // t2 not valid or t1 is better
return true;
uv.x( u ); uv.y( vsol[1] ); uv.z( t2 ); //return vals
return true;
}
else // this one was bad but the other was okay..ret true
return true;
}
else //bad u valid, try other one
{
uv.y( vsol[1] );
uv.x( getu(vsol[1],M1,M2,J1,J2,K1,K2,R1,R2) );
pos1 = SrfEval(uv.x(),uv.y());
uv.z( computet(dir,orig,pos1) );
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon
&& uv.z() > 0) // variables are okay?
return true;
else
return false;
}
break;
} //end 2 root case.
std::cout << " ERROR: We don't get here in twoplanes" << std::endl;
return false;
}
#endif // end two planes
#ifdef raypatch
// Find d w.r.t. x, y, z - subtracting r just after
double dx = P00.x() - r.x();
double dy = P00.y() - r.y();
double dz = P00.z() - r.z();
// Find A1 and A2
double A1 = ax*qz - az*qx;
double A2 = ay*qz - az*qy;
// Find B1 and B2
double B1 = bx*qz - bz*qx;
double B2 = by*qz - bz*qy;
// Find C1 and C2
double C1 = cx*qz - cz*qx;
double C2 = cy*qz - cz*qy;
// Find D1 and D2
double D1 = dx*qz - dz*qx;
double D2 = dy*qz - dz*qy;
Vector dir(qx,qy,qz), orig(rx,ry,rz);
double A = A2*C1 - A1*C2;
double B = A2*D1 -A1*D2 + B2*C1 -B1*C2;
double C = B2*D1 - B1*D2;
uv.x(-2); uv.y(-2); uv.z(-2);
num_sol = QuadraticRoot(A,B,C,-ray_epsilon,1+ray_epsilon,vsol);
switch(num_sol)
{
case 0:
return false; // no solutions found
case 1:
uv.y( vsol[0]);
uv.x( getu(uv.y(),A2,A1,B2,B1,C2,C1,D2,D1));
pos1 = SrfEval(uv.x(),uv.y());
uv.z( computet(dir,orig,pos1) );
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon && uv.z() > -ray_epsilon)//vars okay?
return true;
else
return false; // no other soln - so ret false
case 2: // two solutions found
uv.y( vsol[0]);
uv.x( getu(uv.y(),A2,A1,B2,B1,C2,C1,D2,D1));
pos1 = SrfEval(uv.x(),uv.y());
uv.z( computet(dir,orig,pos1) );
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon && uv.z() > 0)
{
u = getu(vsol[1],A2,A1,B2,B1,C2,C1,D2,D1);
if(u < 1+ray_epsilon && u > ray_epsilon)
{
pos2 = SrfEval(u,vsol[1]);
t2 = computet(dir,orig,pos2);
if(t2 < 0 || uv.z() < t2) // t2 is bad or t1 is better
return true;
// other wise both t2 > 0 and t2 < t1
uv.y( vsol[1]);
uv.x( u );
uv.z( t2 );
return true;
}
return true; // u2 is bad but u1 vars are still okay
}
else // doesn't fit in the root - try other one
{
uv.y( vsol[1] );
uv.x( getu(vsol[1],A2,A1,B2,B1,C2,C1,D2,D1) );
pos1 = SrfEval(uv.x(),uv.y());
uv.z( computet(dir,orig,pos1) );
if(uv.x() < 1+ray_epsilon && uv.x() > -ray_epsilon &&uv.z() > 0)
return true;
else
return false;
}
break;
}
#endif // end ray patch
std::cout << " ERROR: We don't get here in Ray Patch Intersection" << std::endl;
return false;
}
// a x ^2 + b x + c = 0
// in this case, the root must be between min and max
// it returns the # of solutions found
// x = [ -b +/- sqrt(b*b - 4 *a*c) ] / 2a
// or x = 2c / [-b +/- sqrt(b*b-4*a*c)]
int QuadraticRoot(double a, double b, double c,
double min, double max,double *u)
{
u[0] = u[1] = min-min; // make it lower than min
if(a == 0.0) // then its close to 0
{
if(b != 0.0) // not close to 0
{
u[0] = - c / b;
if(u[0] > min && u[0] < max) //its in the interval
return 1; //1 soln found
else //its not in the interval
return 0;
}
else
return 0;
}
double d = b*b - 4*a*c; //discriminant
if(d <= 0.0) // single or no root
{
if(d == 0.0) // close to 0
{
u[0] = -b / a;
if(u[0] > min && u[0] < max) // its in the interval
return 1;
else //its not in the interval
return 0;
}
else // no root d must be below 0
return 0;
}
double q = -0.5 * (b + copysign(sqrt(d),b));
u[0] = c / q;
u[1] = q / a;
if( (u[0] > min && u[0] < max)
&& (u[1] > min && u[1] < max))
return 2;
else if(u[0] > min && u[0] < max) //then one wasn't in interval
return 1;
else if(u[1] > min && u[1] < max)
{ // make it easier, make u[0] be the valid one always
double dummy;
dummy = u[0];
u[0] = u[1];
u[1] = dummy; // just in case somebody wants to check it
return 1;
}
return 0;
}
};
+413
View File
@@ -0,0 +1,413 @@
#include "image.h"
#include "str_util.h"
#include <png.h>
#include <stdint.h>
#include <functional>
unsigned ColorDepths[4] = { DEPTH_Grey, DEPTH_Alpha, DEPTH_RGB, DEPTH_RGBA };
Image* Image::random(const vec2u& resolution, int rnd(int,int)) {
Image* img = new Image(resolution.width, resolution.height, FMT_RGB);
for(unsigned y = 0; y < resolution.height; ++y)
for(unsigned x = 0; x < resolution.width; ++x)
img->get_rgb(x,y) = ColorRGB(rnd(0,255), rnd(0,255), rnd(0,255));
return img;
}
Image* Image::sphereDistort() const {
Image* out = new Image(width, height, format);
Image& img = *out;
auto get_wrapped = [this](int x, int y) -> Color {
x = (x + width) % width;
return get(x,y);
};
auto set_out = [&img](unsigned x, unsigned y, const Color& col) {
switch(img.format) {
case FMT_Grey:
img.grey[y*img.width + x] = col.r;
break;
case FMT_Alpha:
img.grey[y*img.width + x] = col.a;
break;
case FMT_RGB:
img.rgb[y*img.width + x] = ColorRGB(col.r,col.g,col.b);
break;
case FMT_RGBA:
img.rgba[y*img.width + x] = col;
break;
}
};
for(unsigned y = 0; y < height; ++y) {
double angle = ((double)y - (double)height * 0.5) * 3.14159265359 / (double)height;
double needPixels = (1.0 / cos(angle)); needPixels *= needPixels;
if(y == 0 || y == height-1 || needPixels >= (double)width) {
//Special case for poles: Average all pixels
unsigned r = 0, g = 0, b = 0, a = 0;
for(unsigned x = 0; x < width; ++x) {
Color col = get(x,y);
r += col.r;
g += col.g;
b += col.b;
a += col.a;
}
Color col((r+width/2) / width, (g+width/2) / width, (b+width/2) / width, (a+width/2) / width);
for(unsigned x = 0; x < width; ++x)
set_out(x,y,col);
}
else {
unsigned r,g,b,a;
auto addCol = [&r,&g,&b,&a](Color col) {
r += col.r; g += col.g; b += col.b; a += col.a;
};
for(unsigned x = 0; x < width; ++x) {
double pixels = needPixels;
Color col = get(x,y);
r = col.r, g = col.g, b = col.b, a = col.a;
pixels -= 1.0;
for(int off = 1; true; ++off) {
if(pixels >= 2.0) {
addCol(get_wrapped(x-off,y));
addCol(get_wrapped(x+off,y));
pixels -= 2.0;
}
else {
addCol( Color(Colorf(get_wrapped(x-off,y)) * (pixels * 0.5)) );
addCol( Color(Colorf(get_wrapped(x+off,y)) * (pixels * 0.5)) );
break;
}
}
r = unsigned((double)r / needPixels + 0.5);
if(r > 0xff)
r = 0xff;
g = unsigned((double)g / needPixels + 0.5);
if(g > 0xff)
g = 0xff;
b = unsigned((double)b / needPixels + 0.5);
if(b > 0xff)
b = 0xff;
a = unsigned((double)a / needPixels + 0.5);
if(a > 0xff)
a = 0xff;
set_out(x,y, Color(r,g,b,a));
}
}
}
return out;
}
Image* Image::makeMipmap() const {
if(width <= 2 || height <= 2)
return 0;
Image* img = new Image(width/2, height/2, format);
unsigned r,g,b,a;
auto addRGB = [&r,&g,&b](const ColorRGB& col) {
r += col.r;
g += col.g;
b += col.b;
};
auto addRGBA = [&r,&g,&b,&a](const Color& col) {
r += col.r;
g += col.g;
b += col.b;
a += col.a;
};
for(unsigned y = 0; y < img->height; ++y) {
for(unsigned x = 0; x < img->width; ++x) {
unsigned lx = x * 2, ly = y * 2;
switch(format) {
case FMT_Grey: case FMT_Alpha:
r = 2;
r += get_grey(lx,ly);
r += get_grey(lx+1,ly);
r += get_grey(lx,ly);
r += get_grey(lx+1,ly+1);
img->get_grey(x, y) = r / 4;
break;
case FMT_RGB:
r = g = b = 2;
addRGB(get_rgb(lx,ly));
addRGB(get_rgb(lx+1,ly));
addRGB(get_rgb(lx,ly+1));
addRGB(get_rgb(lx+1,ly+1));
img->get_rgb(x,y) = ColorRGB(r/4,g/4,b/4);
break;
case FMT_RGBA:
r = g = b = a = 2;
addRGBA(get_rgba(lx,ly));
addRGBA(get_rgba(lx+1,ly));
addRGBA(get_rgba(lx,ly+1));
addRGBA(get_rgba(lx+1,ly+1));
img->get_rgba(x,y) = Color(r/4,g/4,b/4,a/4);
break;
};
}
}
return img;
}
Image* Image::crop(const rect<unsigned>& region) const {
auto bound = region.clipAgainst(rect<unsigned>(0, 0, width, height));
if(bound.getSize() == vec2u(width, height))
return new Image(*this);
Image* out = new Image(bound.getWidth(), bound.getHeight(), format);
if(out->width == 0 || out->height == 0)
return out;
unsigned bpp = ColorDepths[format];
for(unsigned y = bound.topLeft.y; y < bound.botRight.y; ++y)
memcpy(&out->grey[(y-bound.topLeft.y) * bpp * out->width], &grey[((y*width) + bound.topLeft.x) * bpp], bound.getWidth() * bpp);
return out;
}
Image* loadPNG(const char* filename);
bool savePNG(const Image* img, const char* filename, bool flip);
Image* loadImage(const char* filename) {
auto p_ext = strrchr(filename, '.');
if(p_ext == 0) //No extension to the filename (TODO: Handle this a better way?)
return 0;
if(strcmp_nocase(p_ext, ".png") == 0)
return loadPNG(filename);
return 0;
}
//PNG Loader
namespace PNG_UTIL {
struct callOnReturn {
std::function<void(void)> func;
callOnReturn(std::function<void(void)> func) : func(func) {}
~callOnReturn() { func(); }
};
void f_read(png_structp png, png_bytep out, png_size_t count) {
fread(out, count, 1, (FILE*)png_get_io_ptr(png));
}
void f_write(png_structp png, png_bytep in, png_size_t count) {
fwrite(in, count, 1, (FILE*)png_get_io_ptr(png));
}
void f_flush(png_structp png) {
fflush((FILE*)png_get_io_ptr(png));
}
};
Image* loadPNG(const char* filename) {
//Number of bytes of the PNG signature to read (must <= 8)
const unsigned int readSigBytes = 8;
auto imgfile = fopen(filename,"rb");
if(imgfile == 0)
return 0;
PNG_UTIL::callOnReturn closeFile(
[&imgfile](){ fclose(imgfile); }
);
//Confirm that the file is a png image
unsigned char buffer[readSigBytes];
if(fread(buffer,1,readSigBytes,imgfile) != readSigBytes || png_sig_cmp(buffer, 0, readSigBytes) != 0)
return 0;
//Prep png structures
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(png == 0)
return 0;
png_infop png_info = png_create_info_struct(png);
if(png_info == 0) {
png_destroy_read_struct(&png, NULL, NULL);
return 0;
}
PNG_UTIL::callOnReturn deletePNG(
[&png,&png_info]() { png_destroy_read_struct(&png, &png_info, NULL); }
);
//Prep PNG error handling
if(setjmp(png_jmpbuf(png))) {
fprintf(stderr, "Error reading png file: %s\n", filename);
return 0;
}
//Use c standard file operations, and read the png as an 8-bit depth, RGBA
png_set_read_fn(png, imgfile, PNG_UTIL::f_read);
//png_init_io(png, imgfile);
png_set_sig_bytes(png, readSigBytes);
png_read_info(png, png_info);
//Setup transformations for formats we can't use anyway
png_set_expand(png);
png_set_strip_16(png);
png_set_packing(png);
png_set_interlace_handling(png);
png_read_update_info(png, png_info);
unsigned int w, h;
int depth, format, interlace, compress, filter;
png_get_IHDR(png, png_info, &w, &h, &depth, &format, &interlace, &compress, &filter);
if(depth != 8 || w == 0 || h == 0)
return 0;
png_bytepp rows = new png_bytep[h];
Image* image = 0;
ColorFormat imageFormat = FMT_INVALID;
//TODO: Handle other file formats?
switch(format) {
case PNG_COLOR_TYPE_GRAY:
imageFormat = FMT_Grey; break;
case PNG_COLOR_TYPE_RGB:
imageFormat = FMT_RGB; break;
case PNG_COLOR_TYPE_RGB_ALPHA:
imageFormat = FMT_RGBA; break;
}
if(imageFormat != FMT_INVALID) {
image = new Image(w, h, imageFormat);
for(int y = h-1; y >= 0; --y)
rows[y] = (png_bytep)(image->grey + (y * w * ColorDepths[image->format]));
png_read_image(png, rows);
}
delete[] rows;
return image;
}
bool saveImage(const Image* img, const char* filename, bool flip) {
auto p_ext = strrchr(filename, '.');
if(p_ext == 0) //No extension to the filename (TODO: Handle this a better way?)
return false;
if(strcmp_nocase(p_ext, ".png") == 0)
return savePNG(img, filename, flip);
return false;
}
bool savePNG(const Image* img, const char* filename, bool flip) {
auto imgfile = fopen(filename, "wb");
if(!imgfile)
return false;
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png) {
fclose(imgfile);
return false;
}
png_infop info = png_create_info_struct(png);
png_byte** rows = 0;
png_byte* row_head = 0;
unsigned Bpp;
if(setjmp(png_jmpbuf(png))) {
fprintf(stderr, "Error writing png file: %s\n", filename);
goto png_fail;
}
png_uint_32 pngFmt;
switch(img->format) {
case FMT_Grey:
pngFmt = PNG_COLOR_TYPE_GRAY;
break;
case FMT_RGB:
pngFmt = PNG_COLOR_TYPE_RGB;
break;
case FMT_RGBA:
pngFmt = PNG_COLOR_TYPE_RGBA;
break;
default:
goto png_fail;
}
png_set_IHDR(png, info,
img->width, img->height,
8,
pngFmt,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
Bpp = ColorDepths[img->format];
rows = (png_byte**)png_malloc(png, img->height * sizeof(png_byte*));
row_head = (png_byte*)png_malloc(png, img->height * img->width * Bpp);
for(unsigned y = 0; y < img->height; ++y) {
png_byte* row = row_head + (img->width * y * Bpp);
rows[y] = row;
unsigned cy = flip ? img->height - 1 - y : y;
switch(img->format) {
case FMT_Grey:
memcpy(row, &img->grey[cy*img->width], img->width * Bpp);
break;
case FMT_RGB:
memcpy(row, &img->rgb[cy*img->width], img->width * Bpp);
break;
case FMT_RGBA:
memcpy(row, &img->rgba[cy*img->width], img->width * Bpp);
break;
}
}
png_set_write_fn(png, imgfile, PNG_UTIL::f_write, PNG_UTIL::f_flush);
//png_init_io(png, imgfile);
png_set_rows(png, info, rows);
png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);
png_free(png, row_head);
png_free(png, rows);
fclose(imgfile);
return true;
png_fail:
png_destroy_write_struct(&png, &info);
fclose(imgfile);
return false;
}
File diff suppressed because it is too large Load Diff
+171
View File
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1D1C1D62-A273-4D60-A0EA-3C9032C408D8}</ProjectGuid>
<RootNamespace>util</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(SolutionDir)..\..\lib\win32\</OutDir>
<TargetName>$(ProjectName)d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(SolutionDir)..\..\lib\win64\</OutDir>
<TargetName>$(ProjectName)64d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(SolutionDir)..\..\lib\win32\</OutDir>
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(SolutionDir)..\..\lib\win64\</OutDir>
<TargetName>$(ProjectName)64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\include\;..\..\libpng\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\include\;..\..\libpng\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\include\;..\..\libpng\</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\include\;..\..\libpng\</AdditionalIncludeDirectories>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\include\aabbox.h" />
<ClInclude Include="..\include\BiPatch\bilinear.h" />
<ClInclude Include="..\include\BiPatch\Vector.h" />
<ClInclude Include="..\include\color.h" />
<ClInclude Include="..\include\constants.h" />
<ClInclude Include="..\include\frustum.h" />
<ClInclude Include="..\include\image.h" />
<ClInclude Include="..\include\line3d.h" />
<ClInclude Include="..\include\matrix.h" />
<ClInclude Include="..\include\mesh.h" />
<ClInclude Include="..\include\num_util.h" />
<ClInclude Include="..\include\plane.h" />
<ClInclude Include="..\include\quaternion.h" />
<ClInclude Include="..\include\rect.h" />
<ClInclude Include="..\include\str_util.h" />
<ClInclude Include="..\include\vec2.h" />
<ClInclude Include="..\include\vec3.h" />
<ClInclude Include="..\include\vec4.h" />
<ClInclude Include="..\include\vertex.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\bilinear.cpp" />
<ClCompile Include="..\source\image.cpp" />
<ClCompile Include="..\source\str_util.cpp" />
<ClCompile Include="..\source\Vector.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+90
View File
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\aabbox.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\color.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\constants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\image.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\line3d.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\matrix.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\mesh.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\num_util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\quaternion.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\rect.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\str_util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vec2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vec3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vertex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\BiPatch\Vector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\BiPatch\bilinear.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vec4.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\plane.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\frustum.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\image.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\str_util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\bilinear.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\Vector.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>