Browse Source

Added vertex pack/unpack support.

bkaradzic 13 years ago
parent
commit
446686b48f

+ 37 - 39
examples/06-bump/bump.cpp

@@ -42,21 +42,6 @@ uint32_t packUint32(uint8_t _x, uint8_t _y, uint8_t _z, uint8_t _w)
 	return un.ui32;
 }
 
-void unpackUint32(uint8_t _result[4], uint32_t _packed)
-{
-	union
-	{
-		uint32_t ui32;
-		uint8_t arr[4];
-	} un;
-
-	un.ui32	= _packed;
-	_result[0] = un.arr[0];
-	_result[1] = un.arr[1];
-	_result[2] = un.arr[2];
-	_result[3] = un.arr[3];
-}
-
 uint32_t packF4u(float _x, float _y = 0.0f, float _z = 0.0f, float _w = 0.0f)
 {
 	const uint8_t xx = uint8_t(_x*127.0f + 128.0f);
@@ -66,16 +51,6 @@ uint32_t packF4u(float _x, float _y = 0.0f, float _z = 0.0f, float _w = 0.0f)
 	return packUint32(xx, yy, zz, ww);
 }
 
-void unpackF4u(float _result[4], uint32_t _packed)
-{
-	uint8_t unpacked[4];
-	unpackUint32(unpacked, _packed);
-	_result[0] = (float(unpacked[0]) - 128.0f)/127.0f;
-	_result[1] = (float(unpacked[1]) - 128.0f)/127.0f;
-	_result[2] = (float(unpacked[2]) - 128.0f)/127.0f;
-	_result[3] = (float(unpacked[3]) - 128.0f)/127.0f;
-}
-
 static PosNormalTangentTexcoordVertex s_cubeVertices[24] =
 {
 	{-1.0f,  1.0f,  1.0f, packF4u( 0.0f,  0.0f,  1.0f), 0, 0.0f, 0.0f },
@@ -172,18 +147,42 @@ static const bgfx::Memory* loadTexture(const char* _name)
 	return load(filePath);
 }
 
-template<typename Ty>
-void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices, uint16_t _numVertices)
+void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
 {
+	struct PosTexcoord
+	{
+		float m_x;
+		float m_y;
+		float m_z;
+		float m_pad0;
+		float m_u;
+		float m_v;
+		float m_pad1;
+		float m_pad2;
+	};
+
 	float* tangents = new float[6*_numVertices];
 	memset(tangents, 0, 6*_numVertices*sizeof(float) );
 
+	PosTexcoord v0;
+	PosTexcoord v1;
+	PosTexcoord v2;
+
 	for (uint32_t ii = 0, num = _numIndices/3; ii < num; ++ii)
 	{
 		const uint16_t* indices = &_indices[ii*3];
-		const Ty& v0 = _vertices[indices[0] ];
-		const Ty& v1 = _vertices[indices[1] ];
-		const Ty& v2 = _vertices[indices[2] ];
+		uint32_t i0 = indices[0];
+		uint32_t i1 = indices[1];
+		uint32_t i2 = indices[2];
+
+		bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _decl, _vertices, i0);
+		bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i0);
+
+		bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _decl, _vertices, i1);
+		bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i1);
+
+		bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _decl, _vertices, i2);
+		bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i2);
 
 		const float bax = v1.m_x - v0.m_x;
 		const float bay = v1.m_y - v0.m_y;
@@ -224,12 +223,11 @@ void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices,
 
 	for (uint32_t ii = 0; ii < _numVertices; ++ii)
 	{
-		Ty& v0 = _vertices[ii];
 		const float* tanu = &tangents[ii*6];
 		const float* tanv = &tangents[ii*6 + 3];
 
 		float normal[4];
-		unpackF4u(normal, v0.m_normal);
+		bgfx::vertexUnpack(normal, bgfx::Attrib::Normal, _decl, _vertices, ii);
 		float ndt = vec3Dot(normal, tanu);
 
 		float nxt[3];
@@ -240,13 +238,13 @@ void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices,
 		tmp[1] = tanu[1] - normal[1] * ndt;
 		tmp[2] = tanu[2] - normal[2] * ndt;
 
-		float tangent[3];
+		float tangent[4];
 		vec3Norm(tangent, tmp);
 
-		float tw = vec3Dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
-		v0.m_tangent = packF4u(tangent[0], tangent[1], tangent[2], tw);
+		tangent[3] = vec3Dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
+		bgfx::vertexPack(tangent, true, bgfx::Attrib::Tangent, _decl, _vertices, ii);
 	}
