fteqw/iqm/util.h
Spoike fc7664a69f tweaked the iqm exporter code to output some custom iqm extensions.
importing tweaked to support importing from multiple mesh files.
bone remapping is supported for animations that have extra/missing bones.
complex commandline deprecated, now supports a proper import script thing, so the fte-specific iqm extension info can be specified.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5039 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-01-13 00:42:51 +00:00

1089 lines
28 KiB
C++

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include <assert.h>
#include "iqm.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<class T>
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<class T>
static inline T max(T a, T b)
{
return a > b ? a : b;
}
template<class T>
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<int(m); v++)
#define loopi(m) loop(i,m)
#define loopj(m) loop(j,m)
#define loopk(m) loop(k,m)
#define loopl(m) loop(l,m)
#ifdef WIN32
#ifdef M_PI
#undef M_PI
#endif
#define M_PI 3.14159265
#ifndef __GNUC__
#pragma warning (3: 4189) // local variable is initialized but not referenced
#pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data
#pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data
#pragma warning (disable: 4355) // 'this' : used in base member initializer list
#pragma warning (disable: 4996) // 'strncpy' was declared deprecated
#endif
#define strcasecmp _stricmp
#define PATHDIV '\\'
#else
#define __cdecl
#define _vsnprintf vsnprintf
#define PATHDIV '/'
#endif
// easy safe strings
#define MAXSTRLEN 260
typedef char string[MAXSTRLEN];
inline void vformatstring(char *d, const char *fmt, va_list v, int len = MAXSTRLEN) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
inline char *copystring(char *d, const char *s, size_t len = MAXSTRLEN)
{
size_t slen = min(strlen(s)+1, len);
memcpy(d, s, slen);
d[slen-1] = 0;
return d;
}
inline char *concatstring(char *d, const char *s) { size_t len = strlen(d); return copystring(d+len, s, MAXSTRLEN-len); }
template<size_t N> 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 <class T> 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<T> &operator=(const vector<T> &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<uint(ulen); }
bool inrange(int i) const { return i>=0 && i<ulen; }
T &pop() { return buf[--ulen]; }
T &last() { return buf[ulen-1]; }
void drop() { ulen--; buf[ulen].~T(); }
bool empty() const { return ulen==0; }
int capacity() const { return alen; }
int length() const { return ulen; }
T &operator[](int i) { ASSERT(i>=0 && i<ulen); return buf[i]; }
const T &operator[](int i) const { ASSERT(i >= 0 && i<ulen); return buf[i]; }
void setsize(int i) { ASSERT(i <= ulen); ulen = i; }
void swap(vector<T> &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 <class K, class T> 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<class L>
T *access(const L &key)
{
HTFIND(&c->data, NULL);
}
template<class L>
T &access(const L &key, const T &data)
{
HTFIND(c->data, insert(key, h)->data = data);
}
template<class L>
const T &find(const L &key, const T &notfound)
{
HTFIND(c->data, notfound);
}
template<class L>
T &operator[](const L &key)
{
HTFIND(c->data, insert(key, h)->data);
}
#undef HTFIND
template<class L>
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<k,t>::chain *enumc = (ht).table[i]; enumc;) { hashtable<k,t>::const_key &e = enumc->key; t &f = enumc->data; enumc = enumc->next; b; }
template<class T>
struct unionfind
{
struct ufval
{
int rank, next;
T val;
ufval(const T &val) : rank(0), next(-1), val(val) {}
};
vector<ufval> 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<class T>
struct listnode
{
T *prev, *next;
};
template<class T>
struct list
{
typedef listnode<T> node;
int size;
listnode<T> 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<class T> 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>(uchar n) { return n; }
template<> inline char endianswap<char>(char n) { return n; }
template<> inline ushort endianswap<ushort>(ushort n) { return endianswap16(n); }
template<> inline short endianswap<short>(short n) { return endianswap16(n); }
template<> inline uint endianswap<uint>(uint n) { return endianswap32(n); }
template<> inline int endianswap<int>(int n) { return endianswap32(n); }
template<> inline ullong endianswap<ullong>(ullong n) { return endianswap64(n); }
template<> inline llong endianswap<llong>(llong n) { return endianswap64(n); }
template<> inline double endianswap<double>(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; }
template<class T> inline void endianswap(T *buf, int len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); }
template<class T> inline T endiansame(T n) { return n; }
template<class T> inline void endiansame(T *buf, int len) {}
template<class T> inline T lilswap(T n) { return islittleendian() ? n : endianswap(n); }
template<class T> inline void lilswap(T *buf, int len) { if(!islittleendian()) endianswap(buf, len); }
template<class T> inline T bigswap(T n) { return islittleendian() ? endianswap(n) : n; }
template<class T> 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<class T> bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
template<class T> bool putlil(T n) { return put<T>(lilswap(n)); }
template<class T> bool putbig(T n) { return put<T>(bigswap(n)); }
template<class T> T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
template<class T> T getlil() { return lilswap(get<T>()); }
template<class T> T getbig() { return bigswap(get<T>()); }
};
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<class M>
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);
}