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