221 lines
5.4 KiB
C++
221 lines
5.4 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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 <Vector4> &, 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 <index_count; ++n)
|
|
idx_map[(int)n] = (ushort)trilist->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;
|
|
}
|
|
//------------------------------------------------------------------------------
|