-}
+} 
 
 int _main_(int _argc, char** _argv)
 {
@@ -293,14 +291,14 @@ int _main_(int _argc, char** _argv)
 	// Create vertex stream declaration.
 	s_PosNormalTangentTexcoordDecl.begin();
 	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);
-	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true);
-	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true);
+	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
+	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
 	s_PosNormalTangentTexcoordDecl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
 	s_PosNormalTangentTexcoordDecl.end();
 
 	const bgfx::Memory* mem;
 
-	calcTangents(s_cubeIndices, countof(s_cubeIndices), s_cubeVertices, countof(s_cubeVertices) );
+	calcTangents(s_cubeVertices, countof(s_cubeVertices), s_PosNormalTangentTexcoordDecl, s_cubeIndices, countof(s_cubeIndices) );
 
 	// Create static vertex buffer.
 	mem = bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) );

+ 17 - 1
examples/07-callback/callback.cpp

@@ -329,7 +329,10 @@ struct BgfxCallback : public bgfx::CallbackI
 
 	virtual void fatal(bgfx::Fatal::Enum _code, const char* _str) BX_OVERRIDE
 	{
+		// Something unexpected happened, inform user and bail out.
 		dbgPrintf("Fatal error: 0x%08x: %s", _code, _str);
+
+		// Must terminate, continuing will cause crash anyway.
 		abort();
 	}
 
@@ -337,14 +340,18 @@ struct BgfxCallback : public bgfx::CallbackI
 	{
 		char filePath[256];
 		bx::snprintf(filePath, sizeof(filePath), "%016" PRIx64, _id);
+
+		// Use cache id as filename.
 		FILE* file = fopen(filePath, "rb");
 		if (NULL != file)
 		{
 			uint32_t size = fsize(file);
 			fclose(file);
+			// Return size of shader file.
 			return size;
 		}
 
+		// Return 0 if shader is not found.
 		return 0;
 	}
 
@@ -352,14 +359,20 @@ struct BgfxCallback : public bgfx::CallbackI
 	{
 		char filePath[256];
 		bx::snprintf(filePath, sizeof(filePath), "%016" PRIx64, _id);
+
+		// Use cache id as filename.
 		FILE* file = fopen(filePath, "rb");
 		if (NULL != file)
 		{
+			// Read shader.
 			size_t result = fread(_data, 1, _size, file);
 			fclose(file);
+
+			// Make sure that read size matches requested size.
 			return result == _size;
 		}
 
+		// Shader is not found in cache, needs to be rebuilt.
 		return false;
 	}
 
@@ -368,9 +381,11 @@ struct BgfxCallback : public bgfx::CallbackI
 		char filePath[256];
 		bx::snprintf(filePath, sizeof(filePath), "%016" PRIx64, _id);
 
+		// Use cache id as filename.
 		FILE* file = fopen(filePath, "wb");
 		if (NULL != file)
 		{
+			// Write shader to cache location.
 			fwrite(_data, 1, _size, file);
 			fclose(file);
 		}
@@ -378,6 +393,7 @@ struct BgfxCallback : public bgfx::CallbackI
 
 	virtual void screenShot(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t /*_size*/, bool _yflip) BX_OVERRIDE
 	{
+		// Save screen shot as TGA.
 		saveTga(_filePath, _width, _height, _pitch, _data, false, _yflip);
 	}
 
@@ -556,7 +572,7 @@ int _main_(int _argc, char** _argv)
 			}
 		}
 
-		// Take screenshot at frame 150.
+		// Take screen shot at frame 150.
 		if (150 == frame)
 		{
 			bgfx::saveScreenShot("frame150.tga");

BIN
examples/runtime/meshes/bunny.bin


BIN
examples/runtime/meshes/bunny.ctm


+ 10 - 4
include/bgfx.h

@@ -386,8 +386,8 @@ namespace bgfx
 		virtual void captureFrame(const void* _data, uint32_t _size) = 0;
 	};
 
