| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2009 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:29:41 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "VideoBackends/Software/SWVertexLoader.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 10:25:05 -06:00
										 |  |  | #include <limits>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/Assert.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoBackends/Software/DebugUtil.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-21 02:01:38 -04:00
										 |  |  | #include "VideoBackends/Software/NativeVertexFormat.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoBackends/Software/Rasterizer.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Software/Tev.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "VideoBackends/Software/TransformUnit.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-31 14:51:55 -05:00
										 |  |  | #include "VideoCommon/DataReader.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoCommon/IndexGenerator.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/OpcodeDecoding.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/PixelShaderManager.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/Statistics.h"
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:51:14 +01:00
										 |  |  | #include "VideoCommon/VertexLoaderBase.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-30 00:42:45 +12:00
										 |  |  | #include "VideoCommon/VertexLoaderManager.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-17 16:54:31 -05:00
										 |  |  | #include "VideoCommon/VideoConfig.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoCommon/XFMemory.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | class NullNativeVertexFormat : public NativeVertexFormat | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; } | 
					
						
							|  |  |  |   void SetupVertexPointers() override {} | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 03:14:30 -05:00
										 |  |  | std::unique_ptr<NativeVertexFormat> | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-02-18 03:14:30 -05:00
										 |  |  |   return std::make_unique<NullNativeVertexFormat>(vtx_decl); | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-30 00:42:45 +12:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 12:05:10 -04:00
										 |  |  | SWVertexLoader::SWVertexLoader() : LocalVBuffer(MAXVBUFFERSIZE), LocalIBuffer(MAXIBUFFERSIZE) | 
					
						
							| 
									
										
										
										
											2014-07-29 20:55:07 -04:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 19:55:30 +00:00
										 |  |  | SWVertexLoader::~SWVertexLoader() | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | void SWVertexLoader::ResetBuffer(u32 stride) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-21 23:46:52 -04:00
										 |  |  |   m_cur_buffer_pointer = m_base_buffer_pointer = LocalVBuffer.data(); | 
					
						
							|  |  |  |   m_end_buffer_pointer = m_cur_buffer_pointer + LocalVBuffer.size(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   IndexGenerator::Start(GetIndexBuffer()); | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-05 12:18:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-28 01:37:41 +01:00
										 |  |  | void SWVertexLoader::vFlush() | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   DebugUtil::OnObjectBegin(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u8 primitiveType = 0; | 
					
						
							| 
									
										
										
										
											2016-08-21 23:46:52 -04:00
										 |  |  |   switch (m_current_primitive_type) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |   case PRIMITIVE_POINTS: | 
					
						
							| 
									
										
										
										
											2017-02-07 23:11:04 -05:00
										 |  |  |     primitiveType = OpcodeDecoder::GX_DRAW_POINTS; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case PRIMITIVE_LINES: | 
					
						
							| 
									
										
										
										
											2017-02-07 23:11:04 -05:00
										 |  |  |     primitiveType = OpcodeDecoder::GX_DRAW_LINES; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case PRIMITIVE_TRIANGLES: | 
					
						
							| 
									
										
										
										
											2017-02-07 23:11:04 -05:00
										 |  |  |     primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? | 
					
						
							|  |  |  |                         OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP : | 
					
						
							|  |  |  |                         OpcodeDecoder::GX_DRAW_TRIANGLES; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 12:05:10 -04:00
										 |  |  |   m_SetupUnit.Init(primitiveType); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // set all states with are stored within video sw
 | 
					
						
							|  |  |  |   for (int i = 0; i < 4; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Rasterizer::SetTevReg(i, Tev::RED_C, PixelShaderManager::constants.kcolors[i][0]); | 
					
						
							|  |  |  |     Rasterizer::SetTevReg(i, Tev::GRN_C, PixelShaderManager::constants.kcolors[i][1]); | 
					
						
							|  |  |  |     Rasterizer::SetTevReg(i, Tev::BLU_C, PixelShaderManager::constants.kcolors[i][2]); | 
					
						
							|  |  |  |     Rasterizer::SetTevReg(i, Tev::ALP_C, PixelShaderManager::constants.kcolors[i][3]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u16 index = LocalIBuffer[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (index == 0xffff) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // primitive restart
 | 
					
						
							| 
									
										
										
										
											2016-09-18 12:05:10 -04:00
										 |  |  |       m_SetupUnit.Init(primitiveType); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     memset(&m_Vertex, 0, sizeof(m_Vertex)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Super Mario Sunshine requires those to be zero for those debug boxes.
 | 
					
						
							|  |  |  |     memset(&m_Vertex.color, 0, sizeof(m_Vertex.color)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // parse the videocommon format to our own struct format (m_Vertex)
 | 
					
						
							|  |  |  |     SetFormat(g_main_cp_state.last_id, primitiveType); | 
					
						
							|  |  |  |     ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // transform this vertex so that it can be used for rasterization (outVertex)
 | 
					
						
							| 
									
										
										
										
											2016-09-18 12:05:10 -04:00
										 |  |  |     OutputVertexData* outVertex = m_SetupUnit.GetVertex(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     TransformUnit::TransformPosition(&m_Vertex, outVertex); | 
					
						
							|  |  |  |     memset(&outVertex->normal, 0, sizeof(outVertex->normal)); | 
					
						
							|  |  |  |     if (VertexLoaderManager::g_current_components & VB_HAS_NRM0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       TransformUnit::TransformNormal( | 
					
						
							|  |  |  |           &m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     TransformUnit::TransformColor(&m_Vertex, outVertex); | 
					
						
							|  |  |  |     TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // assemble and rasterize the primitive
 | 
					
						
							| 
									
										
										
										
											2016-09-18 12:05:10 -04:00
										 |  |  |     m_SetupUnit.SetupVertex(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     INCSTAT(stats.thisFrame.numVerticesLoaded) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DebugUtil::OnObjectEnd(); | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // matrix index from xf regs or cp memory?
 | 
					
						
							|  |  |  |   if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexA.Tex1MtxIdx != g_main_cp_state.matrix_index_a.Tex1MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexA.Tex2MtxIdx != g_main_cp_state.matrix_index_a.Tex2MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexA.Tex3MtxIdx != g_main_cp_state.matrix_index_a.Tex3MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexB.Tex4MtxIdx != g_main_cp_state.matrix_index_b.Tex4MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexB.Tex5MtxIdx != g_main_cp_state.matrix_index_b.Tex5MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexB.Tex6MtxIdx != g_main_cp_state.matrix_index_b.Tex6MtxIdx || | 
					
						
							|  |  |  |       xfmem.MatrixIndexB.Tex7MtxIdx != g_main_cp_state.matrix_index_b.Tex7MtxIdx) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ERROR_LOG(VIDEO, "Matrix indices don't match"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   m_Vertex.posMtx = xfmem.MatrixIndexA.PosNormalMtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[0] = xfmem.MatrixIndexA.Tex0MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[1] = xfmem.MatrixIndexA.Tex1MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[2] = xfmem.MatrixIndexA.Tex2MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[3] = xfmem.MatrixIndexA.Tex3MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[4] = xfmem.MatrixIndexB.Tex4MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[5] = xfmem.MatrixIndexB.Tex5MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[6] = xfmem.MatrixIndexB.Tex6MtxIdx; | 
					
						
							|  |  |  |   m_Vertex.texMtx[7] = xfmem.MatrixIndexB.Tex7MtxIdx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // special case if only pos and tex coord 0 and tex coord input is AB11
 | 
					
						
							|  |  |  |   // http://libogc.devkitpro.org/gx_8h.html#a55a426a3ff796db584302bddd829f002
 | 
					
						
							|  |  |  |   m_TexGenSpecialCase = VertexLoaderManager::g_current_components == VB_HAS_UV0 && | 
					
						
							|  |  |  |                         xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST; | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T, typename I> | 
					
						
							|  |  |  | static T ReadNormalized(I value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   T casted = (T)value; | 
					
						
							|  |  |  |   if (!std::numeric_limits<T>::is_integer && std::numeric_limits<I>::is_integer) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // normalize if non-float is converted to a float
 | 
					
						
							|  |  |  |     casted *= (T)(1.0 / std::numeric_limits<I>::max()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return casted; | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | template <typename T, bool swap = false> | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& format, | 
					
						
							|  |  |  |                                 int base_component, int components, bool reverse) | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (format.enable) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     src.Skip(format.offset); | 
					
						
							|  |  |  |     src.Skip(base_component * (1 << (format.type >> 1))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     for (i = 0; i < std::min(format.components - base_component, components); i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       int i_dst = reverse ? components - i - 1 : i; | 
					
						
							|  |  |  |       switch (format.type) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       case VAR_UNSIGNED_BYTE: | 
					
						
							|  |  |  |         dst[i_dst] = ReadNormalized<T, u8>(src.Read<u8, swap>()); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case VAR_BYTE: | 
					
						
							|  |  |  |         dst[i_dst] = ReadNormalized<T, s8>(src.Read<s8, swap>()); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case VAR_UNSIGNED_SHORT: | 
					
						
							|  |  |  |         dst[i_dst] = ReadNormalized<T, u16>(src.Read<u16, swap>()); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case VAR_SHORT: | 
					
						
							|  |  |  |         dst[i_dst] = ReadNormalized<T, s16>(src.Read<s16, swap>()); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case VAR_FLOAT: | 
					
						
							|  |  |  |         dst[i_dst] = ReadNormalized<T, float>(src.Read<float, swap>()); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       _assert_msg_(VIDEO, !format.integer || format.type != VAR_FLOAT, | 
					
						
							|  |  |  |                    "only non-float values are allowed to be streamed as integer"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (; i < components; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       int i_dst = reverse ? components - i - 1 : i; | 
					
						
							|  |  |  |       dst[i_dst] = i == 3; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index) | 
					
						
							| 
									
										
										
										
											2014-12-07 21:51:45 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size()); | 
					
						
							|  |  |  |   src.Skip(index * vdec.stride); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ReadVertexAttribute<float>(&m_Vertex.position[0], src, vdec.position, 0, 3, false); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < 3; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ReadVertexAttribute<float>(&m_Vertex.normal[i][0], src, vdec.normals[i], 0, 3, false); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < 2; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ReadVertexAttribute<u8>(m_Vertex.color[i], src, vdec.colors[i], 0, 4, true); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < 8; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ReadVertexAttribute<float>(m_Vertex.texCoords[i], src, vdec.texcoords[i], 0, 2, false); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     // the texmtr is stored as third component of the texCoord
 | 
					
						
							|  |  |  |     if (vdec.texcoords[i].components >= 3) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ReadVertexAttribute<u8>(&m_Vertex.texMtx[i], src, vdec.texcoords[i], 2, 1, false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ReadVertexAttribute<u8>(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } |