diff options
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/allocator.h | 11 | ||||
| -rw-r--r-- | src/util/callback.h | 84 | ||||
| -rw-r--r-- | src/util/color.h | 4 | ||||
| -rw-r--r-- | src/util/config.h | 25 | ||||
| -rw-r--r-- | src/util/config/config.cpp | 13 | ||||
| -rw-r--r-- | src/util/config/serializers.cpp | 115 | ||||
| -rw-r--r-- | src/util/file.h | 4 | ||||
| -rw-r--r-- | src/util/input.h | 3 | ||||
| -rw-r--r-- | src/util/str_tokenizer.h | 140 | ||||
| -rw-r--r-- | src/util/string.h | 27 | ||||
| -rw-r--r-- | src/util/vector.h | 8 |
11 files changed, 335 insertions, 99 deletions
diff --git a/src/util/allocator.h b/src/util/allocator.h index 327dfc1..623d227 100644 --- a/src/util/allocator.h +++ b/src/util/allocator.h @@ -2,8 +2,7 @@ #include <stdlib.h> #include <string.h> -#include <functional> -#include "typedef.h" +#include "callback.h" template <typename T> struct LIST_ITERATOR { @@ -19,7 +18,7 @@ struct LIST_ITERATOR { }; template <typename T> -using QSORT_FN = std::function< U8( T*, T* ) >; +using QSORT_FN = FN< U8( T*, T* ) >; template <typename T> static U8 qsort_basic_sort( T* t1, T* t2 ) { @@ -58,8 +57,8 @@ struct LIST { U32 capacity; U32 size; - using ON_EACH_FN = std::function< void(T*) >; - using ON_SEARCH_FN = std::function< bool(T*) >; + using ON_EACH_FN = FN< void(T*) >; + using ON_SEARCH_FN = FN< U8(T*) >; LIST() { data = (T*)malloc( sizeof( T ) ); @@ -265,6 +264,8 @@ struct LIST { } T ret = data[--size]; + if constexpr( !__is_trivially_destructible(T) ) + data[size].~T(); if( size < capacity / 4 ) shrink(); diff --git a/src/util/callback.h b/src/util/callback.h new file mode 100644 index 0000000..a2c9477 --- /dev/null +++ b/src/util/callback.h @@ -0,0 +1,84 @@ +#pragma once +#include "typedef.h" + +template <typename T> +struct FN; +// voodoo +template <typename RET, typename... ARGS> +struct FN<RET(ARGS...)> { + template <typename T> struct __strip_ref { using type = T; }; + template <typename T> struct __strip_ref<T&> { using type = T; }; + template <typename T> struct __strip_ref<T&&> { using type = T; }; + template <typename R, typename... A> struct __strip_ref<R(A...)> { using type = R(*)(A...); }; + template <typename R, typename... A> struct __strip_ref<R(&)(A...)> { using type = R(*)(A...); }; + + static const unsigned int BUF_SIZE = 32; + + alignas(8) char buf[BUF_SIZE]; + void* data; + RET( *invoke )( void*, ARGS... ); + void( *destroy )( void* ); + void*( *clone )( void*, char* ); + + template <typename F> + FN(F&& f) { + using __stripped = typename __strip_ref<F>::type; + + if constexpr( sizeof(__stripped) <= BUF_SIZE ) { + new (buf) __stripped( f ); + data = buf; + destroy = pfn( void* d ) { + ( (__stripped*)d )->~__stripped(); + }; + clone = pfn( void* d, char* dst ) -> void* { + new (dst) __stripped( *(__stripped*)d ); + return dst; + }; + } else { + data = new __stripped( f ); + destroy = pfn( void* d ) { + delete (__stripped*)d; + }; + clone = pfn( void* d, char* dst ) -> void* { + return new __stripped( *(__stripped*)d ); + }; + } + + invoke = pfn( void* d, ARGS... args ) -> RET { + return ( *(__stripped*)d )( args... ); + }; + } + + FN( I32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN( U32&& ) : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + FN() : data( 0 ), invoke( 0 ), destroy( 0 ), clone( 0 ) {} + + FN( const FN& other ) : invoke( other.invoke ), destroy( other.destroy ), clone( other.clone ) { + if( !other.data ) { + data = 0; + return; + } + + data = other.clone( other.data, buf ); + } + + FN& operator=( const FN& other ) { + if( this == &other ) return *this; + if( destroy && data ) destroy( data ); + invoke = other.invoke; + destroy = other.destroy; + clone = other.clone; + data = other.data ? other.clone( other.data, buf ) : 0; + return *this; + } + + ~FN() { + if( destroy && data ) destroy( data ); + } + + RET operator()( ARGS... args ) const { + return invoke( data, args... ); + } + + operator bool() const { return !!invoke; } +}; diff --git a/src/util/color.h b/src/util/color.h index 526cddc..8b1a259 100644 --- a/src/util/color.h +++ b/src/util/color.h @@ -1,5 +1,5 @@ #pragma once -#include "typedef.h" +#include "string.h" #include <math.h> struct CLR { @@ -166,3 +166,5 @@ struct CLR { return *this; } }; + +inline STR to_str( CLR c ) { return STR( "%.02f %.02f %.02f %.02f", c.r, c.g, c.b, c.a ); } diff --git a/src/util/config.h b/src/util/config.h index 7973db0..d8c1c2e 100644 --- a/src/util/config.h +++ b/src/util/config.h @@ -1,7 +1,7 @@ #pragma once #include <stdio.h> -#include "allocator.h" +#include "string.h" #include "vector.h" #include "color.h" @@ -26,8 +26,8 @@ enum CfgNodeType_t { // ===================================== [ definitions ] =========================================== -using CFG_PARSEFN = std::function<void( CFG_PARSER*, CFG_SECTION*, char* )>; -using CFG_SERIALIZEFN = std::function<void( CFG_SERIALIZER*, CFG_NODE*, char* )>; +using CFG_PARSEFN = FN<STAT( CFG_PARSER*, CFG_SECTION*, char* )>; +using CFG_SERIALIZEFN = FN<STR( CFG_SERIALIZER*, CFG_NODE*)>; struct CFG_TYPE { U8 type; @@ -37,7 +37,7 @@ struct CFG_TYPE { }; struct CFG_NODE { - char name[64]; + STR name; CFG_NODE* parent; U8 type; }; @@ -66,14 +66,14 @@ extern STAT cfg_parser_clr( CFG_PARSER* parser, CFG_SECTION* section, char* name // ====================================== [ serializers ] ========================================== -extern void cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section, char* buf ); -extern void cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); -extern void cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node, char* buf ); +extern STR cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section ); +extern STR cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node ); +extern STR cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node ); // ========================================= [ config ] ============================================ @@ -158,6 +158,7 @@ static void cfg_free( CFG_NODE* n ) { else if( n->type == CFGT_SECTION ) { CFG_SECTION* s = (CFG_SECTION*)n; s->children.each( fn( CFG_NODE** child ) { cfg_free( *child ); } ); + return delete s; } delete n; diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp index a41e455..00a2512 100644 --- a/src/util/config/config.cpp +++ b/src/util/config/config.cpp @@ -30,9 +30,7 @@ inline void trim_whitespace( char* buf ) { } inline void init_cfg_node( CFG_NODE* node, const char* name, CFG_NODE* parent, U8 type ) { - memset( node->name, 0, sizeof(node->name) ); - strcpy( node->name, name ); - node->name[sizeof(node->name) - 1] = '\0'; + node->name = name; node->parent = parent; if( parent ) ( (CFG_SECTION*)parent )->children.push( node ); @@ -290,17 +288,12 @@ STAT cfg_save( CFG_SECTION* root, const char* path ) { if( !f ) return STAT_ERR; - char* buf = (char*)malloc( 999999 ); - buf[0] = 0; CFG_SERIALIZER s; s.tabc = 0; s.f = f; - cfg_serialize_section( &s, (CFG_NODE*)root, buf ); - U32 len = strlen( buf ); - - fwrite( buf, 1, len, f ); - free( buf ); + STR buf = cfg_serialize_section( &s, (CFG_NODE*)root ); + fwrite( buf, 1, buf.size, f ); fclose( f ); return STAT_OK; diff --git a/src/util/config/serializers.cpp b/src/util/config/serializers.cpp index 01f416c..15ddae0 100644 --- a/src/util/config/serializers.cpp +++ b/src/util/config/serializers.cpp @@ -1,109 +1,122 @@ -#include <cstdarg> -#include <cstdio> - #include "../config.h" -void serialize_node( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) { - U32 len = strlen( buf ); - for( U32 i = 0; i < s->tabc * 2; ++i ) buf[i + len] = ' '; - buf[len + s->tabc * 2] = 0; - sprintf( buf, "%s%s %s", buf, cfg_types[n->type].def, n->name ); +STR serialize_node( CFG_SERIALIZER* s, CFG_NODE* n ) { + STR ret{}; + for( U32 i = 0; i < s->tabc * 2; ++i ) ret.append( " " ); + ret.fmt( "%s %s", cfg_types[n->type].def, n->name.data ); + + return ret; } -void cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n, char *buf ) { +STR cfg_serialize_section( CFG_SERIALIZER* s, CFG_NODE *n ) { CFG_SECTION* sec = (CFG_SECTION*)n; + STR buf; if( sec->parent ) { - serialize_node( s, n, buf ); - strcat( buf, " {\n" ); + buf += serialize_node( s, n ); + buf += " {\n"; s->tabc++; } - char line[8192]; for( U32 i = 0; i < sec->children.size; ++i ) { - line[0] = 0; CFG_NODE* c = sec->children[i]; if( c->type == CFGT_SECTION ) { - cfg_serialize_section( s, c, buf ); + buf += cfg_serialize_section( s, c ); continue; } - cfg_types[c->type].serializer( s, c, line ); - strcat( buf, line ); - strcat( buf, "\n" ); + buf += cfg_types[c->type].serializer( s, c ); + buf += "\n"; } if( sec->parent ) { s->tabc--; - char tabbuf[512] = { 0 }; - for( U32 i = 0 ; i < s->tabc * 2; ++i ) - tabbuf[i] = ' '; - tabbuf[s->tabc * 2] = 0; - strcat( buf, tabbuf ); - strcat( buf, "}" ); + for( U32 i = 0 ; i < s->tabc * 2; ++i ) buf += ' '; + buf += "}"; if( sec->parent ) - strcat( buf, "\n" ); + buf += "\n"; } + + return buf; } -void cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n, char* buf ) { +STR cfg_serialize_bytes( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_BYTES* b = (CFG_BYTES*)n; U32 size = b->size; U8* bytes = b->bytes; - serialize_node( s, n, buf ); - sprintf( buf, "%s[%d] = \"", buf, size ); - U32 len = strlen( buf ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( "[%d] = \"", size ); for( U32 i = 0; i < size; ++i ) { - sprintf( buf + len + i * 2, "%02X", bytes[i] ); + buf.fmt( "%02X", bytes[i] ); } - - sprintf( buf, "%s%s", buf, "\";" ); + buf += "\";"; + return buf; } -void cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_str( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_STR* sn = (CFG_STR*)n; char* str = sn->str; - serialize_node( s, n, buf ); - sprintf( buf, "%s[%d] = \"%s\";", buf, sn->len, str ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( "[%d] = \"%s\";", sn->len, str ); + return buf; } -void cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { - CFG_INT* i = (CFG_INT*)n; - I32 ival = i->value; +STR cfg_serialize_int( CFG_SERIALIZER* s, CFG_NODE* n ) { + CFG_INT* i = (CFG_INT*)n; + I32 ival = i->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = %d;", buf, ival ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = %d;", ival ); + return buf; } -void cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_float( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_FLOAT* f = (CFG_FLOAT*)n; F32 fval = f->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = %g;", buf, fval ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = %g;", fval ); + return buf; } -void cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_vec2( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_VEC2* v = (CFG_VEC2*)n; VEC2 val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g };", buf, val.x, val.y ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g };", val.x, val.y ); + return buf; } -void cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_vec3( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_VEC3* v = (CFG_VEC3*)n; VEC3 val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g, %g };", buf, val.x, val.y, val.z ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g, %g };", val.x, val.y, val.z ); + return buf; } -void cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n, char *buf ) { +STR cfg_serialize_clr( CFG_SERIALIZER* s, CFG_NODE* n ) { CFG_CLR* v = (CFG_CLR*)n; CLR val = v->value; - serialize_node( s, n, buf ); - sprintf( buf, "%s = { %g, %g, %g, %g };", buf, val.r, val.g, val.b, val.a ); + STR buf{}; + + buf += serialize_node( s, n ); + buf.fmt( " = { %g, %g, %g, %g };", val.r, val.g, val.b, val.a ); + return buf; } diff --git a/src/util/file.h b/src/util/file.h index 7e4d413..4309e62 100644 --- a/src/util/file.h +++ b/src/util/file.h @@ -1,7 +1,7 @@ #pragma once -#include <cstdlib> -#include <cstring> +#include <stdlib.h> +#include <string.h> #include <stdio.h> #include <dirent.h> #include <sys/stat.h> diff --git a/src/util/input.h b/src/util/input.h index 1317f94..af5e258 100644 --- a/src/util/input.h +++ b/src/util/input.h @@ -1,7 +1,6 @@ #pragma once #include <SDL_events.h> -#include <functional> #include "vector.h" #include "allocator.h" @@ -33,7 +32,7 @@ struct INPUT_KEYBINDS { U8 crouch = SDL_SCANCODE_LCTRL; }; -using ON_INPUT_FN = std::function<void( SDL_Event* )>; +using ON_INPUT_FN = FN<void( SDL_Event* )>; struct INPUT_DATA { MOUSE_DATA mouse; diff --git a/src/util/str_tokenizer.h b/src/util/str_tokenizer.h new file mode 100644 index 0000000..8a3aebf --- /dev/null +++ b/src/util/str_tokenizer.h @@ -0,0 +1,140 @@ +#pragma once + +#include "string.h" + +using TOKENIZER_COMPARE_FN = FN<U8( char )>; + +struct STR_TOKENIZER { + STR str; + STR ignored; + + I32 cur; + I32 last; +}; + +inline STR_TOKENIZER tok_init( STR str, STR whitespace_chars = " \t\n\r" ) { + return { + .str = str, + .ignored = { whitespace_chars }, + .cur = 0, + .last = 0, + }; +} + +inline STR tok_next( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return ""; + + U8 start = 0; + for( I32 i = t->cur; i < t->str.size; i++ ) { + U8 c = t->str.data[i]; + if( i == t->str.size - 1 ) { + if( !start ) + return ""; + + STR ret = { (U32)i - t->cur + 1, t->str.data + t->cur }; + t->last = t->cur; + t->cur = i + 1; + return ret; + } + + for( auto& it : t->ignored ) { + if( c == it ) { + if( !start ) { + t->cur = i + 1; + continue; + } else { + STR ret = { (U32)i - t->cur, t->str.data + t->cur }; + t->last = t->cur; + t->cur = i + 1; + return ret; + } + } + } + + start = 1; + } + + return ""; +} + +inline STR tok_peek( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return ""; + + U8 start = 0; + I32 cur = t->cur; + for( I32 i = cur; i < t->str.size; i++ ) { + U8 c = t->str.data[i]; + if( i == t->str.size - 1 ) { + if( !start ) + return ""; + + STR ret = { (U32)i - cur + 1, t->str.data + cur }; + return ret; + } + + for( auto& it : t->ignored ) { + if( c == it ) { + if( !start ) { + cur = i + 1; + continue; + } else { + STR ret = { (U32)i - cur, t->str.data + cur }; + return ret; + } + } + } + + start = 1; + } + + return ""; +} + + +inline STR tok_next( STR_TOKENIZER* t, STR what ) { + if( t->cur >= t->str.size ) + return ""; + + if( !what.size ) + return ""; + + for( I32 i = t->cur; i <= t->str.size - what.size; i++ ) { + STR slice = { what.size, t->str.data + i }; + if( slice == what ) { + STR ret = { (U32)i - t->cur, t->str.data + i + what.size }; + t->last = t->cur; + t->cur = i + what.size; + return ret; + } + } + + return ""; +} + +inline char tok_nextchar( STR_TOKENIZER* t ) { + if( t->cur >= t->str.size ) + return 0; + + U32 last = t->cur; + for( ; t->cur < t->str.size; t->cur++ ) { + U8 cont = 0; + for( auto& it : t->ignored ) { + if( t->str.data[t->cur] == it ) { + cont = 1; + break; + } + } + + if( cont ) + continue; + else { + t->last = last; + t->cur++; + return t->str.data[t->cur]; + } + } + + return 0; +} diff --git a/src/util/string.h b/src/util/string.h index 2268a36..672fb5d 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -55,8 +55,6 @@ template <typename CT> struct __str : public LIST<CT> { __str() : LIST<CT>() {} __str( U32 count, const CT* str ) : LIST<CT>() { - this->data = 0; - this->capacity = 0; this->reserve( count * 2 ); memcpy( this->data, str, count ); this->size = count; @@ -69,8 +67,6 @@ struct __str : public LIST<CT> { va_copy( args2, args ); U32 c = vsnprintf( 0, 0, fmt, args ); va_end( args ); - this->data = 0; - this->capacity = 0; this->reserve( c * 2 ); vsnprintf( this->data, c + 1, fmt, args2 ); this->data[c] = 0; @@ -89,8 +85,6 @@ struct __str : public LIST<CT> { if( this->data && this->data != other.data ) free( this->data ); - this->data = 0; - if( !other.capacity || !other.size ) { this->capacity = 1; this->size = 0; @@ -116,8 +110,9 @@ struct __str : public LIST<CT> { __str<CT> operator+( const CT rhs ) { __str<CT> ret = *this; ret.push( rhs ); return ret; } __str<CT>& operator+=( const __str<CT>& rhs ) { return this->append( rhs ); } __str<CT>& operator+=( const CT* rhs ) { return this->append( rhs ); } - __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return this; } + __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return *this; } + operator const CT*() { return this->data; } operator CT*() { return this->data; } CT operator[]( U32 i ) { @@ -128,10 +123,8 @@ struct __str : public LIST<CT> { if( rhs.size != this->size ) return 0; - for( U32 i = 0; i < this->size; ++i ) { - if( this->data[i] != rhs.data[i] ) - return 0; - } + if( !!memcmp( this->data, rhs.data, this->size ) ) + return 0; return 1; } @@ -165,7 +158,7 @@ struct __str : public LIST<CT> { __str<CT>& append( const CT* str ) { U32 len; for( len = 0; !!str[len]; ++len ); - if( this->size + len > this->capacity ) + if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); memcpy( this->data + this->size, str, len * sizeof(CT) ); @@ -179,7 +172,7 @@ struct __str : public LIST<CT> { if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); - memcpy( this->data + this->size, str, len * sizeof(CT) ); + memcpy( this->data + this->size, str.data, len * sizeof(CT) ); this->size += len; this->data[this->size] = 0; return *this; @@ -281,3 +274,11 @@ struct __str : public LIST<CT> { using STR = __str<char>; using WSTR = __str<wchar_t>; + +inline STR to_str( F32 f ) { return STR( "%.02f", f ); } +inline STR to_str( F64 f ) { return STR( "%.02g", f ); } +inline STR to_str( I32 i ) { return STR( "%d", i ); } +inline STR to_str( I64 i ) { return STR( "%lld", i ); } +inline STR to_str( U32 u ) { return STR( "%u", u ); } +inline STR to_str( U64 u ) { return STR( "%llu", u ); } +inline STR to_str( void* p ) { return STR( "%llx", (U64)p ); } diff --git a/src/util/vector.h b/src/util/vector.h index 854b454..eb386ab 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -1,7 +1,7 @@ #pragma once #include <math.h> -#include "typedef.h" +#include "string.h" static const F32 PI = 3.14159265359f; static const F32 PIRAD = 0.01745329251f; @@ -13,7 +13,6 @@ struct VEC2 { VEC2() { x = y = 0.0f; } VEC2( F32 X, F32 Y ) { x = X; y = Y; } - VEC2( const F32* v ) { x = v[0]; y = v[1]; } VEC2( const VEC2& v ) { x = v.x; y = v.y; } bool operator==( const VEC2& v ) const { return ( x == v.x && y == v.y ); } @@ -49,7 +48,6 @@ struct VEC3 { VEC3() { x = y = z = 0.0f; } VEC3( F32 X, F32 Y, F32 Z ) { x = X; y = Y; z = Z; } - VEC3( const F32* v ) { x = v[0]; y = v[1]; z = v[2]; } VEC3( const VEC3& v ) { x = v.x; y = v.y; z = v.z; } VEC3( const VEC2& v ) { x = v.x; y = v.y; z = 0.f; } @@ -250,3 +248,7 @@ inline void angle_vectors( const VEC3& angles, VEC3* forward, VEC3* right, VEC3* up->z = cr * cp; } } + +inline STR to_str( VEC2 v ) { return STR( "%.02f, %.02f", v.x, v.y ); } +inline STR to_str( VEC3 v ) { return STR( "%.02f, %.02f, %.02f", v.x, v.y, v.z ); } +inline STR to_str( VEC4 v ) { return STR( "%.02f, %.02f, %.02f, %.02f", v.x, v.y, v.z, v.w ); } |