-	inline CallbackI::~CallbackI()
-	{
+	inline CallbackI::~CallbackI()
+	{
 	}
 
 	struct Memory
@@ -442,10 +442,10 @@ namespace bgfx
 		void end();
 
 		/// Add attribute to VertexDecl. Note: Must be called between begin/end.
-		void add(Attrib::Enum _attrib, uint8_t _num, AttribType::Enum _type, bool _normalized = false);
+		void add(Attrib::Enum _attrib, uint8_t _num, AttribType::Enum _type, bool _normalized = false, bool _asInt = false);
 
 		/// Decode attribute.
-		void decode(Attrib::Enum _attrib, uint8_t& _num, AttribType::Enum& _type, bool& _normalized) const;
+		void decode(Attrib::Enum _attrib, uint8_t& _num, AttribType::Enum& _type, bool& _normalized, bool& _asInt) const;
 
 		/// Returns true if VertexDecl contains attribute.
 		bool has(Attrib::Enum _attrib) const { return 0xff != m_attributes[_attrib]; }
@@ -465,6 +465,12 @@ namespace bgfx
 		uint8_t m_attributes[Attrib::Count];
 	};
 
+	/// Pack vec4 into vertex stream format.
+	void vertexPack(const float _input[4], bool _inputNormalized, Attrib::Enum _attr, const VertexDecl& _decl, void* _data, uint32_t _index = 0);
+
+	/// Unpack vec4 from vertex stream format.
+	void vertexUnpack(float _output[4], Attrib::Enum _attr, const VertexDecl& _decl, const void* _data, uint32_t _index = 0);
+
 	/// Returns renderer backend API type.
 	RendererType::Enum getRendererType();
 

+ 2 - 1
src/renderer_d3d11.cpp

@@ -229,7 +229,8 @@ namespace bgfx
 					uint8_t num;
 					AttribType::Enum type;
 					bool normalized;
-					_decl.decode(Attrib::Enum(attr), num, type, normalized);
+					bool asInt;
+					_decl.decode(Attrib::Enum(attr), num, type, normalized, asInt);
 					elem->Format = s_attribType[type][num-1][normalized];
 					elem->AlignedByteOffset = _decl.m_offset[attr];
 				}

+ 2 - 1
src/renderer_d3d9.cpp

@@ -1045,7 +1045,8 @@ namespace bgfx
 				uint8_t num;
 				AttribType::Enum type;
 				bool normalized;
-				_decl.decode(Attrib::Enum(attr), num, type, normalized);
+				bool asInt;
+				_decl.decode(Attrib::Enum(attr), num, type, normalized, asInt);
 
 				memcpy(elem, &s_attrib[attr], sizeof(D3DVERTEXELEMENT9) );
 

+ 2 - 1
src/renderer_gl.cpp

@@ -1269,7 +1269,8 @@ namespace bgfx
 			uint8_t num;
 			AttribType::Enum type;
 			bool normalized;
-			_vertexDecl.decode(attr, num, type, normalized);
+			bool asInt;
+			_vertexDecl.decode(attr, num, type, normalized, asInt);
 
 			if (-1 != loc
 			&&  0xff != _vertexDecl.m_attributes[attr])

+ 227 - 8
src/vertexdecl.cpp

@@ -5,6 +5,7 @@
 
 #include <string.h>
 #include <bx/hash.h>
+#include <bx/uint32_t.h>
 
 #include "vertexdecl.h"
 
@@ -65,23 +66,25 @@ namespace bgfx
 		m_hash = bx::hashMurmur2A(m_attributes, sizeof(m_attributes) );
 	}
 
-	void VertexDecl::add(Attrib::Enum _attrib, uint8_t _num, AttribType::Enum _type, bool _normalized)
+	void VertexDecl::add(Attrib::Enum _attrib, uint8_t _num, AttribType::Enum _type, bool _normalized, bool _asInt)
 	{
-		const uint8_t encoded_norm = (_normalized&1)<<6;
-		const uint8_t encoded_type = (_type&3)<<3;
-		const uint8_t encoded_num = (_num-1)&3;
+		const uint8_t encodedNorm = (_normalized&1)<<6;
+		const uint8_t encodedType = (_type&3)<<3;
+		const uint8_t encodedNum = (_num-1)&3;
+		const uint8_t encodeAsInt = (_asInt&(!!"\x1\x1\x0\x0"[_type]) )<<7;
 
-		m_attributes[_attrib] = encoded_norm|encoded_type|encoded_num;
+		m_attributes[_attrib] = encodedNorm|encodedType|encodedNum|encodeAsInt;
 		m_offset[_attrib] = m_stride;
 		m_stride += (*s_attribTypeSize[m_hash])[_type][_num-1];
 	}
 
