diff --git a/c++/perspective/SConstruct b/c++/perspective/SConstruct new file mode 100644 index 0000000..cf81332 --- /dev/null +++ b/c++/perspective/SConstruct @@ -0,0 +1,3 @@ +build_dir = ARGUMENTS.get('build_dir', 'build') +VariantDir(build_dir, 'src', duplicate = 0) +SConscript(build_dir + '/SConstruct') diff --git a/c++/perspective/build/perspective b/c++/perspective/build/perspective new file mode 100755 index 0000000..668ec21 Binary files /dev/null and b/c++/perspective/build/perspective differ diff --git a/c++/perspective/src/SConstruct b/c++/perspective/src/SConstruct new file mode 100644 index 0000000..3871bff --- /dev/null +++ b/c++/perspective/src/SConstruct @@ -0,0 +1,32 @@ + +env = Environment() + + +# config + +libs = ['gtkmm-3.0'] + + +# compute build options + +flags = ' -O0 -g -Wall -fmessage-length=0 ' + + +# files lists + +target = 'perspective' + +sources = [ + 'generator.cpp', + 'main.cpp', + 'surface.cpp' ] + + +# build + +env.ParseConfig('pkg-config --cflags --libs ' + ' '.join(libs)) + +env.Program( + target = target, + source = sources, + parse_flags = flags ) diff --git a/c++/perspective/src/common.h b/c++/perspective/src/common.h new file mode 100644 index 0000000..d3bea9c --- /dev/null +++ b/c++/perspective/src/common.h @@ -0,0 +1,61 @@ +#ifndef COMMON_H +#define COMMON_H + +#include +#include + + +typedef float ColorReal; +typedef double Real; +typedef int Int; +typedef unsigned int UInt; +typedef long long int LongInt; +typedef unsigned long long int ULongInt; + + +const Real realRrecision = 1e-10; + + +class Shared { +private: + int ref_count; +public: + Shared(): ref_count() { } + Shared(const Shared&): ref_count() { } + virtual ~Shared() { }; + + inline Shared& operator=(const Shared&) { return *this; } + inline void reference() { ++ref_count; } + inline void unreference() { if (--ref_count <= 0) delete this; } +}; + + +class Color { +public: + typedef ColorReal Channel; + union { + struct { Channel channels[4]; }; + struct { Channel r, g, b, a; }; + }; + + inline explicit Color(Channel r = 0.0, Channel g = 0.0, Channel b = 0.0, Channel a = 0.0): + r(r), g(g), b(b), a(a) { } +}; + + +inline int clz(const Int &x) + { return x ? __builtin_clz(x) : 32; } +inline int clz(const UInt &x) + { return x ? __builtin_clz(x) : 32; } +inline int clz(const LongInt &x) + { return x ? __builtin_clzll(x) : 64; } +inline int clz(const ULongInt &x) + { return x ? __builtin_clzll(x) : 64; } + + +inline Real flip_clamp(Real x) { + x -= floor(0.5*x)*2.0; + return 1.0 - fabs(1.0 - x); +} + +#endif diff --git a/c++/perspective/src/generator.cpp b/c++/perspective/src/generator.cpp new file mode 100644 index 0000000..8fb0116 --- /dev/null +++ b/c++/perspective/src/generator.cpp @@ -0,0 +1,138 @@ +#include + +#include "generator.h" + + +Generator::Generator(): Generator(random(time(NULL))) { } + +Generator::Generator(ULongInt seed): + one(1ull << 32), + max_cache_count(8*1024*1024) +{ + set_seed(seed); + LongIntVector2 a(1, 2); + LongIntVector2 b(3); + m_cache[ULongIntVector2()]; + m_cache_top = m_cache.begin(); + m_cache_top->second.next = m_cache_top->second.previous = m_cache_top; +} + +void +Generator::set_seed(ULongInt x) { + for(int i = 0; i < 2; ++i) + for(int j = 0; j < 4; ++j) + x = random( m_seeds[i][j] = x ); +} + + +Real +Generator::random(const ULongIntVector2 &coord, int index) const { + ULongInt seed = ULongInt(rand()) ^ (ULongInt(rand()) << 16) ^ (ULongInt(rand()) << 32) ^ (ULongInt(rand()) << 48); + //ULongInt seed = random(coord.x ^ seeds_x()[index]); + //seed = random(seed ^ coord.y ^ seeds_y()[index]); + return Real(seed)/Real(ULLONG_MAX); +} + +Vector4 +Generator::generate(const ULongIntVector2 &coord, bool shrink_cache) const { + // search value in cache + + Cache::iterator i = m_cache.find(coord); + bool found = i != m_cache.end(); + if (found) { + i->second.previous->second.next = i->second.next; + i->second.next->second.previous = i->second.previous; + assert(!i->second.in_use); + if (i->second.in_use) return i->second.value; + } else { + i = m_cache.insert(Cache::value_type(coord, CacheEntry())).first; + ++m_cache_count; + } + i->second.in_use = true; + i->second.previous = m_cache_top; + i->second.next = i->second.previous->second.next; + m_cache_top = i; + i->second.previous->second.next = i; + i->second.next->second.previous = i; + + while (shrink_cache && m_cache_count > max_cache_count) { + Cache::iterator ri = m_cache_top->second.next; + if (ri->second.in_use) break; + ri->second.previous->second.next = ri->second.next; + ri->second.next->second.previous = ri->second.previous; + m_cache.erase(ri); + --m_cache_count; + } + + Vector4 &value = i->second.value; + if (!found) { + // generate new value + + for(int j = 0; j < 4; ++j) + value[j] = random(coord, j); + + ULongInt x_minus_one = coord.x - 1; + ULongInt y_minus_one = coord.y - 1; + ULongInt level_x = coord.x ? (coord.x ^ x_minus_one) >> 1 : (ULongInt)-1; + ULongInt level_y = coord.y ? (coord.y ^ y_minus_one) >> 1 : (ULongInt)-1; + ULongInt level = (level_x < level_y ? level_x : level_y) + 1; + + if (level < one) { + value /= (one/level); + if (level_x == level_y) { + // square corners + value += ( generate(ULongIntVector2(coord.x - level, coord.y - level)) + + generate(ULongIntVector2(coord.x - level, coord.y + level)) + + generate(ULongIntVector2(coord.x + level, coord.y - level)) + + generate(ULongIntVector2(coord.x + level, coord.y + level)) )*0.25; + } else { + // diamond corners + value += ( generate(ULongIntVector2(coord.x - level, coord.y)) + + generate(ULongIntVector2(coord.x + level, coord.y)) + + generate(ULongIntVector2(coord.x, coord.y - level)) + + generate(ULongIntVector2(coord.x, coord.y + level)) )*0.25; + } + } + } + i->second.in_use = false; + + return value; +} + +Vector4 +Generator::generate(const Vector2 &coord, const Vector2 &precision) const { + const int bits = clz(ULongInt(0)); + + ULongIntVector2 coord_int( + (ULongInt)(LongInt)(coord.x*one), + (ULongInt)(LongInt)(coord.y*one) ); + ULongIntVector2 precision_int( + (ULongInt)(LongInt)(precision.x*one), + (ULongInt)(LongInt)(precision.y*one) ); + int level_x = bits - clz(precision_int.x); + int level_y = bits - clz(precision_int.y); + coord_int.x = (coord_int.x >> level_x) << level_x; + coord_int.y = (coord_int.y >> level_y) << level_y; + return generate(coord_int); +} + +void +Generator::generate(Surface &target, const Vector2 <, const Vector2 &rb) const { + if (target.empty()) return; + Vector2 d = rb - lt; + d.x /= target.width(); + d.y /= target.height(); + Vector2 precision = d/2.0; + + Vector2 p = lt; + for(int r = 0; r < target.height(); ++r, p.x = lt.x, p.y += d.y) { + Color *row = target[r]; + for(int c = 0; c < target.width(); ++c, p.x += d.x) { + Vector4 v = generate(p, precision); + row[c].r = flip_clamp(v.x); + row[c].g = flip_clamp(v.y); + row[c].b = flip_clamp(v.z); + row[c].a = flip_clamp(v.w); + } + } +} diff --git a/c++/perspective/src/generator.h b/c++/perspective/src/generator.h new file mode 100644 index 0000000..affe538 --- /dev/null +++ b/c++/perspective/src/generator.h @@ -0,0 +1,58 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + + +#include +#include + +#include "surface.h" +#include "vector.h" + + +class Generator: public Shared { +public: + struct CacheEntry; + typedef std::map Cache; + + struct CacheEntry { + Cache::iterator next, previous; + bool in_use; + Vector4 value; + }; + + static inline ULongInt random(ULongInt x) { + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + return x; + } + static inline Real random_to_real(ULongInt x) + { return Real(x)/Real(ULLONG_MAX); } + +private: + const ULongInt one; + const int max_cache_count; + + mutable Cache m_cache; + mutable Cache::iterator m_cache_top; + mutable int m_cache_count; + + ULongInt m_seeds[2][4]; + +public: + Generator(); + explicit Generator(ULongInt seed); + + inline const ULongInt* seeds_x() const { return m_seeds[0]; } + inline const ULongInt* seeds_y() const { return m_seeds[1]; } + inline ULongInt seed() const { return seeds_x()[0]; } + void set_seed(ULongInt x); + + Real random(const ULongIntVector2 &coord, int index) const; + Vector4 generate(const ULongIntVector2 &coord, bool shrink_cache = true) const; + Vector4 generate(const Vector2 &coord, const Vector2 &precision) const; + void generate(Surface &target, const Vector2 <, const Vector2 &rb) const; +}; + + +#endif diff --git a/c++/perspective/src/main.cpp b/c++/perspective/src/main.cpp new file mode 100644 index 0000000..58eb40d --- /dev/null +++ b/c++/perspective/src/main.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include + +#include "surface.h" +#include "generator.h" + + +int main(int argc, char **argv) { + std::cout << "Lab: prototype of perspective transformation" << std::endl; + Glib::RefPtr application = Gtk::Application::create( + argc, argv, "org.morevnaproject.lab.perspective"); + + std::cout << "generate" << std::endl; + Generator generator; + DataSurface surface(256, 256); + generator.generate(surface, Vector2(0, 0), Vector2(16, 16)); + + std::cout << "convert" << std::endl; + Glib::RefPtr pixbuf = Gdk::Pixbuf::create( + Gdk::COLORSPACE_RGB, true, 8, surface.width(), surface.height() ); + guint8 *pixel = pixbuf->get_pixels(); + for(int r = 0; r < surface.height(); ++r) { + Color *row = surface[r]; + for(int c = 0; c < surface.width(); ++c) { + const Color &color = row[c]; + *(pixel++) = (guint8)(color.r*255.9); + *(pixel++) = (guint8)(color.g*255.9); + *(pixel++) = (guint8)(color.b*255.9); + *(pixel++) = (guint8)(color.a*255.9); + } + } + + std::cout << "create window" << std::endl; + Gtk::Window window; + window.set_default_size(200, 200); + Gtk::Image image(pixbuf); + window.add(image); + window.show_all(); + + std::cout << "run" << std::endl; + int result = application->run(window); + + std::cout << "finished with code " << result << std::endl; +} diff --git a/c++/perspective/src/surface.cpp b/c++/perspective/src/surface.cpp new file mode 100644 index 0000000..104fbe2 --- /dev/null +++ b/c++/perspective/src/surface.cpp @@ -0,0 +1,88 @@ + +#include "surface.h" + + +Surface::Surface(): + m_width(), m_height(), m_pitch(), m_origin() { } + +Surface::Surface(const Surface &): + m_width(), m_height(), m_pitch(), m_origin() { } + +void +Surface::reset() { + m_width = m_height = m_pitch = 0; + m_origin = NULL; +} + +void Surface::copy(int width, int height, const Color *src_origin, Color *dest_origin, int src_pitch, int dest_pitch) { +#ifndef NDEBUG + { // check source and destination ranges + assert(dest_origin); + assert(src_origin); + + Color *dest_begin = dest_origin + begin_offset(width, height, dest_pitch), + *dest_end = dest_origin + end_offset(width, height, dest_pitch); + const Color *src_begin = src_origin + begin_offset(width, height, src_pitch), + *src_end = src_origin + end_offset(width, height, src_pitch); + assert(src_end <= dest_begin || dest_end <= src_begin); + } +#endif + + if (!src_pitch) src_pitch = width; + if (!dest_pitch) dest_pitch = width; + + const Color *src_row = src_origin; + for( Color *dest_row = dest_origin, *dest_row_end = dest_row + height*dest_pitch; + dest_row != dest_row_end; + dest_row += dest_pitch, src_row += src_pitch ) + { + const Color *src_col = src_row; + for( Color *dest_col = dest_row, *dest_col_end = dest_col + width; + dest_col != dest_col_end; + ++dest_col, ++src_col ) + { *dest_col = *src_col; } + } +} + + +void DataSurface::clear() { + if (Color *data = data_begin()) delete[] data; + reset(); +} + +void DataSurface::init(int width, int height, int pitch, const Color *src_origin, int src_pitch) { + Color *origin = NULL; + if (width > 0 && height > 0) { + if (!pitch) pitch = width; + + int count = data_count(width, height, pitch); + int offset = begin_offset(width, height, pitch); + Color *data = new Color[count]; + origin = data - offset; + + if (src_origin) + copy(width, height, src_origin, origin, src_pitch, pitch); + } else { + width = 0; + height = 0; + pitch = 0; + } + + clear(); + m_width = width; + m_height = height; + m_pitch = pitch; + m_origin = origin; +} + + +void AliasSurface::init(Color *origin, int width, int height, int pitch) { + clear(); + if (origin && width > 0 && height > 0) { + m_width = width; + m_height = height; + m_pitch = pitch ? pitch : width; + m_origin = origin; + } +} + diff --git a/c++/perspective/src/surface.h b/c++/perspective/src/surface.h new file mode 100644 index 0000000..69a910c --- /dev/null +++ b/c++/perspective/src/surface.h @@ -0,0 +1,108 @@ +#ifndef SURFACE_H +#define SURFACE_H + + +#include +#include + +#include "common.h" + + +class Surface: public Shared { +protected: + int m_width; + int m_height; + int m_pitch; + Color *m_origin; + + Surface(); + Surface(const Surface &); + Surface& operator= (const Surface &) { return *this; } + void reset(); + +public: + virtual ~Surface() { } + + inline int width() const { return m_width; } + inline int height() const { return m_height; } + inline int pitch() const { return m_pitch; } + inline int count() const { return m_width*m_height; } + inline bool empty() const { return !count(); } + + inline Color* origin() { return m_origin; } + inline const Color* origin() const { return m_origin; } + + inline int data_count() const { return data_count (width(), height(), pitch()); } + inline size_t data_size() const { return data_size (width(), height(), pitch()); } + inline int begin_offset() const { return begin_offset(width(), height(), pitch()); } + inline int end_offset() const { return end_offset (width(), height(), pitch()); } + + inline Color* data_begin() { return m_origin ? m_origin + begin_offset() : NULL; } + inline const Color* data_begin() const { return m_origin ? m_origin + begin_offset() : NULL; } + inline Color* data_end() { return m_origin ? m_origin + end_offset() : NULL; } + inline const Color* data_end() const { return m_origin ? m_origin + end_offset() : NULL; } + + inline Color* row(int index) + { assert(index >= 0 && index < m_height); return m_origin + index*m_pitch; } + inline const Color* row(int index) const + { assert(index >= 0 && index < m_height); return m_origin + index*m_pitch; } + + inline Color* operator[] (int index) { return row(index); } + inline const Color* operator[] (int index) const { return row(index); } + + static inline int data_count(int width, int height, int pitch) + { return width + abs(pitch)*(height - 1); } + static inline size_t data_size(int width, int height, int pitch) + { return data_count(width, height, pitch)*sizeof(Color); } + static inline int begin_offset(int width, int height, int pitch) + { return pitch > 0 ? 0 : width - data_count(width, height, pitch); } + static inline int end_offset(int width, int height, int pitch) + { return pitch > 0 ? data_count(width, height, pitch) : width; } + + static void copy(int width, int height, const Color *src_origin, Color *dest_origin, int src_pitch = 0, int dest_pitch = 0); +}; + + +class DataSurface: public Surface { +public: + explicit DataSurface(int width = 0, int height = 0, int pitch = 0, const Color *src_origin = NULL, int src_pitch = 0) + { init(width, height, pitch, src_origin, src_pitch); } + DataSurface(const Surface &other) + { *this = other; } + ~DataSurface() + { clear(); } + DataSurface& operator= (const Surface &other) + { init(other); return *this; } + + void clear(); + void init(int width, int height, int pitch = 0, const Color *src_origin = NULL, int src_pitch = 0); + inline void init(const Surface &other) + { init(other.width(), other.height(), other.pitch(), other.origin(), other.pitch()); } +}; + + +class AliasSurface: public Surface { +public: + AliasSurface() { } + AliasSurface(Color *origin, int width, int height, int pitch = 0) + { init(origin, width, height, pitch); } + AliasSurface(const AliasSurface &other) + { *this = other; } + AliasSurface(Surface &other) + { init(other); } + AliasSurface& operator= (const AliasSurface &other) + { init(other); return *this; } + + inline Color* origin() const { return m_origin; } + + void init(Color *origin, int width, int height, int pitch = 0); + + inline void clear() { reset(); } + inline void init(Surface &other) + { init(other.origin(), other.width(), other.height(), other.pitch()); } + inline void init(const AliasSurface &other) + { init(other.origin(), other.width(), other.height(), other.pitch()); } +}; + + +#endif diff --git a/c++/perspective/src/vector.h b/c++/perspective/src/vector.h new file mode 100644 index 0000000..59b217a --- /dev/null +++ b/c++/perspective/src/vector.h @@ -0,0 +1,302 @@ +#ifndef VECTOR_H +#define VECTOR_H + + +#include + +#include "common.h" + + +template +class VectorBase2T { +public: + typedef ST SelfType; + typedef LT LowerType; + + typedef SelfType Vector2; + typedef LowerType Coord; + + enum { Count = 2 }; + + union { + struct { Coord coords[Count]; }; + struct { Coord x, y; }; + }; + + inline explicit VectorBase2T(const Coord &x = Coord(), const Coord &y = Coord()): + x(x), y(y) { } + + inline SelfType perp() const + { return SelfType(-y, x); } + inline SelfType yx() const + { return SelfType(y, x); } +}; + + +template +class VectorBase3T { +public: + typedef ST SelfType; + typedef LT LowerType; + + typedef SelfType Vector3; + typedef LowerType Vector2; + typedef typename LowerType::Coord Coord; + + enum { Count = 3 }; + + union { + struct { Coord coords[Count]; }; + struct { Coord x, y, z; }; + }; + + inline explicit VectorBase3T(const Coord &x = Coord(), const Coord &y = Coord(), const Coord &z = Coord()): + x(x), y(y), z(z) { } + inline VectorBase3T(const Vector2 &v, const Coord &z): + x(v.x), y(v.y), z(z) { } + + inline SelfType cross(const SelfType &other) const + { return SelfType(y*other.z - z*other.y, z*other.x - x*other.z, x*other.y - y*other.x); } + + inline Vector2& vec2() + { return *(Vector2*)this; }; + inline const Vector2& vec2() const + { return *(const Vector2*)this; }; + + inline SelfType xzy() const + { return SelfType(x, z, y); } + inline SelfType zxy() const + { return SelfType(z, x, y); } + inline SelfType zyx() const + { return SelfType(z, y, x); } + inline SelfType yxz() const + { return SelfType(y, x, z); } + inline SelfType yzx() const + { return SelfType(y, z, x); } +}; + + +template +class VectorBase4T { +public: + typedef ST SelfType; + typedef LT LowerType; + + typedef SelfType Vector4; + typedef LowerType Vector3; + typedef typename LowerType::Vector2 Vector2; + typedef typename LowerType::Coord Coord; + + enum { Count = 4 }; + + union { + struct { Coord coords[Count]; }; + struct { Coord x, y, z, w; }; + }; + + inline explicit VectorBase4T(const Coord &x = Coord(), const Coord &y = Coord(), const Coord &z = Coord(), const Coord &w = Coord()): + x(x), y(y), z(z), w(w) { } + inline VectorBase4T(const Vector2 &v, const Coord &z, const Coord &w = Coord()): + x(v.x), y(v.y), z(z), w(w) { } + inline VectorBase4T(const Vector3 &v, const Coord &w): + x(v.x), y(v.y), z(v.z), w(w) { } + + inline Vector3& vec3() + { return *(Vector3*)this; }; + inline const Vector3& vec3() const + { return *(const Vector3*)this; }; + + inline Vector2& vec2() + { return *(Vector2*)this; }; + inline const Vector2& vec2() const + { return *(const Vector2*)this; }; + + inline SelfType cross(const SelfType &other) const + { return SelfType(y*other.z - z*other.y, z*other.x - x*other.z, x*other.y - y*other.x, w); } +}; + + +template +class VectorT: public T { +public: + typedef T ParentType; + using ParentType::Count; + using typename ParentType::Coord; + using typename ParentType::SelfType; + using ParentType::coords; + using ParentType::ParentType; // contructors + + inline VectorT() { } + + inline explicit VectorT(const Coord *c) { + assert(c); + for(int i = 0; i < Count; ++i) coords[i] = c[i]; + } + + template + inline explicit VectorT(const VectorT &v) { + const int cnt = TT::Count < Count ? TT::Count : Count; + for(int i = 0; i < cnt; ++i) coords[i] = Coord(v.coords[i]); + for(int i = cnt; i < Count; ++i) coords[i] = Coord(); + } + + Coord& operator[] (int i) + { assert(i >= 0 && i < Count); return coords[i]; } + const Coord& operator[] (int i) const + { assert(i >= 0 && i < Count); return coords[i]; } + + inline bool operator< (const SelfType &other) const { + for(int i = 0; i < Count; ++i) + if (coords[i] < other.coords[i]) return true; + else if (other.coords[i] < coords[i]) return false; + return false; + } + + inline bool operator== (const SelfType &other) const { + for(int i = 0; i < Count; ++i) + if (coords[i] != other.coords[i]) return false; + return true; + } + + inline bool operator!= (const SelfType &other) const + { return !(*(const SelfType*)this == other); } + + inline SelfType& operator+= (const SelfType &other) { + for(int i = 0; i < Count; ++i) coords[i] += other.coords[i]; + return *(SelfType*)this; + } + inline SelfType& operator-= (const SelfType &other) { + for(int i = 0; i < Count; ++i) coords[i] -= other.coords[i]; + return *(SelfType*)this; + } + inline SelfType& operator*= (const Coord &c) { + for(int i = 0; i < Count; ++i) coords[i] *= c; + return *(SelfType*)this; + } + inline SelfType operator- () const { + SelfType v; + for(int i = 0; i < Count; ++i) v.coords[i] = -coords[i]; + return v; + } + inline Coord operator* (const SelfType &other) const { + Coord r = Coord(); + for(int i = 0; i < Count; ++i) r += coords[i]*other.coords[i]; + return r; + } + + inline SelfType operator+ (const SelfType &other) const + { return SelfType(*this) += other; } + inline SelfType operator- (const SelfType &other) const + { return SelfType(*this) -= other; } + inline SelfType operator* (const Coord &c) const + { return SelfType(*this) *= c; } + inline Coord square() const + { return *this * *this; } +}; + + +template +class VectorFT: public VectorT { +public: + typedef VectorT ParentType; + using ParentType::Count; + using typename ParentType::Coord; + using typename ParentType::SelfType; + using ParentType::coords; + using ParentType::ParentType; // contructors + + + inline SelfType& operator/= (const Coord &c) + { return *this *= Coord(1)/c; } + inline SelfType operator/ (const Coord &c) + { return SelfType(*this) /= c; } + inline Coord length() const + { return Coord(sqrt(ParentType::square())); } + + inline bool operator< (const SelfType &other) const { + for(int i = 0; i < Count; ++i) + if (coords[i] < other.coords[i] - realRrecision) return true; + else if (other.coords[i] < coords[i] - realRrecision) return false; + return false; + } + + inline bool operator== (const SelfType &other) const { + for(int i = 0; i < Count; ++i) + if ( coords[i] < other.coords[i] - realRrecision + || other.coords[i] < coords[i] - realRrecision ) return false; + return true; + } + + inline bool operator!= (const SelfType &other) const + { return !(*(const SelfType*)this == other); } +}; + + +template +class Vectors { +public: + typedef T Type; + + class Vector2: public VectorT< VectorBase2T > { + public: + typedef VectorT< VectorBase2T > ParentType; + using ParentType::ParentType; // constructors + }; + class Vector3: public VectorT< VectorBase3T > { + public: + typedef VectorT< VectorBase3T > ParentType; + using ParentType::ParentType; // constructors + }; + class Vector4: public VectorT< VectorBase4T > { + public: + typedef VectorT< VectorBase4T > ParentType; + using ParentType::ParentType; // constructors + }; +}; + + +template +class VectorsFloat { +public: + typedef T Type; + + class Vector2: public VectorFT< VectorBase2T > { + public: + typedef VectorFT< VectorBase2T > ParentType; + using ParentType::ParentType; // constructors + }; + class Vector3: public VectorFT< VectorBase3T > { + public: + typedef VectorFT< VectorBase3T > ParentType; + using ParentType::ParentType; // constructors + }; + class Vector4: public VectorFT< VectorBase4T > { + public: + typedef VectorFT< VectorBase4T > ParentType; + using ParentType::ParentType; // constructors + }; +}; + + +typedef VectorsFloat::Vector2 Vector2; +typedef VectorsFloat::Vector3 Vector3; +typedef VectorsFloat::Vector4 Vector4; + +typedef VectorsFloat::Vector2 IntVector2; +typedef VectorsFloat::Vector3 IntVector3; +typedef VectorsFloat::Vector4 IntVector4; + +typedef VectorsFloat::Vector2 LongIntVector2; +typedef VectorsFloat::Vector3 LongIntVector3; +typedef VectorsFloat::Vector4 LongIntVector4; + +typedef VectorsFloat::Vector2 UIntVector2; +typedef VectorsFloat::Vector3 UIntVector3; +typedef VectorsFloat::Vector4 UIntVector4; + +typedef VectorsFloat::Vector2 ULongIntVector2; +typedef VectorsFloat::Vector3 ULongIntVector3; +typedef VectorsFloat::Vector4 ULongIntVector4; + + +#endif