/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "gpu/gpu_display_list.h" #include "gpu/gpu_renderer.h" #include "core/triangle_list.h" #include "log/log.h" #define __USE_VBO__ 1 using namespace GS::GPU; namespace GS { namespace Core { bool ComputeVertexArrayMinMax(const Array &, MinMax &, const Matrix4 * = 0); } } //------------------------------------------------------------------------------ bool DisplayList::Create(GS::Core::Trilist *trilist, GS::Render::Material *list_material) { // Setup skin data. bone.Clone(trilist->bone); // Setup triangle list indices. index_count = trilist->idx.GetCount(); #if __USE_VBO__ if (!idx) idx = renderer.NewVBO(); if (!idx || !idx->Create(index_count * sizeof(ushort), VBO::Index, VBO::Static)) return false; #endif if (!idx_map.Allocate(index_count)) return false; for (size_t n = 0; n idx[(int)n]; #if __USE_VBO__ idx->Update(idx_map, 0, idx_map.GetSize()); idx_map.Free(); #endif // Setup triangle list vertex. stride = 0; // Vertex offset. vertex_offset = stride; stride += 3 * sizeof(hfloat); // Compute normal stream size. if (trilist->nrm) { normal_offset = stride; stride += 4 * sizeof(char); } // Compute RGB stream size. if (trilist->rgb) { rgb_offset = stride; stride += 4 * sizeof(char); } // Compute UV stream size. for (int s = 0; s < __UV_PER_GEOMETRY__; ++s) if (trilist->uv[s]) { uv_offset[s] = stride; stride += 2 * sizeof(hfloat); } // Compute tangent stream size. if (trilist->tangent) { tangent_offset = stride; stride += 4 * 2 * sizeof(char); } // Compute skinning stream size. if (trilist->skin) { skinning_offset = stride; stride += 4 * 2 * sizeof(uchar); } #define __GPU_PADSIZE 4 // Compute vertex padding. int padding = 0; padding = stride % __GPU_PADSIZE ? __GPU_PADSIZE - (stride % __GPU_PADSIZE) : 0; if (padding) __LOG__ << "Padding GPU vertex to " << __GPU_PADSIZE << "B by " << padding << "B (from " << (uint)stride << "B)\n"; stride += padding; // Setup attribute streams. size_t vtx_stream_size = stride * size_t(trilist->vtx.GetCount()); #if __USE_VBO__ if (!vtx) vtx = renderer.NewVBO(); if (!vtx || !vtx->Create(vtx_stream_size, VBO::Vertex, VBO::Static)) return false; #endif if (!vtx_map.Allocate(vtx_stream_size)) return false; char *p_stream = (char *)vtx_map.c_ptr(); for (uint n = 0; n < trilist->vtx.GetCount(); ++n) { // Output vertex stream. hfloat *p_vtx = (hfloat *)p_stream; p_vtx[0] = Types::FloatToHFloat(trilist->vtx[n].x); p_vtx[1] = Types::FloatToHFloat(trilist->vtx[n].y); p_vtx[2] = Types::FloatToHFloat(trilist->vtx[n].z); p_stream += 3 * sizeof(hfloat); // Output normal stream. if (trilist->nrm) { schar *p_nrm = (schar *)p_stream; p_nrm[0] = (schar)(trilist->nrm[n].x * 127.f); p_nrm[1] = (schar)(trilist->nrm[n].y * 127.f); p_nrm[2] = (schar)(trilist->nrm[n].z * 127.f); p_stream += 4 * sizeof(schar); } // Output RGB stream. if (trilist->rgb) { uchar *p_rgb = (uchar *)p_stream; p_rgb[0] = uchar(trilist->rgb[n].x * 255.f); p_rgb[1] = uchar(trilist->rgb[n].y * 255.f); p_rgb[2] = uchar(trilist->rgb[n].z * 255.f); p_rgb[3] = uchar(trilist->rgb[n].w * 255.f); p_stream += 4 * sizeof(uchar); } // Output UV streams. for (uint s = 0; s < __UV_PER_GEOMETRY__; ++s) if (trilist->uv[s]) { hfloat *p_uv = (hfloat *)p_stream; p_uv[0] = Types::FloatToHFloat(trilist->uv[s][n].x); p_uv[1] = Types::FloatToHFloat(trilist->uv[s][n].y); p_stream += 2 * sizeof(hfloat); } // Output tangent stream. if (trilist->tangent) { schar *p_tng = (schar *)p_stream; p_tng[0] = schar(trilist->tangent[n].T.x * 127.f); p_tng[1] = schar(trilist->tangent[n].T.y * 127.f); p_tng[2] = schar(trilist->tangent[n].T.z * 127.f); // Mind the gap! p_tng[4] = schar(trilist->tangent[n].B.x * 127.f); p_tng[5] = schar(trilist->tangent[n].B.y * 127.f); p_tng[6] = schar(trilist->tangent[n].B.z * 127.f); p_stream += 4 * 2 * sizeof(schar); } // Output skinning stream. if (trilist->skin) { uchar *p_skn = (uchar *)p_stream; p_skn[0] = uchar(trilist->skin[n].bone_index[0]); p_skn[1] = uchar(trilist->skin[n].bone_index[1]); p_skn[2] = uchar(trilist->skin[n].bone_index[2]); p_skn[3] = uchar(trilist->skin[n].bone_index[3]); p_skn[4] = uchar(trilist->skin[n].w[0] * 255.f); p_skn[5] = uchar(trilist->skin[n].w[1] * 255.f); p_skn[6] = uchar(trilist->skin[n].w[2] * 255.f); p_skn[7] = uchar(trilist->skin[n].w[3] * 255.f); p_stream += 4 * 2 * sizeof(uchar); } p_stream += padding; } #if __USE_VBO__ vtx->Update(vtx_map, 0, vtx_map.GetSize()); vtx_map.Free(); #else p_stream = (char *)vtx_map.c_ptr(); #define OffsetToAdress(_Offset) \ if (_Offset != -1) _Offset += (size_t)p_stream; OffsetToAdress(vertex_offset) OffsetToAdress(normal_offset) OffsetToAdress(rgb_offset) for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n) OffsetToAdress(uv_offset[n]) OffsetToAdress(tangent_offset) OffsetToAdress(skinning_offset) #endif Core::ComputeVertexArrayMinMax(trilist->vtx, minmax); material = list_material; return true; } //------------------------------------------------------------------------------