-	void VertexDecl::decode(Attrib::Enum _attrib, uint8_t& _num, AttribType::Enum& _type, bool& _normalized) const
+	void VertexDecl::decode(Attrib::Enum _attrib, uint8_t& _num, AttribType::Enum& _type, bool& _normalized, bool& _asInt) const
 	{
 		uint8_t val = m_attributes[_attrib];
 		_num = (val&3)+1;
 		_type = AttribType::Enum((val>>3)&3);
 		_normalized = !!(val&(1<<6) );
+		_asInt = !!(val&(1<<7) );
 	}
 
 	const char* getAttribName(Attrib::Enum _attr)
@@ -123,14 +126,16 @@ namespace bgfx
 				uint8_t num;
 				AttribType::Enum type;
 				bool normalized;
-				_decl.decode(Attrib::Enum(attr), num, type, normalized);
+				bool asInt;
+				_decl.decode(Attrib::Enum(attr), num, type, normalized, asInt);
 
-				BX_TRACE("\tattr %d - %s, num %d, type %d, norm %d, offset %d"
+				BX_TRACE("\tattr %d - %s, num %d, type %d, norm %d, asint %d, offset %d"
 					, attr
 					, getAttribName(Attrib::Enum(attr) )
 					, num
 					, type
 					, normalized
+					, asInt
 					, _decl.m_offset[attr]
 				);
 			}
@@ -140,4 +145,218 @@ namespace bgfx
 #endif // BGFX_CONFIG_DEBUG
 	}
 
