#include #include #include #include #include #include #include #include #include "vvm.h" #define ASSERT(c) if(c) {} #ifdef NULL #undef NULL #endif #define NULL 0 #ifdef _WIN32 #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif #define strcasecmp _stricmp #define strncasecmp _strnicmp #endif typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef signed long long int llong; typedef unsigned long long int ullong; inline void *operator new(size_t size) { void *p = malloc(size); if(!p) abort(); return p; } inline void *operator new[](size_t size) { void *p = malloc(size); if(!p) abort(); return p; } inline void operator delete(void *p) { if(p) free(p); } inline void operator delete[](void *p) { if(p) free(p); } inline void *operator new(size_t, void *p) { return p; } inline void *operator new[](size_t, void *p) { return p; } inline void operator delete(void *, void *) { } inline void operator delete[](void *, void *) { } #ifdef swap #undef swap #endif template static inline void swap(T &a, T &b) { T t = a; a = b; b = t; } #ifdef max #undef max #endif #ifdef min #undef min #endif template static inline T max(T a, T b) { return a > b ? a : b; } template static inline T min(T a, T b) { return a < b ? a : b; } #define clamp(a,b,c) (max(b, min(a, c))) #define loop(v,m) for(int v = 0; v inline void formatstring(char (&d)[N], const char *fmt, ...) { va_list v; va_start(v, fmt); vformatstring(d, fmt, v, int(N)); va_end(v); } #define defformatstring(d,...) string d; formatstring(d, __VA_ARGS__) #define defvformatstring(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); } inline char *newstring(size_t l) { return new char[l+1]; } inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); } inline char *newstring(const char *s) { size_t l = strlen(s); char *d = newstring(l); memcpy(d, s, l+1); return d; } #define loopv(v) for(int i = 0; i<(v).length(); i++) #define loopvj(v) for(int j = 0; j<(v).length(); j++) #define loopvk(v) for(int k = 0; k<(v).length(); k++) #define loopvrev(v) for(int i = (v).length()-1; i>=0; i--) template struct vector { static const int MINSIZE = 8; T *buf; int alen, ulen; vector() : buf(NULL), alen(0), ulen(0) { } vector(const vector &v) : buf(NULL), alen(0), ulen(0) { *this = v; } ~vector() { setsize(0); if(buf) delete[] (uchar *)buf; } vector &operator=(const vector &v) { setsize(0); if(v.length() > alen) growbuf(v.length()); loopv(v) add(v[i]); return *this; } T &add(const T &x) { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T(x); return buf[ulen++]; } T &add() { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T; return buf[ulen++]; } T &dup() { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T(buf[ulen-1]); return buf[ulen++]; } bool inrange(uint i) const { return i=0 && i=0 && i= 0 && i &v) { ::swap(buf, v.buf); ::swap(ulen, v.ulen); ::swap(alen, v.alen); } T *getbuf() { return buf; } const T *getbuf() const { return buf; } bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; } void growbuf(int sz) { int olen = alen; if(!alen) alen = max(MINSIZE, sz); else while(alen < sz) alen *= 2; if(alen <= olen) return; uchar *newbuf = new uchar[alen*sizeof(T)]; if(olen > 0) { memcpy(newbuf, buf, olen*sizeof(T)); delete[] (uchar *)buf; } buf = (T *)newbuf; } T *reserve(int sz) { if(ulen+sz > alen) growbuf(ulen+sz); return &buf[ulen]; } void advance(int sz) { ulen += sz; } void put(const T *v, int n) { memcpy(reserve(n), v, n*sizeof(T)); advance(n); } }; static inline uint hthash(const char *key) { uint h = 5381; for(int i = 0, k; (k = key[i]); i++) h = ((h<<5)+h)^k; // bernstein k=33 xor return h; } static inline bool htcmp(const char *x, const char *y) { return !strcmp(x, y); } static inline uint hthash(int key) { return key; } static inline bool htcmp(int x, int y) { return x==y; } static inline bool htcmp(double x, double y) { return x == y; } static inline uint hthash(double k) { union { double f; uint h[sizeof(double)/sizeof(uint)]; } conv; conv.f = k; uint hash = conv.h[0]; for(size_t i = 1; i < sizeof(conv.h)/sizeof(uint); i++) hash ^= conv.h[i]; return hash; } template struct hashtable { typedef K key; typedef const K const_key; typedef T value; typedef const T const_value; enum { CHUNKSIZE = 64 }; struct chain { T data; K key; chain *next; }; struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; int size; int numelems; chain **table; chainchunk *chunks; chain *unused; hashtable(int size = 1<<10) : size(size) { numelems = 0; chunks = NULL; unused = NULL; table = new chain *[size]; loopi(size) table[i] = NULL; } ~hashtable() { if(table) delete[] table; deletechunks(); } chain *insert(const K &key, uint h) { if(!unused) { chainchunk *chunk = new chainchunk; chunk->next = chunks; chunks = chunk; loopi(CHUNKSIZE-1) chunk->chains[i].next = &chunk->chains[i+1]; chunk->chains[CHUNKSIZE-1].next = unused; unused = chunk->chains; } chain *c = unused; unused = unused->next; c->key = key; c->next = table[h]; table[h] = c; numelems++; return c; } #define HTFIND(success, fail) \ uint h = hthash(key)&(size-1); \ for(chain *c = table[h]; c; c = c->next) \ { \ if(htcmp(key, c->key)) return (success); \ } \ return (fail); template T *access(const L &key) { HTFIND(&c->data, NULL); } template T &access(const L &key, const T &data) { HTFIND(c->data, insert(key, h)->data = data); } template const T &find(const L &key, const T ¬found) { HTFIND(c->data, notfound); } template T &operator[](const L &key) { HTFIND(c->data, insert(key, h)->data); } #undef HTFIND template bool remove(const L &key) { uint h = hthash(key)&(size-1); for(chain **p = &table[h], *c = table[h]; c; p = &c->next, c = c->next) { if(htcmp(key, c->key)) { *p = c->next; c->data.~T(); c->key.~K(); new (&c->data) T; new (&c->key) K; c->next = unused; unused = c; numelems--; return true; } } return false; } void deletechunks() { for(chainchunk *nextchunk; chunks; chunks = nextchunk) { nextchunk = chunks->next; delete chunks; } } void clear() { if(!numelems) return; loopi(size) table[i] = NULL; numelems = 0; unused = NULL; deletechunks(); } }; #define enumerate(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc;) { hashtable::const_key &e = enumc->key; t &f = enumc->data; enumc = enumc->next; b; } template struct unionfind { struct ufval { int rank, next; T val; ufval(const T &val) : rank(0), next(-1), val(val) { } }; vector ufvals; void clear() { ufvals.setsize(0); } const T &find(int k, const T &noval, const T &initval) { if(k>=ufvals.length()) return initval; while(ufvals[k].next>=0) k = ufvals[k].next; if(ufvals[k].val == noval) ufvals[k].val = initval; return ufvals[k].val; } int compressfind(int k) { if(ufvals[k].next<0) return k; return ufvals[k].next = compressfind(ufvals[k].next); } void unite (int x, int y, const T &noval) { while(ufvals.length() <= max(x, y)) ufvals.add(ufval(noval)); x = compressfind(x); y = compressfind(y); if(x==y) return; ufval &xval = ufvals[x], &yval = ufvals[y]; if(xval.rank < yval.rank) xval.next = y; else { yval.next = x; if(xval.rank==yval.rank) yval.rank++; } } }; template struct listnode { T *prev, *next; }; template struct list { typedef listnode node; int size; listnode nodes; list() { clear(); } bool empty() const { return nodes.prev == nodes.next; } bool notempty() const { return nodes.prev != nodes.next; } T *first() const { return nodes.next; } T *last() const { return nodes.prev; } T *end() const { return (T *)&nodes; } void clear() { size = 0; nodes.prev = nodes.next = (T *)&nodes; } T *remove(T *node) { size--; node->prev->next = node->next; node->next->prev = node->prev; return node; } T *insertafter(T *node, T *pos) { size++; node->next = pos->next; node->next->prev = node; node->prev = pos; pos->next = node; return node; } T *insertbefore(T *node, T *pos) { size++; node->prev = pos->prev; node->prev->next = node; node->next = pos; pos->prev = node; return node; } T *insertfirst(T *node) { return insertafter(node, end()); } T *insertlast(T *node) { return insertbefore(node, end()); } T *removefirst() { return remove(first()); } T *removelast() { return remove(last()); } }; static inline bool islittleendian() { union { int i; uchar b[sizeof(int)]; } conv; conv.i = 1; return conv.b[0] != 0; } inline ushort endianswap16(ushort n) { return (n<<8) | (n>>8); } inline uint endianswap32(uint n) { return (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000); } inline ullong endianswap64(ullong n) { return endianswap32(uint(n >> 32)) | ((ullong)endianswap32(uint(n)) << 32); } template inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = endianswap32(conv.i); return conv.t; } template<> inline uchar endianswap(uchar n) { return n; } template<> inline char endianswap(char n) { return n; } template<> inline ushort endianswap(ushort n) { return endianswap16(n); } template<> inline short endianswap(short n) { return endianswap16(n); } template<> inline uint endianswap(uint n) { return endianswap32(n); } template<> inline int endianswap(int n) { return endianswap32(n); } template<> inline ullong endianswap(ullong n) { return endianswap64(n); } template<> inline llong endianswap(llong n) { return endianswap64(n); } template<> inline double endianswap(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; } template inline void endianswap(T *buf, int len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); } template inline T endiansame(T n) { return n; } template inline void endiansame(T *buf, int len) { } template inline T lilswap(T n) { return islittleendian() ? n : endianswap(n); } template inline void lilswap(T *buf, int len) { if(!islittleendian()) endianswap(buf, len); } template inline T bigswap(T n) { return islittleendian() ? endianswap(n) : n; } template inline void bigswap(T *buf, int len) { if(islittleendian()) endianswap(buf, len); } /* workaround for some C platforms that have these two functions as macros - not used anywhere */ #ifdef getchar #undef getchar #endif #ifdef putchar #undef putchar #endif struct stream { virtual ~stream() { } virtual void close() = 0; virtual bool end() = 0; virtual long tell() { return -1; } virtual bool seek(long offset, int whence = SEEK_SET) { return false; } virtual long size(); virtual size_t read(void *buf, size_t len) { return 0; } virtual size_t write(const void *buf, size_t len) { return 0; } virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; } virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; } virtual bool getline(char *str, size_t len); virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; } virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); } virtual int printf(const char *fmt, ...) { return -1; } template bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); } template bool putlil(T n) { return put(lilswap(n)); } template bool putbig(T n) { return put(bigswap(n)); } template T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; } template T getlil() { return lilswap(get()); } template T getbig() { return bigswap(get()); } }; long stream::size() { long pos = tell(), endpos; if(pos < 0 || !seek(0, SEEK_END)) return -1; endpos = tell(); return pos == endpos || seek(pos, SEEK_SET) ? endpos : -1; } bool stream::getline(char *str, size_t len) { loopi(len-1) { if(read(&str[i], 1) != 1) { str[i] = '\0'; return i > 0; } else if(str[i] == '\n') { str[i+1] = '\0'; return true; } } if(len > 0) str[len-1] = '\0'; return true; } struct filestream : stream { FILE *file; filestream() : file(NULL) { } ~filestream() { close(); } bool open(const char *name, const char *mode) { if(file) return false; file = fopen(name, mode); return file!=NULL; } void close() { if(file) { fclose(file); file = NULL; } } bool end() { return feof(file)!=0; } long tell() { return ftell(file); } bool seek(long offset, int whence) { return fseek(file, offset, whence) >= 0; } size_t read(void *buf, size_t len) { return fread(buf, 1, len, file); } size_t write(const void *buf, size_t len) { return fwrite(buf, 1, len, file); } int getchar() { return fgetc(file); } bool putchar(int c) { return fputc(c, file)!=EOF; } bool getline(char *str, int len) { return fgets(str, len, file)!=NULL; } bool putstring(const char *str) { return fputs(str, file)!=EOF; } int printf(const char *fmt, ...) { va_list v; va_start(v, fmt); int result = vfprintf(file, fmt, v); va_end(v); return result; } }; char *path(char *s) { for(char *curpart = s;;) { char *endpart = strchr(curpart, '&'); if(endpart) *endpart = '\0'; if(curpart[0]=='<') { char *file = strrchr(curpart, '>'); if(!file) return s; curpart = file+1; } for(char *t = curpart; (t = strpbrk(t, "/\\")); *t++ = PATHDIV); for(char *prevdir = NULL, *curdir = s;;) { prevdir = curdir[0]==PATHDIV ? curdir+1 : curdir; curdir = strchr(prevdir, PATHDIV); if(!curdir) break; if(prevdir+1==curdir && prevdir[0]=='.') { memmove(prevdir, curdir+1, strlen(curdir+1)+1); curdir = prevdir; } else if(curdir[1]=='.' && curdir[2]=='.' && curdir[3]==PATHDIV) { if(prevdir+2==curdir && prevdir[0]=='.' && prevdir[1]=='.') continue; memmove(prevdir, curdir+4, strlen(curdir+4)+1); curdir = prevdir; } } if(endpart) { *endpart = '&'; curpart = endpart+1; } else break; } return s; } char *path(const char *s, bool copy) { static string tmp; copystring(tmp, s); path(tmp); return tmp; } const char *parentdir(const char *directory) { const char *p = directory + strlen(directory); while(p > directory && *p != '/' && *p != '\\') p--; static string parent; size_t len = p-directory+1; copystring(parent, directory, len); return parent; } stream *openfile(const char *filename, const char *mode) { filestream *file = new filestream; if(!file->open(path(filename, true), mode)) { delete file; return NULL; } return file; } struct Vec4; struct Vec3 { union { struct { double x, y, z; }; double v[3]; uint h[3*sizeof(double)/sizeof(uint)]; }; Vec3() { } Vec3(double x, double y, double z) : x(x), y(y), z(z) { } explicit Vec3(const double *v) : x(v[0]), y(v[1]), z(v[2]) { } explicit Vec3(const Vec4 &v); double &operator[](int i) { return v[i]; } double operator[](int i) const { return v[i]; } bool operator==(const Vec3 &o) const { return x == o.x && y == o.y && z == o.z; } bool operator!=(const Vec3 &o) const { return x != o.x || y != o.y || z != o.z; } bool operator<(const Vec3 &o) const { return x < o.x || y < o.y || z < o.z; } bool operator>(const Vec3 &o) const { return x > o.x || y > o.y || z > o.z; } Vec3 operator+(const Vec3 &o) const { return Vec3(x+o.x, y+o.y, z+o.z); } Vec3 operator-(const Vec3 &o) const { return Vec3(x-o.x, y-o.y, z-o.z); } Vec3 operator+(double k) const { return Vec3(x+k, y+k, z+k); } Vec3 operator-(double k) const { return Vec3(x-k, y-k, z-k); } Vec3 operator-() const { return Vec3(-x, -y, -z); } Vec3 operator*(const Vec3 &o) const { return Vec3(x*o.x, y*o.y, z*o.z); } Vec3 operator/(const Vec3 &o) const { return Vec3(x/o.x, y/o.y, z/o.z); } Vec3 operator*(double k) const { return Vec3(x*k, y*k, z*k); } Vec3 operator/(double k) const { return Vec3(x/k, y/k, z/k); } Vec3 &operator+=(const Vec3 &o) { x += o.x; y += o.y; z += o.z; return *this; } Vec3 &operator-=(const Vec3 &o) { x -= o.x; y -= o.y; z -= o.z; return *this; } Vec3 &operator+=(double k) { x += k; y += k; z += k; return *this; } Vec3 &operator-=(double k) { x -= k; y -= k; z -= k; return *this; } Vec3 &operator*=(const Vec3 &o) { x *= o.x; y *= o.y; z *= o.z; return *this; } Vec3 &operator/=(const Vec3 &o) { x /= o.x; y /= o.y; z /= o.z; return *this; } Vec3 &operator*=(double k) { x *= k; y *= k; z *= k; return *this; } Vec3 &operator/=(double k) { x /= k; y /= k; z /= k; return *this; } double dot(const Vec3 &o) const { return x*o.x + y*o.y + z*o.z; } double magnitude() const { return sqrt(dot(*this)); } double squaredlen() const { return dot(*this); } double dist(const Vec3 &o) const { return (*this - o).magnitude(); } Vec3 normalize() const { return *this * (1.0 / magnitude()); } Vec3 cross(const Vec3 &o) const { return Vec3(y*o.z-z*o.y, z*o.x-x*o.z, x*o.y-y*o.x); } Vec3 reflect(const Vec3 &n) const { return *this - n*2.0*dot(n); } Vec3 project(const Vec3 &n) const { return *this - n*dot(n); } Vec3 zxy() const { return Vec3(z, x, y); } Vec3 zyx() const { return Vec3(z, y, x); } Vec3 yxz() const { return Vec3(y, x, z); } Vec3 yzx() const { return Vec3(y, z, x); } Vec3 xzy() const { return Vec3(x, z, y); } }; static inline bool htcmp(const Vec3 &x, const Vec3 &y) { return x == y; } static inline uint hthash(const Vec3 &k) { uint hash = k.h[0]; for(size_t i = 1; i < sizeof(k.h)/sizeof(uint); i++) hash ^= k.h[i]; return hash; } struct Vec4 { union { struct { double x, y, z, w; }; double v[4]; uint h[4*sizeof(double)/sizeof(uint)]; }; Vec4() { } Vec4(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) { } explicit Vec4(const Vec3 &p, double w = 0) : x(p.x), y(p.y), z(p.z), w(w) { } explicit Vec4(const double *v) : x(v[0]), y(v[1]), z(v[2]), w(v[3]) { } double &operator[](int i) { return v[i]; } double operator[](int i) const { return v[i]; } bool operator==(const Vec4 &o) const { return x == o.x && y == o.y && z == o.z && w == o.w; } bool operator!=(const Vec4 &o) const { return x != o.x || y != o.y || z != o.z || w != o.w; } bool operator<(const Vec4 &o) const { return x < o.x || y < o.y || z < o.z || w < o.w; } bool operator>(const Vec4 &o) const { return x > o.x || y > o.y || z > o.z || w > o.w; } Vec4 operator+(const Vec4 &o) const { return Vec4(x+o.x, y+o.y, z+o.z, w+o.w); } Vec4 operator-(const Vec4 &o) const { return Vec4(x-o.x, y-o.y, z-o.z, w-o.w); } Vec4 operator+(double k) const { return Vec4(x+k, y+k, z+k, w+k); } Vec4 operator-(double k) const { return Vec4(x-k, y-k, z-k, w-k); } Vec4 operator-() const { return Vec4(-x, -y, -z, -w); } Vec4 operator*(double k) const { return Vec4(x*k, y*k, z*k, w*k); } Vec4 operator/(double k) const { return Vec4(x/k, y/k, z/k, w/k); } Vec4 addw(double f) const { return Vec4(x, y, z, w + f); } Vec4 &operator+=(const Vec4 &o) { x += o.x; y += o.y; z += o.z; w += o.w; return *this; } Vec4 &operator+=(const Vec3 &o) { x += o.x; y += o.y; z += o.z; return *this; } Vec4 &operator-=(const Vec4 &o) { x -= o.x; y -= o.y; z -= o.z; w -= o.w; return *this; } Vec4 &operator-=(const Vec3 &o) { x -= o.x; y -= o.y; z -= o.z; return *this; } Vec4 &operator+=(double k) { x += k; y += k; z += k; w += k; return *this; } Vec4 &operator-=(double k) { x -= k; y -= k; z -= k; w -= k; return *this; } Vec4 &operator*=(double k) { x *= k; y *= k; z *= k; w *= k; return *this; } Vec4 &operator/=(double k) { x /= k; y /= k; z /= k; w /= k; return *this; } double dot3(const Vec4 &o) const { return x*o.x + y*o.y + z*o.z; } double dot3(const Vec3 &o) const { return x*o.x + y*o.y + z*o.z; } double dot(const Vec4 &o) const { return dot3(o) + w*o.w; } double dot(const Vec3 &o) const { return x*o.x + y*o.y + z*o.z + w; } double magnitude() const { return sqrt(dot(*this)); } double magnitude3() const { return sqrt(dot3(*this)); } Vec4 normalize() const { return *this * (1.0 / magnitude()); } Vec3 cross3(const Vec4 &o) const { return Vec3(y*o.z-z*o.y, z*o.x-x*o.z, x*o.y-y*o.x); } Vec3 cross3(const Vec3 &o) const { return Vec3(y*o.z-z*o.y, z*o.x-x*o.z, x*o.y-y*o.x); } void setxyz(const Vec3 &o) { x = o.x; y = o.y; z = o.z; } }; inline Vec3::Vec3(const Vec4 &v) : x(v.x), y(v.y), z(v.z) { } static inline bool htcmp(const Vec4 &x, const Vec4 &y) { return x == y; } static inline uint hthash(const Vec4 &k) { uint hash = k.h[0]; for(size_t i = 1; i < sizeof(k.h)/sizeof(uint); i++) hash ^= k.h[i]; return hash; } struct Matrix3x3; struct Matrix3x4; struct Quat : Vec4 { Quat() { } Quat(double x, double y, double z, double w) : Vec4(x, y, z, w) { } Quat(double angle, const Vec3 &axis) { double s = sin(0.5*angle); x = s*axis.x; y = s*axis.y; z = s*axis.z; w = cos(0.5*angle); } explicit Quat(const Vec3 &v) : Vec4(v.x, v.y, v.z, -sqrt(max(1.0 - v.squaredlen(), 0.0))) { } explicit Quat(const Matrix3x3 &m) { convertmatrix(m); } explicit Quat(const Matrix3x4 &m) { convertmatrix(m); } void restorew() { w = -sqrt(max(1.0 - dot3(*this), 0.0)); } Quat operator*(const Quat &o) const { return Quat(w*o.x + x*o.w + y*o.z - z*o.y, w*o.y - x*o.z + y*o.w + z*o.x, w*o.z + x*o.y - y*o.x + z*o.w, w*o.w - x*o.x - y*o.y - z*o.z); } Quat &operator*=(const Quat &o) { return (*this = *this * o); } Quat operator+(const Vec4 &o) const { return Quat(x+o.x, y+o.y, z+o.z, w+o.w); } Quat &operator+=(const Vec4 &o) { return (*this = *this + o); } Quat operator-(const Vec4 &o) const { return Quat(x-o.x, y-o.y, z-o.z, w-o.w); } Quat &operator-=(const Vec4 &o) { return (*this = *this - o); } Quat operator-() const { return Quat(-x, -y, -z, w); } void flip() { x = -x; y = -y; z = -z; w = -w; } Vec3 transform(const Vec3 &p) const { return p + cross3(cross3(p) + p*w)*2.0; } template void convertmatrix(const M &m) { double trace = m.a.x + m.b.y + m.c.z; if(trace>0) { double r = sqrt(1 + trace), inv = 0.5/r; w = 0.5*r; x = (m.c.y - m.b.z)*inv; y = (m.a.z - m.c.x)*inv; z = (m.b.x - m.a.y)*inv; } else if(m.a.x > m.b.y && m.a.x > m.c.z) { double r = sqrt(1 + m.a.x - m.b.y - m.c.z), inv = 0.5/r; x = 0.5*r; y = (m.b.x + m.a.y)*inv; z = (m.a.z + m.c.x)*inv; w = (m.c.y - m.b.z)*inv; } else if(m.b.y > m.c.z) { double r = sqrt(1 + m.b.y - m.a.x - m.c.z), inv = 0.5/r; x = (m.b.x + m.a.y)*inv; y = 0.5*r; z = (m.c.y + m.b.z)*inv; w = (m.a.z - m.c.x)*inv; } else { double r = sqrt(1 + m.c.z - m.a.x - m.b.y), inv = 0.5/r; x = (m.a.z + m.c.x)*inv; y = (m.c.y + m.b.z)*inv; z = 0.5*r; w = (m.b.x - m.a.y)*inv; } } static Quat fromangles(const Vec3 &rot) { double cx = cos(rot.x/2), sx = sin(rot.x/2), cy = cos(rot.y/2), sy = sin(rot.y/2), cz = cos(rot.z/2), sz = sin(rot.z/2); Quat q(sx*cy*cz - cx*sy*sz, cx*sy*cz + sx*cy*sz, cx*cy*sz - sx*sy*cz, cx*cy*cz + sx*sy*sz); if(q.w > 0) q.flip(); return q; } static Quat fromdegrees(const Vec3 &rot) { return fromangles(rot * (M_PI / 180)); } }; struct Matrix3x3 { Vec3 a, b, c; Matrix3x3() { } Matrix3x3(const Vec3 &a, const Vec3 &b, const Vec3 &c) : a(a), b(b), c(c) { } explicit Matrix3x3(const Quat &q) { convertquat(q); } explicit Matrix3x3(const Quat &q, const Vec3 &scale) { convertquat(q); a *= scale; b *= scale; c *= scale; } void convertquat(const Quat &q) { double x = q.x, y = q.y, z = q.z, w = q.w, tx = 2*x, ty = 2*y, tz = 2*z, txx = tx*x, tyy = ty*y, tzz = tz*z, txy = tx*y, txz = tx*z, tyz = ty*z, twx = w*tx, twy = w*ty, twz = w*tz; a = Vec3(1 - (tyy + tzz), txy - twz, txz + twy); b = Vec3(txy + twz, 1 - (txx + tzz), tyz - twx); c = Vec3(txz - twy, tyz + twx, 1 - (txx + tyy)); } Matrix3x3 operator*(const Matrix3x3 &o) const { return Matrix3x3( o.a*a.x + o.b*a.y + o.c*a.z, o.a*b.x + o.b*b.y + o.c*b.z, o.a*c.x + o.b*c.y + o.c*c.z); } Matrix3x3 &operator*=(const Matrix3x3 &o) { return (*this = *this * o); } void transpose(const Matrix3x3 &o) { a = Vec3(o.a.x, o.b.x, o.c.x); b = Vec3(o.a.y, o.b.y, o.c.y); c = Vec3(o.a.z, o.b.z, o.c.z); } void transpose() { transpose(Matrix3x3(*this)); } Vec3 transform(const Vec3 &o) const { return Vec3(a.dot(o), b.dot(o), c.dot(o)); } float determinant() { return a.x * b.y * c.z + a.y * b.z * c.x + a.z * b.x * c.y - a.z * b.y * c.x - a.y * b.x * c.z - a.x * b.z * c.y; } }; struct Matrix3x4 { Vec4 a, b, c; Matrix3x4() { } Matrix3x4(const Vec4 &a, const Vec4 &b, const Vec4 &c) : a(a), b(b), c(c) { } explicit Matrix3x4(const Matrix3x3 &rot, const Vec3 &trans) : a(Vec4(rot.a, trans.x)), b(Vec4(rot.b, trans.y)), c(Vec4(rot.c, trans.z)) { } explicit Matrix3x4(const Quat &rot, const Vec3 &trans) { *this = Matrix3x4(Matrix3x3(rot), trans); } explicit Matrix3x4(const Quat &rot, const Vec3 &trans, const Vec3 &scale) { *this = Matrix3x4(Matrix3x3(rot, scale), trans); } Matrix3x4 operator*(float k) const { return Matrix3x4(*this) *= k; } Matrix3x4 &operator*=(float k) { a *= k; b *= k; c *= k; return *this; } Matrix3x4 operator+(const Matrix3x4 &o) const { return Matrix3x4(*this) += o; } Matrix3x4 &operator+=(const Matrix3x4 &o) { a += o.a; b += o.b; c += o.c; return *this; } Matrix3x4 operator+(const Vec3 &o) const { return Matrix3x4(*this) += o; } Matrix3x4 &operator+=(const Vec3 &o) { a[3] += o[0]; b[3] += o[1]; c[3] += o[2]; return *this; } void invert(const Matrix3x4 &o) { Matrix3x3 invrot(Vec3(o.a.x, o.b.x, o.c.x), Vec3(o.a.y, o.b.y, o.c.y), Vec3(o.a.z, o.b.z, o.c.z)); invrot.a /= invrot.a.squaredlen(); invrot.b /= invrot.b.squaredlen(); invrot.c /= invrot.c.squaredlen(); Vec3 trans(o.a.w, o.b.w, o.c.w); a = Vec4(invrot.a, -invrot.a.dot(trans)); b = Vec4(invrot.b, -invrot.b.dot(trans)); c = Vec4(invrot.c, -invrot.c.dot(trans)); } void invert() { invert(Matrix3x4(*this)); } Matrix3x4 operator*(const Matrix3x4 &o) const { return Matrix3x4( (o.a*a.x + o.b*a.y + o.c*a.z).addw(a.w), (o.a*b.x + o.b*b.y + o.c*b.z).addw(b.w), (o.a*c.x + o.b*c.y + o.c*c.z).addw(c.w)); } Matrix3x4 &operator*=(const Matrix3x4 &o) { return (*this = *this * o); } Vec3 transform(const Vec3 &o) const { return Vec3(a.dot(o), b.dot(o), c.dot(o)); } }; void conoutf(const char *s, ...) { defvformatstring(msg,s,s); printf("%s\n", msg); } void fatal(const char *s, ...) // failure exit { defvformatstring(msg,s,s); fprintf(stderr, "%s\n", msg); exit(EXIT_FAILURE); }