diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index a7b25e26..b894f3d3 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -73,144 +73,329 @@ void EasyMesh::CloseBrace() } //----------------------------------------------------------------------------- -void EasyMesh::MeshConvert(Shader* provided_shader) +GpuShaderData::GpuShaderData() { - for (int i = 0; i < DebugRenderMode::Max; i++) - { - if (i == DebugRenderMode::Default) - { - if(provided_shader == NULL) - m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shiny)); - else - m_gpu.shader << provided_shader; - } - else if (i == DebugRenderMode::Wireframe) - m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugwireframe)); - else if (i == DebugRenderMode::Lighting) - m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebuglighting)); - else if (i == DebugRenderMode::Normal) - m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugnormal)); - else if (i == DebugRenderMode::UV) - m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV)); - - m_gpu.modelview << m_gpu.shader.Last()->GetUniformLocation("in_ModelView"); - m_gpu.invmodelview << m_gpu.shader.Last()->GetUniformLocation("in_Inv_ModelView"); - m_gpu.view << m_gpu.shader.Last()->GetUniformLocation("in_View"); - m_gpu.invview << m_gpu.shader.Last()->GetUniformLocation("in_Inv_View"); - m_gpu.proj << m_gpu.shader.Last()->GetUniformLocation("in_Proj"); - m_gpu.normalmat << m_gpu.shader.Last()->GetUniformLocation("in_NormalMat"); - m_gpu.damage << m_gpu.shader.Last()->GetUniformLocation("in_Damage"); - m_gpu.lights << m_gpu.shader.Last()->GetUniformLocation("u_Lights"); - m_gpu.coord << m_gpu.shader.Last()->GetAttribLocation("in_Vertex", - VertexUsage::Position, 0); - m_gpu.norm << m_gpu.shader.Last()->GetAttribLocation("in_Normal", - VertexUsage::Normal, 0); - m_gpu.color << m_gpu.shader.Last()->GetAttribLocation("in_Color", - VertexUsage::Color, 0); -#if VERTEX_USEAGE == VU_BONES - //TODO : -- BONE SUPPORT -- -#elif VERTEX_USEAGE == VU_TEX_UV - //UV SUPPORT -- - m_gpu.tex_coord << m_gpu.shader.Last()->GetAttribLocation("in_TexCoord", - VertexUsage::TexCoord, 0); -#endif - } + m_render_mode = DebugRenderMode::Default; +} + +//----------------------------------------------------------------------------- +GpuShaderData::GpuShaderData(uint16_t vert_decl_flags, Shader* shader, DebugRenderMode render_mode) +{ + m_render_mode = render_mode; + m_shader = shader; + m_vert_decl_flags = vert_decl_flags; +} -#if VERTEX_USEAGE == VU_BONES - //TODO : -- BONE SUPPORT -- -#elif VERTEX_USEAGE == VU_TEX_UV - //UV SUPPORT -- - m_gpu.vdecl = new VertexDeclaration( - VertexStream(VertexUsage::Position, - VertexUsage::Normal, - VertexUsage::Color, - VertexUsage::TexCoord)); - - Array vertexlist; - for (int i = 0; i < m_vert.Count(); i++) - vertexlist.Push(m_vert[i].m1, - m_vert[i].m2, - (u8vec4)(m_vert[i].m3 * 255.f), - m_vert[i].m4); -#else - //-- VANILLA -- - m_gpu.vdecl = new VertexDeclaration( - VertexStream(VertexUsage::Position, - VertexUsage::Normal, - VertexUsage::Color)); +//----------------------------------------------------------------------------- +GpuShaderData::~GpuShaderData() +{ + m_shader_uniform.Empty(); + m_shader_attrib.Empty(); +} - Array vertexlist; - for (int i = 0; i < m_vert.Count(); i++) - vertexlist.Push(m_vert[i].m1, - m_vert[i].m2, - (u8vec4)(m_vert[i].m3 * 255.f)); -#endif +//----------------------------------------------------------------------------- +void GpuShaderData::AddUniform(const lol::String &new_uniform) +{ + m_shader_uniform.Push(new_uniform, m_shader->GetUniformLocation(new_uniform.C())); +} - Array indexlist; - for (int i = 0; i < m_indices.Count(); i += 3) - { - indexlist << m_indices[i + 0]; - indexlist << m_indices[i + 1]; - indexlist << m_indices[i + 2]; - } +//----------------------------------------------------------------------------- +void GpuShaderData::AddAttribute(const lol::String &new_attribute, VertexUsage usage, int index) +{ + m_shader_attrib.Push(new_attribute, m_shader->GetAttribLocation(new_attribute.C(), usage, index)); +} - m_gpu.vbo = new VertexBuffer(vertexlist.Bytes()); - void *mesh = m_gpu.vbo->Lock(0, 0); - memcpy(mesh, &vertexlist[0], vertexlist.Bytes()); - m_gpu.vbo->Unlock(); +//----------------------------------------------------------------------------- +ShaderUniform const *GpuShaderData::GetUniform(const lol::String &uniform) +{ + for (int i = 0; i < m_shader_uniform.Count(); ++i) + if (m_shader_uniform[i].m1 == uniform) + return &m_shader_uniform[i].m2; + return NULL; +} + +//----------------------------------------------------------------------------- +ShaderAttrib const *GpuShaderData::GetAttribute(const lol::String &attribute) +{ + for (int i = 0; i < m_shader_attrib.Count(); ++i) + if (m_shader_attrib[i].m1 == attribute) + return &m_shader_attrib[i].m2; + return NULL; +} - m_gpu.ibo = new IndexBuffer(indexlist.Bytes()); - void *indices = m_gpu.ibo->Lock(0, 0); - memcpy(indices, &indexlist[0], indexlist.Bytes()); - m_gpu.ibo->Unlock(); +//----------------------------------------------------------------------------- +DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode) +{ + bool with_UV = false; + m_render_mode = render_mode; + m_vert_decl_flags = (VertexUsage::Position << 1) | + (VertexUsage::Normal << 1) | + (VertexUsage::Color << 1); + + if (render_mode == DebugRenderMode::Default) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny)); + else if (render_mode == DebugRenderMode::Wireframe) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugwireframe)); + else if (render_mode == DebugRenderMode::Lighting) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebuglighting)); + else if (render_mode == DebugRenderMode::Normal) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugnormal)); + else if (render_mode == DebugRenderMode::UV) + { + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV)); + m_vert_decl_flags |= (VertexUsage::TexCoord << 1); + with_UV = true; + } + SetupDefaultData(with_UV); +} - m_gpu.vertexcount = vertexlist.Count(); - m_gpu.indexcount = indexlist.Count(); +//----------------------------------------------------------------------------- +DefaultShaderData::DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV) + : GpuShaderData(vert_decl_flags, shader, DebugRenderMode::Default) +{ + SetupDefaultData(with_UV); } //----------------------------------------------------------------------------- -void EasyMesh::Render(mat4 const &model, float damage) +void DefaultShaderData::SetupDefaultData(bool with_UV) { - DebugRenderMode d = Video::GetDebugRenderMode(); + AddUniform("in_ModelView"); + AddUniform("in_Inv_ModelView"); + AddUniform("in_View"); + AddUniform("in_Inv_View"); + AddUniform("in_Proj"); + AddUniform("in_NormalMat"); + AddUniform("in_Damage"); + AddUniform("u_Lights"); + AddAttribute("in_Vertex", VertexUsage::Position, 0); + AddAttribute("in_Normal", VertexUsage::Normal, 0); + AddAttribute("in_Color", VertexUsage::Color, 0); + if (with_UV) + AddAttribute("in_TexCoord", VertexUsage::TexCoord, 0); +} +//----------------------------------------------------------------------------- +void DefaultShaderData::SetupShaderDatas(mat4 const &model) +{ mat4 modelview = Scene::GetDefault()->GetViewMatrix() * model; mat3 normalmat = transpose(inverse(mat3(modelview))); - m_gpu.shader[d]->Bind(); - /* FIXME: this should be hidden in the shader */ /* FIXME: the 4th component of the position can be used for other things */ + /* FIXME: GetUniform("blabla") is costly */ Array const lights = Scene::GetDefault()->GetLights(); Array light_data; for (int i = 0; i < lights.Count(); ++i) light_data << lights[i]->GetPosition() << lights[i]->GetColor(); while (light_data.Count() < 8) light_data << vec4(0.f) << vec4(0.f); - m_gpu.shader[d]->SetUniform(m_gpu.lights[d], light_data); - - m_gpu.shader[d]->SetUniform(m_gpu.modelview[d], modelview); - m_gpu.shader[d]->SetUniform(m_gpu.invmodelview[d], inverse(modelview)); - m_gpu.shader[d]->SetUniform(m_gpu.view[d], Scene::GetDefault()->GetViewMatrix()); - m_gpu.shader[d]->SetUniform(m_gpu.invview[d], inverse(Scene::GetDefault()->GetViewMatrix())); - m_gpu.shader[d]->SetUniform(m_gpu.proj[d], Scene::GetDefault()->GetProjMatrix()); - m_gpu.shader[d]->SetUniform(m_gpu.normalmat[d], normalmat); - m_gpu.shader[d]->SetUniform(m_gpu.damage[d], damage); - m_gpu.vdecl->Bind(); -#if VERTEX_USEAGE == VU_BONES - //TODO : -- BONE SUPPORT -- -#elif VERTEX_USEAGE == VU_TEX_UV - //UV SUPPORT -- - m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord[d], m_gpu.norm[d], m_gpu.color[d], m_gpu.tex_coord[d]); -#else - //-- VANILLA -- - m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord[d], m_gpu.norm[d], m_gpu.color[d]); -#endif - m_gpu.ibo->Bind(); - m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles, - 0, 0, m_gpu.vertexcount, - 0, m_gpu.indexcount); - m_gpu.ibo->Unbind(); - m_gpu.vdecl->Unbind(); + m_shader->SetUniform(*GetUniform("u_Lights"), light_data); + + m_shader->SetUniform(*GetUniform("in_ModelView"), modelview); + m_shader->SetUniform(*GetUniform("in_Inv_ModelView"), inverse(modelview)); + m_shader->SetUniform(*GetUniform("in_View"), Scene::GetDefault()->GetViewMatrix()); + m_shader->SetUniform(*GetUniform("in_Inv_View"), inverse(Scene::GetDefault()->GetViewMatrix())); + m_shader->SetUniform(*GetUniform("in_Proj"), Scene::GetDefault()->GetProjMatrix()); + m_shader->SetUniform(*GetUniform("in_NormalMat"), normalmat); + m_shader->SetUniform(*GetUniform("in_Damage"), 0); +} + +//----------------------------------------------------------------------------- +GpuEasyMeshData::GpuEasyMeshData() +{ + m_vertexcount = 0; + m_indexcount = 0; + m_ibo = NULL; +} + +//----------------------------------------------------------------------------- +GpuEasyMeshData::~GpuEasyMeshData() +{ + m_gpudatas.Empty(); + m_vdatas.Empty(); + if (m_ibo) + delete(m_ibo); +} + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::AddGpuData(GpuShaderData* gpudata, EasyMesh* src_mesh) +{ + SetupVertexData(gpudata->m_vert_decl_flags, src_mesh); + + if (!m_ibo) + { + Array indexlist; + for (int i = 0; i < src_mesh->m_indices.Count(); i += 3) + { + indexlist << src_mesh->m_indices[i + 0]; + indexlist << src_mesh->m_indices[i + 1]; + indexlist << src_mesh->m_indices[i + 2]; + } + + m_ibo = new IndexBuffer(indexlist.Bytes()); + void *indices = m_ibo->Lock(0, 0); + memcpy(indices, &indexlist[0], indexlist.Bytes()); + m_ibo->Unlock(); + + m_indexcount = indexlist.Count(); + } + + if (m_gpudatas.Count() != DebugRenderMode::Max) + { + m_gpudatas.Reserve(DebugRenderMode::Max); + for (int i = 0; i < DebugRenderMode::Max; i++) + m_gpudatas << NULL; + } + m_gpudatas[gpudata->m_render_mode] = gpudata; +} + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::SetupVertexData(uint16_t vdecl_flags, EasyMesh* src_mesh) +{ + for (int i = 0; i < m_vdatas.Count(); ++i) + if (m_vdatas[i].m1 == vdecl_flags) + return; + + VertexDeclaration* new_vdecl = NULL; + VertexBuffer* new_vbo = NULL; + void *vbo_data = NULL; + int vbo_bytes = 0; + +#define COPY_VBO \ + new_vbo = new VertexBuffer(vbo_bytes); \ + void *mesh = new_vbo->Lock(0, 0); \ + memcpy(mesh, vbo_data, vbo_bytes); \ + new_vbo->Unlock(); + + if (vdecl_flags == ((VertexUsage::Position<<1) | + (VertexUsage::Normal<<1) | + (VertexUsage::Color<<1) | + (VertexUsage::TexCoord<<1))) + { + new_vdecl = new VertexDeclaration( + VertexStream( + VertexUsage::Position, + VertexUsage::Normal, + VertexUsage::Color, + VertexUsage::TexCoord)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m1, + src_mesh->m_vert[i].m2, + (u8vec4)(src_mesh->m_vert[i].m3 * 255.f), + src_mesh->m_vert[i].m4); + + vbo_data = &vertexlist[0]; + vbo_bytes = vertexlist.Bytes(); + m_vertexcount = vertexlist.Count(); + + COPY_VBO; + } + else if (vdecl_flags == ((VertexUsage::Position<<1) | + (VertexUsage::Normal<<1) | + (VertexUsage::Color<<1))) + { + new_vdecl = new VertexDeclaration( + VertexStream( + VertexUsage::Position, + VertexUsage::Normal, + VertexUsage::Color)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m1, + src_mesh->m_vert[i].m2, + (u8vec4)(src_mesh->m_vert[i].m3 * 255.f)); + + vbo_data = &vertexlist[0]; + vbo_bytes = vertexlist.Bytes(); + m_vertexcount = vertexlist.Count(); + + COPY_VBO; + } + + m_vdatas.Push(vdecl_flags, new_vdecl, new_vbo); +} + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::RenderMeshData(mat4 const &model) +{ + DebugRenderMode d = Video::GetDebugRenderMode(); + GpuShaderData& gpu_sd = *(m_gpudatas[d]); + + int vdecl_idx = 0; + for (; vdecl_idx < m_vdatas.Count(); ++vdecl_idx) + if (m_vdatas[vdecl_idx].m1 == gpu_sd.m_vert_decl_flags) + break; + + if (vdecl_idx >= m_vdatas.Count()) + return; + + uint16_t vflags = m_vdatas[vdecl_idx].m1; + VertexDeclaration* vdecl = m_vdatas[vdecl_idx].m2; + VertexBuffer* vbo = m_vdatas[vdecl_idx].m3; + + gpu_sd.m_shader->Bind(); + gpu_sd.SetupShaderDatas(model); + + vdecl->Bind(); + + if (vflags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | + (VertexUsage::Color<<1) | (VertexUsage::TexCoord<<1))) + { + vdecl->SetStream(vbo, *gpu_sd.GetAttribute(lol::String("in_Vertex")), + *gpu_sd.GetAttribute(lol::String("in_Normal")), + *gpu_sd.GetAttribute(lol::String("in_Color")), + *gpu_sd.GetAttribute(lol::String("in_TexCoord"))); + } + else if (vflags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | + (VertexUsage::Color<<1))) + { + vdecl->SetStream(vbo, *gpu_sd.GetAttribute(lol::String("in_Vertex")), + *gpu_sd.GetAttribute(lol::String("in_Normal")), + *gpu_sd.GetAttribute(lol::String("in_Color"))); + } + + m_ibo->Bind(); + vdecl->DrawIndexedElements(MeshPrimitive::Triangles, 0, 0, m_vertexcount, 0, m_indexcount); + m_ibo->Unbind(); + vdecl->Unbind(); +} + +//----------------------------------------------------------------------------- +void EasyMesh::MeshConvert(GpuShaderData* new_gpu_sdata) +{ + if (new_gpu_sdata) + { + m_gpu_data.AddGpuData(new_gpu_sdata, this); + for (int i = DebugRenderMode::Default + 1; i < DebugRenderMode::Max; i++) + m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode(i)), this); + } +} + +//----------------------------------------------------------------------------- +void EasyMesh::MeshConvert(Shader* provided_shader) +{ + if (provided_shader) + { + GpuShaderData *new_gpu_sdata = new DefaultShaderData(((VertexUsage::Position<<1) | + (VertexUsage::Normal<<1) | + (VertexUsage::Color<<1)), + provided_shader, + false); + m_gpu_data.AddGpuData(new_gpu_sdata, this); + } + else + m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode::Default), this); + for (int i = DebugRenderMode::Default + 1; i < DebugRenderMode::Max; i++) + m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode(i)), this); +} + +//----------------------------------------------------------------------------- +void EasyMesh::Render(mat4 const &model, float damage) +{ + m_gpu_data.RenderMeshData(model); } //------------------- diff --git a/src/easymesh/easymesh.h b/src/easymesh/easymesh.h index 0e64dea4..946c6a87 100644 --- a/src/easymesh/easymesh.h +++ b/src/easymesh/easymesh.h @@ -19,7 +19,7 @@ #define VU_TEX_UV 1 #define VU_VANILLA 0 -#define VERTEX_USEAGE VU_VANILLA +#define VERTEX_USEAGE VU_TEX_UV #if !defined __EASYMESH_EASYMESH_H__ #define __EASYMESH_EASYMESH_H__ @@ -27,6 +27,68 @@ namespace lol { +//----------------------------------------------------------------------------- +//Base class to declare shader datas +class GpuShaderData +{ + friend class GpuEasyMeshData; + +protected: + GpuShaderData(); +public: + //-- + GpuShaderData(uint16_t vert_decl_flags, Shader* shader, DebugRenderMode render_mode); + ~GpuShaderData(); + //-- + void AddUniform(const lol::String &new_uniform); + void AddAttribute(const lol::String &new_attribute, VertexUsage usage, int index); + ShaderUniform const *GetUniform(const lol::String &uniform); + ShaderAttrib const *GetAttribute(const lol::String &attribute); + //-- + virtual void SetupShaderDatas(mat4 const &model) { } + +protected: + uint16_t m_vert_decl_flags; + Shader* m_shader; + DebugRenderMode m_render_mode; + Array m_shader_uniform; + Array m_shader_attrib; +}; + +class DefaultShaderData : public GpuShaderData +{ +public: + //--- + DefaultShaderData(DebugRenderMode render_mode); + DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV); + //--- + void SetupDefaultData(bool with_UV); + virtual void SetupShaderDatas(mat4 const &model); +}; + +class GpuEasyMeshData +{ +public: + //--- + GpuEasyMeshData(); + ~GpuEasyMeshData(); + //--- + void AddGpuData(GpuShaderData* gpudata, class EasyMesh* src_mesh); + void RenderMeshData(mat4 const &model); + +private: + void SetupVertexData(uint16_t vdecl_flags, EasyMesh* src_mesh); + + Array m_gpudatas; + //uint16_t are the vdecl/vbo flags to avoid copy same vdecl several times. + Array m_vdatas; + int m_vertexcount; + //We only need only one ibo for the whole mesh + IndexBuffer * m_ibo; + int m_indexcount; +}; + /* A safe enum for MeshCSG operations. */ struct CSGUsage { @@ -116,6 +178,7 @@ public: EasyMesh(); bool Compile(char const *command); + void MeshConvert(GpuShaderData* new_gpu_sdata); void MeshConvert(Shader* ProvidedShader = NULL); void Render(mat4 const &model, float damage = 0.f); @@ -444,29 +507,8 @@ private: vec2 m_texcoord_offset; vec2 m_texcoord_scale; - /* FIXME: put this in a separate class so that we can copy meshes. */ - struct - { - /* FIXME: very naughty way of handling debug render modes */ - Arrayshader; -#if VERTEX_USEAGE == VU_BONES - //TODO : -- BONE SUPPORT -- - Array coord, norm, color, bone_id, bone_weight; -#elif VERTEX_USEAGE == VU_TEX_UV - //-- UV SUPPORT -- - Array coord, norm, color, tex_coord; -#else - //-- VANILLA -- - Array coord, norm, color; -#endif - Array modelview, invmodelview, view, invview, proj, normalmat, damage, lights; - - VertexDeclaration *vdecl; - VertexBuffer *vbo; - IndexBuffer *ibo; - int vertexcount, indexcount; - } - m_gpu; + friend class GpuEasyMeshData; + GpuEasyMeshData m_gpu_data; }; } /* namespace lol */ diff --git a/src/video.h b/src/video.h index 58454fb8..0469ad92 100644 --- a/src/video.h +++ b/src/video.h @@ -56,7 +56,9 @@ struct DebugRenderMode } m_value; + inline DebugRenderMode() : m_value(Default) {} inline DebugRenderMode(Value v) : m_value(v) {} + inline DebugRenderMode(int v) : m_value((Value)v) {} inline operator Value() { return m_value; } };