+	void vertexPack(const float _input[4], bool _inputNormalized, Attrib::Enum _attr, const VertexDecl& _decl, void* _data, uint32_t _index)
+	{
+		if (!_decl.has(_attr) )
+		{
+			return;
+		}
+
+		uint32_t stride = _decl.getStride();
+		uint8_t* data = (uint8_t*)_data + _index*stride + _decl.getOffset(_attr);
+
+		uint8_t num;
+		AttribType::Enum type;
+		bool normalized;
+		bool asInt;
+		_decl.decode(_attr, num, type, normalized, asInt);
+
+		switch (type)
+		{
+		case AttribType::Uint8:
+			{
+				uint8_t* packed = (uint8_t*)data;
+				if (_inputNormalized)
+				{
+					if (asInt)
+					{
+						switch (num)
+						{
+						default: *packed++ = uint8_t(*_input++ * 127.0f + 128.0f);
+						case 3:  *packed++ = uint8_t(*_input++ * 127.0f + 128.0f);
+						case 2:  *packed++ = uint8_t(*_input++ * 127.0f + 128.0f);
+						case 1:  *packed++ = uint8_t(*_input++ * 127.0f + 128.0f);
+						}
+					}
+					else
+					{
+						switch (num)
+						{
+						default: *packed++ = uint8_t(*_input++ * 255.0f);
+						case 3:  *packed++ = uint8_t(*_input++ * 255.0f);
+						case 2:  *packed++ = uint8_t(*_input++ * 255.0f);
+						case 1:  *packed++ = uint8_t(*_input++ * 255.0f);
+						}
+					}
+				}
+				else
+				{
+					switch (num)
+					{
+					default: *packed++ = uint8_t(*_input++);
+					case 3:  *packed++ = uint8_t(*_input++);
+					case 2:  *packed++ = uint8_t(*_input++);
+					case 1:  *packed++ = uint8_t(*_input++);
+					}
+				}
+			}
+			break;
+
+		case AttribType::Uint16:
+			{
+				uint16_t* packed = (uint16_t*)data;
+				if (_inputNormalized)
+				{
+					if (asInt)
+					{
+						switch (num)
+						{
+						default: *packed++ = uint16_t(*_input++ * 32767.0f + 32768.0f);
+						case 3:  *packed++ = uint16_t(*_input++ * 32767.0f + 32768.0f);
+						case 2:  *packed++ = uint16_t(*_input++ * 32767.0f + 32768.0f);
+						case 1:  *packed++ = uint16_t(*_input++ * 32767.0f + 32768.0f);
+						}
+					}
+					else
+					{
+						switch (num)
+						{
+						default: *packed++ = uint16_t(*_input++ * 65535.0f);
+						case 3:  *packed++ = uint16_t(*_input++ * 65535.0f);
+						case 2:  *packed++ = uint16_t(*_input++ * 65535.0f);
+						case 1:  *packed++ = uint16_t(*_input++ * 65535.0f);
+						}
+					}
+				}
+				else
+				{
+					switch (num)
+					{
+					default: *packed++ = uint16_t(*_input++);
+					case 3:  *packed++ = uint16_t(*_input++);
+					case 2:  *packed++ = uint16_t(*_input++);
+					case 1:  *packed++ = uint16_t(*_input++);
+					}
+				}
+			}
+			break;
+
+		case AttribType::Half:
+			{
+				uint16_t* packed = (uint16_t*)data;
+				switch (num)
+				{
+				default: *packed++ = bx::halfFromFloat(*_input++);
+				case 3:  *packed++ = bx::halfFromFloat(*_input++);
+				case 2:  *packed++ = bx::halfFromFloat(*_input++);
+				case 1:  *packed++ = bx::halfFromFloat(*_input++);
+				}
+			}
+			break;
+
+		case AttribType::Float:
+			memcpy(data, _input, num*sizeof(float) );
+			break;
+		}
+	}
+
+	void vertexUnpack(float _output[4], Attrib::Enum _attr, const VertexDecl& _decl, const void* _data, uint32_t _index)
+	{
+		if (!_decl.has(_attr) )
+		{
+			memset(_output, 0, 4*sizeof(float) );
+			return;
+		}
+
+		uint32_t stride = _decl.getStride();
+		uint8_t* data = (uint8_t*)_data + _index*stride + _decl.getOffset(_attr);
+
+		uint8_t num;
+		AttribType::Enum type;
+		bool normalized;
+		bool asInt;
+		_decl.decode(_attr, num, type, normalized, asInt);
+
+		switch (type)
+		{
+		case AttribType::Uint8:
+			{
+				uint8_t* packed = (uint8_t*)data;
+				if (asInt)
+				{
+					switch (num)
+					{
+					default: *_output++ = (float(*packed++) - 128.0f)*1.0f/127.0f;
+					case 3:  *_output++ = (float(*packed++) - 128.0f)*1.0f/127.0f;
+					case 2:  *_output++ = (float(*packed++) - 128.0f)*1.0f/127.0f;
+					case 1:  *_output++ = (float(*packed++) - 128.0f)*1.0f/127.0f;
+					}
+				}
+				else
+				{
+					switch (num)
+					{
+					default: *_output++ = float(*packed++)*1.0f/255.0f;
+					case 3:  *_output++ = float(*packed++)*1.0f/255.0f;
+					case 2:  *_output++ = float(*packed++)*1.0f/255.0f;
+					case 1:  *_output++ = float(*packed++)*1.0f/255.0f;
+					}
+				}
+			}
+			break;
+
+		case AttribType::Uint16:
+			{
+				uint16_t* packed = (uint16_t*)data;
+				if (asInt)
+				{
+					switch (num)
+					{
+					default: *_output++ = (float(*packed++) - 32768.0f)*1.0f/32767.0f;
+					case 3:  *_output++ = (float(*packed++) - 32768.0f)*1.0f/32767.0f;
+					case 2:  *_output++ = (float(*packed++) - 32768.0f)*1.0f/32767.0f;
+					case 1:  *_output++ = (float(*packed++) - 32768.0f)*1.0f/32767.0f;
+					}
+				}
+				else
+				{
+					switch (num)
+					{
+					default: *_output++ = float(*packed++)*1.0f/65535.0f;
+					case 3:  *_output++ = float(*packed++)*1.0f/65535.0f;
+					case 2:  *_output++ = float(*packed++)*1.0f/65535.0f;
+					case 1:  *_output++ = float(*packed++)*1.0f/65535.0f;
+					}
+				}
+			}
+			break;
+
+		case AttribType::Half:
+			{
+				uint16_t* packed = (uint16_t*)data;
+				switch (num)
+				{
+				default: *_output++ = bx::halfToFloat(*packed++);
+				case 3:  *_output++ = bx::halfToFloat(*packed++);
+				case 2:  *_output++ = bx::halfToFloat(*packed++);
+				case 1:  *_output++ = bx::halfToFloat(*packed++);
+				}
+			}
+			break;
+
+		case AttribType::Float:
+			memcpy(_output, data, num*sizeof(float) );
+			_output += num;
+			break;
+		}
+
+		switch (num)
+		{
+		case 1: *_output++ = 0.0f;
+		case 2: *_output++ = 0.0f;
+		case 3: *_output++ = 0.0f;
+		default: break;
+		}
+	}
+
 } // namespace bgfx

+ 3 - 0
src/vertexdecl.h

@@ -7,7 +7,10 @@
 
 namespace bgfx
 {
+	/// Returns attribute name.
 	const char* getAttribName(Attrib::Enum _attr);
+
+	/// Dump vertex declaration into debug output.
 	void dump(const VertexDecl& _decl);
 
 } // namespace bgfx

+ 51 - 137
tools/geometryc/geometryc.cpp

@@ -133,95 +133,42 @@ void triangleReorder(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVert
 	delete [] newIndexList;
 }
 
-uint32_t packUint32(uint8_t _x, uint8_t _y, uint8_t _z, uint8_t _w)
-{
-	union
-	{
-		uint32_t ui32;
-		uint8_t arr[4];
-	} un;
-
-	un.arr[0] = _x;
-	un.arr[1] = _y;
-	un.arr[2] = _z;
-	un.arr[3] = _w;
-
-	return un.ui32;
-}
-
-void unpackUint32(uint8_t _result[4], uint32_t _packed)
-{
-	union
-	{
-		uint32_t ui32;
-		uint8_t arr[4];
-	} un;
-
-	un.ui32	= _packed;
-	_result[0] = un.arr[0];
-	_result[1] = un.arr[1];
-	_result[2] = un.arr[2];
-	_result[3] = un.arr[3];
-}
-
-uint32_t packF4u(float _x, float _y = 0.0f, float _z = 0.0f, float _w = 0.0f)
-{
-	const uint8_t xx = uint8_t(_x*127.0f + 128.0f);
-	const uint8_t yy = uint8_t(_y*127.0f + 128.0f);
-	const uint8_t zz = uint8_t(_z*127.0f + 128.0f);
-	const uint8_t ww = uint8_t(_w*127.0f + 128.0f);
-	return packUint32(xx, yy, zz, ww);
-}
-
-void unpackF4u(float _result[4], uint32_t _packed)
-{
-	uint8_t unpacked[4];
-	unpackUint32(unpacked, _packed);
-	_result[0] = (float(unpacked[0]) - 128.0f)/127.0f;
-	_result[1] = (float(unpacked[1]) - 128.0f)/127.0f;
-	_result[2] = (float(unpacked[2]) - 128.0f)/127.0f;
-	_result[3] = (float(unpacked[3]) - 128.0f)/127.0f;
-}
-
-uint32_t packF2h(float _x, float _y)
-{
-	union
-	{
-		uint32_t ui32;
-		uint16_t arr[2];
-	} un;
-
-	un.arr[0] = bx::halfFromFloat(_x);
-	un.arr[1] = bx::halfFromFloat(_y);
-
-	return un.ui32;
-}
-
-void unpackF2h(float _result[2], uint32_t _packed)
-{
-	union
-	{
-		uint32_t ui32;
-		uint16_t arr[2];
-	} un;
-
-	un.ui32 = _packed;
-	_result[0] = bx::halfToFloat(un.arr[0]);
-	_result[1] = bx::halfToFloat(un.arr[1]);
-}
-
-template<typename Ty>
-void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices, uint16_t _numVertices)
+void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
 {
+	struct PosTexcoord
+	{
+		float m_x;
+		float m_y;
+		float m_z;
+		float m_pad0;
+		float m_u;
+		float m_v;
+		float m_pad1;
+		float m_pad2;
+	};
+	
 	float* tangents = new float[6*_numVertices];
 	memset(tangents, 0, 6*_numVertices*sizeof(float) );
 
+	PosTexcoord v0;
+	PosTexcoord v1;
+	PosTexcoord v2;
+
 	for (uint32_t ii = 0, num = _numIndices/3; ii < num; ++ii)
 	{
 		const uint16_t* indices = &_indices[ii*3];
-		const Ty& v0 = _vertices[indices[0] ];
-		const Ty& v1 = _vertices[indices[1] ];
-		const Ty& v2 = _vertices[indices[2] ];
+		uint32_t i0 = indices[0];
+		uint32_t i1 = indices[1];
+		uint32_t i2 = indices[2];
+
+		bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _decl, _vertices, i0);
+		bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i0);
+
+		bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _decl, _vertices, i1);
+		bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i1);
+
+		bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _decl, _vertices, i2);
+		bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i2);
 
 		const float bax = v1.m_x - v0.m_x;
 		const float bay = v1.m_y - v0.m_y;
@@ -262,12 +209,11 @@ void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices,
 
 	for (uint32_t ii = 0; ii < _numVertices; ++ii)
 	{
-		Ty& v0 = _vertices[ii];
 		const float* tanu = &tangents[ii*6];
 		const float* tanv = &tangents[ii*6 + 3];
 
 		float normal[4];
-		unpackF4u(normal, v0.m_normal);
+		bgfx::vertexUnpack(normal, bgfx::Attrib::Normal, _decl, _vertices, ii);
 		float ndt = vec3Dot(normal, tanu);
 
 		float nxt[3];
@@ -278,11 +224,11 @@ void calcTangents(const uint16_t* _indices, uint32_t _numIndices, Ty* _vertices,
 		tmp[1] = tanu[1] - normal[1] * ndt;
 		tmp[2] = tanu[2] - normal[2] * ndt;
 
-		float tangent[3];
+		float tangent[4];
 		vec3Norm(tangent, tmp);
 
-		float tw = vec3Dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
-		v0.m_tangent = packF4u(tangent[0], tangent[1], tangent[2], tw);
+		tangent[3] = vec3Dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
+		bgfx::vertexPack(tangent, true, bgfx::Attrib::Tangent, _decl, _vertices, ii);
 	}
 } 
 
@@ -752,6 +698,8 @@ int main(int _argc, const char* _argv[])
 
 	if (hasNormal)
 	{
+		hasTangent &= hasTexcoord;
+
 		switch (packNormal)
 		{
 		default:
@@ -764,10 +712,10 @@ int main(int _argc, const char* _argv[])
 			break;
 
 		case 1:
-			decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true);
+			decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
 			if (hasTangent)
 			{
-				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true);
+				decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
 			}
 			break;
 		}
@@ -828,6 +776,11 @@ int main(int _argc, const char* _argv[])
 				}
 				triReorderElapsed += bx::getHPCounter();
 
+				if (hasTangent)
+				{
+					calcTangents(vertexData, numVertices, decl, indexData, numIndices);
+				}
+
 				write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
 				primitives.clear();
 
@@ -875,58 +828,14 @@ int main(int _argc, const char* _argv[])
 							uv[1] = -uv[1];
 						}
 
-						switch (packUv)
-						{
-						default:
-						case 0:
-							{
-								float* texcoord0 = (float*)(vertices + texcoord0Offset);
-								memcpy(texcoord0, uv, 2*sizeof(float) );
-							}
-							break;
-
-						case 1:
-							{
-								uint32_t* texcoord0 = (uint32_t*)(vertices + texcoord0Offset);
-								*texcoord0 = packF2h(uv[0], uv[1]);
-							}
-							break;
-						}
+						bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
 					}
 
 					if (hasNormal)
 					{
-						switch (packNormal)
-						{
-						default:
-						case 0:
-							{
-								float* normal = (float*)(vertices + normalOffset);
-								vec3Norm(normal, (float*)&normals[index.m_normal]);
-
-								if (hasTangent)
-								{
-									float* tangent = (float*)(vertices + tangentOffset);
-									memset(tangent, 0, 3*sizeof(float) );
-								}
-							}
-							break;
-
-						case 1:
-							{
-								float normal[3];
-								vec3Norm(normal, (float*)&normals[index.m_normal]);
-								uint32_t* nxyz0 = (uint32_t*)(vertices + normalOffset);
-								*nxyz0 = packF4u(normal[0], normal[1], normal[2]);
-
-								if (hasTangent)
-								{
-									uint32_t* txyz0 = (uint32_t*)(vertices + tangentOffset);
-									*txyz0 = packF4u(0.0f);
-								}
-							}
-							break;
-						}
+						float normal[4];
+						vec3Norm(normal, (float*)&normals[index.m_normal]);
+						bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
 					}
 
 					vertices += stride;
@@ -965,6 +874,11 @@ int main(int _argc, const char* _argv[])
 		}
 		triReorderElapsed += bx::getHPCounter();
 
+		if (hasTangent)
+		{
+			calcTangents(vertexData, numVertices, decl, indexData, numIndices);
+		}
+
 		write(&writer, vertexData, numVertices, decl, indexData, numIndices, material, primitives);
 	}