From 2b6b50aa2625815da6882f372acd309730a50ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Sat, 19 Oct 2013 19:40:32 +0000 Subject: [PATCH] EZMesh : Some files splitup --- src/Makefile.am | 3 + src/commandstack.h | 87 +++++ src/easymesh/easymesh.cpp | 589 ------------------------------ src/easymesh/easymesh.h | 612 +------------------------------- src/easymesh/easymeshbuild.cpp | 216 +++++++++++ src/easymesh/easymeshbuild.h | 455 ++++++++++++++++++++++++ src/easymesh/easymeshrender.cpp | 426 ++++++++++++++++++++++ src/easymesh/easymeshrender.h | 142 ++++++++ src/lolcore.vcxproj | 5 + src/lolcore.vcxproj.filters | 13 + test/data/mesh-buffer.txt | 1 - 11 files changed, 1352 insertions(+), 1197 deletions(-) create mode 100644 src/commandstack.h create mode 100644 src/easymesh/easymeshbuild.cpp create mode 100644 src/easymesh/easymeshbuild.h create mode 100644 src/easymesh/easymeshrender.cpp create mode 100644 src/easymesh/easymeshrender.h diff --git a/src/Makefile.am b/src/Makefile.am index ed83a77c..8cb87c5c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,9 @@ liblolcore_sources = \ application/application.cpp application/application.h \ eglapp.cpp eglapp.h \ \ + commandstack.h \ + easymesh/easymeshbuild.cpp easymesh/easymeshbuild.h \ + easymesh/easymeshrender.cpp easymesh/easymeshrender.h \ easymesh/easymesh.cpp easymesh/easymesh.h \ easymesh/csgbsp.cpp easymesh/csgbsp.h \ easymesh/shiny.lolfx easymesh/shinyflat.lolfx \ diff --git a/src/commandstack.h b/src/commandstack.h new file mode 100644 index 00000000..f95b4764 --- /dev/null +++ b/src/commandstack.h @@ -0,0 +1,87 @@ +// +// Lol Engine +// +// Copyright: (c) 2009-2013 Benjamin "Touky" Huet +// (c) 2010-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The CommandStack struct +// ------------------ +// + +#if !defined __COMMANDSTACK_COMMANDSTACK_H__ +#define __COMMANDSTACK_COMMANDSTACK_H__ + +namespace lol +{ + +//Utility struct to convert command code to pseudo-bytecode +struct CommandStack +{ +private: + Array m_commands; + Array m_floats; + Array m_ints; + int m_f_cur; + int m_i_cur; + +public: + //GET/SET exec + int GetCmdNb() { return m_commands.Count(); } + int GetCmd(int i) + { + ASSERT(0 <= i && i < m_commands.Count()); + m_f_cur = m_commands[i].m2; + m_i_cur = m_commands[i].m3; + return m_commands[i].m1; + } + + //cmd storage + void AddCmd(int cmd) { m_commands.Push(cmd, m_floats.Count(), m_ints.Count()); } + + //GETTER + inline float F() { return m_floats[m_f_cur++]; } + inline int I() { return m_ints[m_i_cur++]; } + inline int E() { return I(); } + inline bool B() { return !!I(); } + inline vec2 V2() { vec2 v(F()); v.y = F(); return v; } + inline vec3 V3() { vec3 v(V2(), 0.f); v.z = F(); return v; } + inline vec4 V4() { vec4 v(V3(), 0.f); v.w = F(); return v; } + inline ivec2 IV2() { ivec2 v(I()); v.y = I(); return v; } + inline ivec3 IV3() { ivec3 v(IV2(), 0); v.z = I(); return v; } + inline ivec4 IV4() { ivec4 v(IV3(), 0); v.w = I(); return v; } + + //Alternate getters + inline void GetValue(float &f) { f = F(); } + inline void GetValue(int &i) { i = I(); } + inline void GetValue(bool &b) { b = B(); } + inline void GetValue(vec2 &v2) { v2 = V2(); } + inline void GetValue(vec3 &v3) { v3 = V3(); } + inline void GetValue(vec4 &v4) { v4 = V4(); } + inline void GetValue(ivec2 &iv2) { iv2 = IV2(); } + inline void GetValue(ivec3 &iv3) { iv3 = IV3(); } + inline void GetValue(ivec4 &iv4) { iv4 = IV4(); } + //For Safe Enum + template< class T > inline + void GetValue(T &i) { i = T((typename T::Value)I()); } + + //SETTER + CommandStack &operator<<(int i) { m_ints << i; return *this; } + CommandStack &operator<<(float f) { m_floats << f; return *this; } + CommandStack &operator<<(bool b) { return (*this << (int)b); } + CommandStack &operator<<(vec2 v) { return (*this << v.x << v.y); } + CommandStack &operator<<(vec3 v) { return (*this << v.xy << v.z); } + CommandStack &operator<<(vec4 v) { return (*this << v.xyz << v.w); } + CommandStack &operator<<(ivec2 iv) { return (*this << iv.x << iv.y); } + CommandStack &operator<<(ivec3 iv) { return (*this << iv.xy << iv.z); } + CommandStack &operator<<(ivec4 iv) { return (*this << iv.xyz << iv.w); } +}; + +} /* namespace lol */ + +#endif /* __COMMANDSTACK_COMMANDSTACK_H__ */ diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index fedcc70d..ff4b2b5d 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -22,409 +22,9 @@ #include "core.h" #include "easymesh/easymesh-compiler.h" -LOLFX_RESOURCE_DECLARE(shiny); -LOLFX_RESOURCE_DECLARE(shinyflat); -LOLFX_RESOURCE_DECLARE(shinydebugwireframe); -LOLFX_RESOURCE_DECLARE(shinydebuglighting); -LOLFX_RESOURCE_DECLARE(shinydebugnormal); -LOLFX_RESOURCE_DECLARE(shinydebugUV); -LOLFX_RESOURCE_DECLARE(shiny_SK); - namespace lol { - -//----------------------------------------------------------------------------- -GpuShaderData::GpuShaderData() -{ - 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; -} - -//----------------------------------------------------------------------------- -GpuShaderData::~GpuShaderData() -{ - m_shader_uniform.Empty(); - m_shader_attrib.Empty(); -} - -//----------------------------------------------------------------------------- -void GpuShaderData::AddUniform(const lol::String &new_uniform) -{ - m_shader_uniform.Push(new_uniform, m_shader->GetUniformLocation(new_uniform.C())); -} - -//----------------------------------------------------------------------------- -void GpuShaderData::AddAttribute(VertexUsage usage, int index) -{ - m_shader_attrib.Push(m_shader->GetAttribLocation(usage, index)); -} - -//----------------------------------------------------------------------------- -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 nullptr; -} - -//----------------------------------------------------------------------------- -ShaderAttrib const *GpuShaderData::GetAttribute(VertexUsage usage, int index) -{ - for (int i = 0; i < m_shader_attrib.Count(); ++i) - if (m_shader_attrib[i].GetUsage() == usage && m_shader_attrib[i].GetIndex() == index) - return &m_shader_attrib[i]; - return nullptr; -} - -//----------------------------------------------------------------------------- -DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode) -{ - bool with_UV = false; - m_render_mode = render_mode; - m_vert_decl_flags = (1 << VertexUsage::Position) | - (1 << VertexUsage::Normal) | - (1 << VertexUsage::Color); - - if (render_mode == DebugRenderMode::Default) - m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny)); - else if (render_mode == DebugRenderMode::Flat) - m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinyflat)); - 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 |= (1 << VertexUsage::TexCoord); - with_UV = true; - } - StoreUniformNames(); - SetupDefaultData(with_UV); -} - -//----------------------------------------------------------------------------- -DefaultShaderData::DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV) - : GpuShaderData(vert_decl_flags, shader, DebugRenderMode::Default) -{ - StoreUniformNames(); - SetupDefaultData(with_UV); -} - -static const String DefaultUniforms[7] = -{ - String("u_Lights"), - String("in_ModelView"), - String("in_View"), - String("in_Inv_View"), - String("in_Proj"), - String("in_NormalMat"), - String("in_Damage") -}; -//----------------------------------------------------------------------------- -void DefaultShaderData::StoreUniformNames() -{ -} - -//----------------------------------------------------------------------------- -void DefaultShaderData::SetupDefaultData(bool with_UV) -{ - UNUSED(with_UV); - for (int i = 0; i < 7; i++) - AddUniform(DefaultUniforms[i]); -} - -//----------------------------------------------------------------------------- -void DefaultShaderData::SetupShaderDatas(mat4 const &model) -{ - mat4 proj = g_scene->GetCamera()->GetProjection(); - mat4 view = g_scene->GetCamera()->GetView(); - mat4 modelview = view * model; - mat3 normalmat = transpose(inverse(mat3(modelview))); - /* FIXME: this should be hidden in the shader */ - Array const &lights = g_scene->GetLights(); - Array light_data; - //This is not very nice, but necessary for emscripten WebGL generation. - float f = 0.f; - - /* FIXME: the 4th component of the position can be used for other things */ - /* FIXME: GetUniform("blabla") is costly */ - for (int i = 0; i < lights.Count(); ++i) - light_data << lights[i]->GetPosition() << lights[i]->GetColor(); - while (light_data.Count() < 8) - light_data << vec4::zero << vec4::zero; - - int i = 0; - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), light_data); - - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), modelview); - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), view); - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), inverse(view)); - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), proj); - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), normalmat); - m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), f); -} - -//----------------------------------------------------------------------------- -GpuEasyMeshData::GpuEasyMeshData() -{ - m_vertexcount = 0; - m_indexcount = 0; - m_ibo = nullptr; -} - -//----------------------------------------------------------------------------- -GpuEasyMeshData::~GpuEasyMeshData() -{ - m_gpudatas.Empty(); - m_vdatas.Empty(); - if (m_ibo) - delete(m_ibo); -} - -#define BUILD_VFLAG(bool_value, flag_value, check_flag) \ - bool bool_value = (check_flag & (1 << flag_value)) != 0; \ - check_flag &= ~(1 << flag_value); -#define BUILD_VFLAG_OR(bool_value, flag_value, check_flag) \ - bool_value = (bool_value || (check_flag & (1 << flag_value)) != 0); \ - check_flag &= ~(1 << flag_value); -#define BUILD_VFLAG_COUNT(bool_value, flag_value, check_flag, count_value) \ - BUILD_VFLAG(bool_value, flag_value, check_flag) \ - count_value += (int)bool_value; - -//----------------------------------------------------------------------------- -void GpuEasyMeshData::AddGpuData(GpuShaderData* gpudata, EasyMesh* src_mesh) -{ - uint16_t vflags = gpudata->m_vert_decl_flags; - - BUILD_VFLAG(has_position, VertexUsage::Position, vflags); - BUILD_VFLAG(has_normal, VertexUsage::Normal, vflags); - BUILD_VFLAG(has_color, VertexUsage::Color, vflags); - BUILD_VFLAG(has_texcoord, VertexUsage::TexCoord, vflags); - BUILD_VFLAG_OR(has_texcoord, VertexUsage::TexCoordExt, vflags); - ASSERT(!vflags, "Vertex Usage setup is not implemented for %s, feel free to do so.", - VertexUsage::GetNameList(vflags).C()); - - if (has_position) gpudata->AddAttribute(VertexUsage::Position, 0); - if (has_normal) gpudata->AddAttribute(VertexUsage::Normal, 0); - if (has_color) gpudata->AddAttribute(VertexUsage::Color, 0); - if (has_texcoord) gpudata->AddAttribute(VertexUsage::TexCoord, 0); - - 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(); - } - - //init to a minimum of gpudata->m_render_mode size - if (m_gpudatas.Count() <= gpudata->m_render_mode) - { - int i = m_gpudatas.Count(); - int max = gpudata->m_render_mode + 1; - m_gpudatas.Reserve(max); - for (; i < max; i++) - m_gpudatas << nullptr; - } - m_gpudatas[gpudata->m_render_mode] = gpudata; -} - -//----------------------------------------------------------------------------- -void GpuEasyMeshData::SetupVertexData(uint16_t vflags, EasyMesh* src_mesh) -{ - for (int i = 0; i < m_vdatas.Count(); ++i) - if (m_vdatas[i].m1 == vflags) - return; - - VertexDeclaration* new_vdecl = nullptr; - VertexBuffer* new_vbo = nullptr; - void *vbo_data = nullptr; - int vbo_bytes = 0; - -#define COPY_VBO \ - vbo_data = &vertexlist[0]; \ - vbo_bytes = vertexlist.Bytes(); \ - m_vertexcount = vertexlist.Count(); \ - new_vbo = new VertexBuffer(vbo_bytes); \ - void *mesh = new_vbo->Lock(0, 0); \ - memcpy(mesh, vbo_data, vbo_bytes); \ - new_vbo->Unlock(); - - //Keep a count of the flags - uint16_t saveflags = vflags; - int flagnb = 0; - BUILD_VFLAG_COUNT(has_position, VertexUsage::Position, saveflags, flagnb); - BUILD_VFLAG_COUNT(has_normal, VertexUsage::Normal, saveflags, flagnb); - BUILD_VFLAG_COUNT(has_color, VertexUsage::Color, saveflags, flagnb); - BUILD_VFLAG_COUNT(has_texcoord, VertexUsage::TexCoord, saveflags, flagnb); - BUILD_VFLAG_COUNT(has_texcoordExt,VertexUsage::TexCoordExt, saveflags, flagnb); - ASSERT(!saveflags, "Vertex Declaration setup is not implemented for %s, feel free to do so.", - VertexUsage::GetNameList(vflags).C()); - - if (flagnb == 5 && has_position && has_normal && has_color && has_texcoord && has_texcoordExt) - { - 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].m_coord, - src_mesh->m_vert[i].m_normal, - (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), - src_mesh->m_vert[i].m_texcoord); - COPY_VBO; - } - else if (flagnb == 4 && has_position && has_normal && has_color && has_texcoord) - { - 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].m_coord, - src_mesh->m_vert[i].m_normal, - (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), - src_mesh->m_vert[i].m_texcoord.xy); - COPY_VBO; - } - else if (flagnb == 4 && has_position && has_color && has_texcoord && has_texcoordExt) - { - new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::Color, VertexUsage::TexCoord)); - - Array vertexlist; - for (int i = 0; i < src_mesh->m_vert.Count(); i++) - vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_color, src_mesh->m_vert[i].m_texcoord); - COPY_VBO; - } - else if (flagnb == 3 && has_position && has_normal && has_color) - { - 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].m_coord, - src_mesh->m_vert[i].m_normal, - (u8vec4)(src_mesh->m_vert[i].m_color * 255.f)); - COPY_VBO; - } - else if (flagnb == 3 && has_position && has_texcoord && has_texcoordExt) - { - new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::TexCoord)); - - Array vertexlist; - for (int i = 0; i < src_mesh->m_vert.Count(); i++) - vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord); - COPY_VBO; - } - else if (flagnb == 2 && has_position && has_texcoord) - { - new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::TexCoord)); - - Array vertexlist; - for (int i = 0; i < src_mesh->m_vert.Count(); i++) - vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord.xy); - COPY_VBO; - } - else if (flagnb == 2 && has_position && has_color) - { - new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::Color)); - - Array vertexlist; - for (int i = 0; i < src_mesh->m_vert.Count(); i++) - vertexlist.Push(src_mesh->m_vert[i].m_coord, (u8vec4)(src_mesh->m_vert[i].m_color * 255.f)); - COPY_VBO; - } - else - ASSERT(0, "Vertex Declaration combination is not implemented for %s, feel free to do so.", - VertexUsage::GetNameList(vflags).C()); - - m_vdatas.Push(vflags, new_vdecl, new_vbo); -} - -//----------------------------------------------------------------------------- -void GpuEasyMeshData::RenderMeshData(mat4 const &model, int render_mode) -{ - ASSERT(0 <= render_mode && render_mode < m_gpudatas.Count(), "render mode is not in the defined range"); - ASSERT(m_gpudatas[render_mode], "gpu datas for this render mode don't exist"); - GpuShaderData& gpu_sd = *(m_gpudatas[render_mode]); - - 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(); - - BUILD_VFLAG(has_position, VertexUsage::Position, vflags); - BUILD_VFLAG(has_normal, VertexUsage::Normal, vflags); - BUILD_VFLAG(has_color, VertexUsage::Color, vflags); - BUILD_VFLAG(has_texcoord, VertexUsage::TexCoord, vflags); - BUILD_VFLAG_OR(has_texcoord,VertexUsage::TexCoordExt, vflags); - ASSERT(!vflags, "Vertex Stream setup is not implemented for %s, feel free to do so.", - VertexUsage::GetNameList(vflags).C()); - - int idx = 0; - ShaderAttrib Attribs[4] = { lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib() }; - - if (has_position) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Position, 0); - if (has_normal) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Normal, 0); - if (has_color) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Color, 0); - if (has_texcoord) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::TexCoord, 0); - - vdecl->SetStream(vbo, Attribs[0], Attribs[1], Attribs[2], Attribs[3]); - - m_ibo->Bind(); - vdecl->DrawIndexedElements(MeshPrimitive::Triangles, 0, 0, m_vertexcount, 0, m_indexcount); - m_ibo->Unbind(); - vdecl->Unbind(); -} - //----------------------------------------------------------------------------- EasyMesh::EasyMesh() : m_build_data(nullptr) @@ -696,195 +296,6 @@ bool EasyMesh::SetRender(bool should_render) // "Collisions" functions //------------------- -//----------------------------------------------------------------------------- -//helpers func to retrieve a vertex. -int VertexDictionnary::FindVertexMaster(const int search_idx) -{ - //Resolve current vertex idx in the dictionnary (if exist) - for (int j = 0; j < vertex_list.Count(); j++) - if (vertex_list[j].m1 == search_idx) - return vertex_list[j].m3; - return VDictType::DoesNotExist; -} - -//----------------------------------------------------------------------------- -//retrieve a list of matching vertices, doesn't include search_idx. -bool VertexDictionnary::FindMatchingVertices(const int search_idx, Array &matching_ids) -{ - int cur_mast = FindVertexMaster(search_idx); - - if (cur_mast == VDictType::DoesNotExist || cur_mast == VDictType::Alone) - return false; - - if (cur_mast == VDictType::Master) - cur_mast = search_idx; - else - matching_ids << vertex_list[cur_mast].m1; - - for (int j = 0; j < vertex_list.Count(); j++) - if (vertex_list[j].m3 == cur_mast && vertex_list[j].m1 != search_idx) - matching_ids << vertex_list[j].m1; - - return (matching_ids.Count() > 0); -} - -//----------------------------------------------------------------------------- -//Will return connected vertices (through triangles), if returned vertex has matching ones, it only returns the master. -bool VertexDictionnary::FindConnectedVertices(const int search_idx, const Array &tri_list, const int tri0, Array &connected_vert, Array const *ignored_tri) -{ - Array connected_tri; - FindConnectedTriangles(search_idx, tri_list, tri0, connected_tri, ignored_tri); - - for (int i = 0; i < connected_tri.Count(); i++) - { - for (int j = 0; j < 3; j++) - { - int v_indice = tri_list[connected_tri[i] + j]; - if (v_indice != search_idx) - { - int found_master = FindVertexMaster(tri_list[connected_tri[i] + j]); - if (found_master == VDictType::Alone || found_master == VDictType::Master) - found_master = v_indice; - if (found_master != search_idx) - { - bool already_exist = false; - for (int k = 0; !already_exist && k < connected_vert.Count(); k++) - if (connected_vert[k] == found_master) - already_exist = true; - if (!already_exist) - connected_vert << found_master; - } - } - } - } - return (connected_vert.Count() > 0); -} -//----------------------------------------------------------------------------- -bool VertexDictionnary::FindConnectedTriangles(const int search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) -{ - return FindConnectedTriangles(ivec3(search_idx, search_idx, search_idx), tri_list, tri0, connected_tri, ignored_tri); -} -//----------------------------------------------------------------------------- -bool VertexDictionnary::FindConnectedTriangles(const ivec2 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) -{ - return FindConnectedTriangles(ivec3(search_idx, search_idx.x), tri_list, tri0, connected_tri, ignored_tri); -} -//----------------------------------------------------------------------------- -bool VertexDictionnary::FindConnectedTriangles(const ivec3 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) -{ - int needed_validation = 0; - Array vert_list[3]; - for (int i = 0; i < 3; i++) - { - //Small optim since above func will use this one - if ((i == 1 && search_idx[0] == search_idx[1]) || - (i == 2 && (search_idx[0] == search_idx[2] || search_idx[1] == search_idx[2]))) - continue; - else - { - //increment the validation info, hence empty list aren't taken into account. - needed_validation++; - vert_list[i] << search_idx[i]; - FindMatchingVertices(search_idx[i], vert_list[i]); - } - } - - for (int i = tri0; i < tri_list.Count(); i += 3) - { - if (ignored_tri) - { - bool should_pass = false; - for (int j = 0; !should_pass && j < ignored_tri->Count(); j++) - if ((*ignored_tri)[j] == i) - should_pass = true; - if (should_pass) - continue; - } - int found_validation = 0; - for (int j = 0; j < 3; j++) - { - bool validated = false; - for (int k = 0; !validated && k < vert_list[j].Count(); k++) - for (int l = 0; !validated && l < 3; l++) - if (vert_list[j][k] == tri_list[i + l]) - validated = true; - found_validation += (validated)?(1):(0); - } - //triangle is validated store it - if (found_validation == needed_validation) - connected_tri << i; - } - - return (connected_tri.Count() > 0); -} - -//----------------------------------------------------------------------------- -//Will update the given list with all the vertices on the same spot. -void VertexDictionnary::AddVertex(const int vert_id, const vec3 vert_coord) -{ - for (int j = 0; j < vertex_list.Count(); j++) - if (vertex_list[j].m1 == vert_id) - return; - - //First, build the vertex Dictionnary - int i = 0; - for (; i < master_list.Count(); i++) - { - int cur_mast = master_list[i]; - int cur_id = vertex_list[cur_mast].m1; - vec3 cur_loc = vertex_list[cur_mast].m2; - int &cur_type = vertex_list[cur_mast].m3; - - if (cur_id == vert_id) - return; - - if (sqlength(cur_loc - vert_coord) < CSG_EPSILON) - { - if (cur_type == VDictType::Alone) - cur_type = VDictType::Master; - vertex_list.Push(vert_id, vert_coord, cur_mast); - return; - } - } - - //We're here because we couldn't find any matching vertex - master_list.Push(vertex_list.Count()); - vertex_list.Push(vert_id, vert_coord, VDictType::Alone); -} - -//----------------------------------------------------------------------------- -//Will update the given list with all the vertices on the same spot. -void VertexDictionnary::RemoveVertex(const int vert_id) -{ - int j = 0; - for (; j < vertex_list.Count(); j++) - if (vertex_list[j].m1 == vert_id) - break; - - if (vertex_list[j].m3 == VDictType::Master) - { - int jf = -1; - //change all the master ref in the list - for (int i = 0; i < vertex_list.Count(); i++) - { - if (vertex_list[i].m3 == j) - { - if (jf < 0) - { - jf = i; - vertex_list[i].m3 = VDictType::Master; - } - else - vertex_list[i].m3 = jf; - } - } - } - vertex_list.Remove(j); - for (int i = 0; i < master_list.Count(); i++) - if (master_list[j] == j) - break; -} - //----------------------------------------------------------------------------- void EasyMesh::MeshCsg(CSGUsage csg_operation) { diff --git a/src/easymesh/easymesh.h b/src/easymesh/easymesh.h index 1229aa89..2d4ae328 100644 --- a/src/easymesh/easymesh.h +++ b/src/easymesh/easymesh.h @@ -15,582 +15,16 @@ // ------------------ // +#include "commandstack.h" +#include "easymeshrender.h" +#include "easymeshbuild.h" + #if !defined __EASYMESH_EASYMESH_H__ #define __EASYMESH_EASYMESH_H__ namespace lol { -//Utility struct to convert command code to pseudo-bytecode -struct CommandStack -{ -private: - Array m_commands; - Array m_floats; - Array m_ints; - int m_f_cur; - int m_i_cur; - -public: - //GET/SET exec - int GetCmdNb() { return m_commands.Count(); } - int GetCmd(int i) - { - ASSERT(0 <= i && i < m_commands.Count()); - m_f_cur = m_commands[i].m2; - m_i_cur = m_commands[i].m3; - return m_commands[i].m1; - } - - //cmd storage - void AddCmd(int cmd) { m_commands.Push(cmd, m_floats.Count(), m_ints.Count()); } - - //GETTER - inline float F() { return m_floats[m_f_cur++]; } - inline int I() { return m_ints[m_i_cur++]; } - inline int E() { return I(); } - inline bool B() { return !!I(); } - inline vec2 V2() { vec2 v(F()); v.y = F(); return v; } - inline vec3 V3() { vec3 v(V2(), 0.f); v.z = F(); return v; } - inline vec4 V4() { vec4 v(V3(), 0.f); v.w = F(); return v; } - inline ivec2 IV2() { ivec2 v(I()); v.y = I(); return v; } - inline ivec3 IV3() { ivec3 v(IV2(), 0); v.z = I(); return v; } - inline ivec4 IV4() { ivec4 v(IV3(), 0); v.w = I(); return v; } - - //Alternate getters - inline void GetValue(float &f) { f = F(); } - inline void GetValue(int &i) { i = I(); } - inline void GetValue(bool &b) { b = B(); } - inline void GetValue(vec2 &v2) { v2 = V2(); } - inline void GetValue(vec3 &v3) { v3 = V3(); } - inline void GetValue(vec4 &v4) { v4 = V4(); } - inline void GetValue(ivec2 &iv2) { iv2 = IV2(); } - inline void GetValue(ivec3 &iv3) { iv3 = IV3(); } - inline void GetValue(ivec4 &iv4) { iv4 = IV4(); } - //For Safe Enum - template< class T > inline - void GetValue(T &i) { i = T((typename T::Value)I()); } - - //SETTER - CommandStack &operator<<(int i) { m_ints << i; return *this; } - CommandStack &operator<<(float f) { m_floats << f; return *this; } - CommandStack &operator<<(bool b) { return (*this << (int)b); } - CommandStack &operator<<(vec2 v) { return (*this << v.x << v.y); } - CommandStack &operator<<(vec3 v) { return (*this << v.xy << v.z); } - CommandStack &operator<<(vec4 v) { return (*this << v.xyz << v.w); } - CommandStack &operator<<(ivec2 iv) { return (*this << iv.x << iv.y); } - CommandStack &operator<<(ivec3 iv) { return (*this << iv.xy << iv.z); } - CommandStack &operator<<(ivec4 iv) { return (*this << iv.xyz << iv.w); } -}; - -//Utility enum for renderers -struct MeshRender -{ - enum Value - { - NeedData, - NeedConvert, - CanRender, - IgnoreRender, - - Max - } - m_value; - - inline MeshRender(Value v) : m_value(v) {} - inline MeshRender() : m_value(NeedData) {} - inline operator Value() { return m_value; } -}; - -//Vertex datas for easymesh vertex list. -//TODO : -struct VertexData -{ - vec3 m_coord; - vec3 m_normal; - vec4 m_color; - vec4 m_texcoord; - ivec4 m_bone_id; - vec4 m_bone_weight; - - VertexData(vec3 new_coord = vec3(0.f), - vec3 new_normal = vec3(0.f, 1.f, 0.f), - vec4 new_color = vec4(0.f), - vec4 new_texcoord = vec4(0.f), - ivec4 new_bone_id = ivec4(0), - vec4 new_bone_weight= vec4(0.f)) - { - m_coord = new_coord; - m_normal = new_normal; - m_color = new_color; - m_texcoord = new_texcoord; - m_bone_id = new_bone_id; - m_bone_weight = new_bone_weight; - } -}; - -//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); - virtual ~GpuShaderData(); - //-- - void AddUniform(const lol::String &new_uniform); - void AddAttribute(VertexUsage usage, int index); - ShaderUniform const *GetUniform(const lol::String &uniform); - ShaderAttrib const *GetAttribute(VertexUsage usage, int index); - //-- - virtual void SetupShaderDatas(mat4 const &model) { UNUSED(model); } - //-- - -protected: - uint16_t m_vert_decl_flags; - Shader* m_shader; - int 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); - virtual ~DefaultShaderData() {} - void StoreUniformNames(); - //--- - void SetupDefaultData(bool with_UV); - virtual void SetupShaderDatas(mat4 const &model); - //-- - Array m_uniform_names; -}; - -class GpuEasyMeshData -{ - friend class EasyMesh; - -public: - //--- - GpuEasyMeshData(); - ~GpuEasyMeshData(); - //--- - void AddGpuData(GpuShaderData* gpudata, class EasyMesh* src_mesh); - void RenderMeshData(mat4 const &model, int render_mode=Video::GetDebugRenderMode()); - bool HasData(int render_mode) { return (0 <= render_mode && render_mode < m_gpudatas.Count() && !!m_gpudatas[render_mode]); } - -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; -}; - - -struct MeshBuildOperation -{ - enum Value - { - //When this flag is up, negative scaling will not invert faces. - ScaleWinding = (1 << 0), - CommandRecording = (1 << 1), - CommandExecution = (1 << 2), - QuadWeighting = (1 << 3), - IgnoreQuadWeighting = (1 << 4), - PostBuildComputeNormals = (1 << 5), - PreventVertCleanup = (1 << 6), - - All = 0xffffffff - } - m_value; - - inline MeshBuildOperation(Value v) : m_value(v) {} - inline MeshBuildOperation(uint64_t i) : m_value((Value)i) {} - inline operator Value() { return m_value; } -}; - -struct EasyMeshCmdType -{ - enum Value - { - MeshCsg = 0, - - LoopStart, - LoopEnd, - OpenBrace, - CloseBrace, - - ScaleWinding, - QuadWeighting, - PostBuildNormal, - PreventVertCleanup, - SetColorA, - SetColorB, - SetVertColor, - - VerticesMerge, - VerticesSeparate, - - Translate, - Rotate, - RadialJitter, - MeshTranform, - Scale, - DupAndScale, - Chamfer, - - SplitTriangles, - SmoothMesh, - - AppendCylinder, - AppendCapsule, - AppendTorus, - AppendBox, - AppendStar, - AppendExpandedStar, - AppendDisc, - AppendSimpleTriangle, - AppendSimpleQuad, - AppendCog, - - Max - } - m_value; - - inline EasyMeshCmdType(Value v) : m_value(v) {} - inline operator Value() { return m_value; } - inline int Value() { return m_value; } -}; - - -struct MeshType -{ - enum Value - { - Triangle = 0, - Quad, - Box, - Sphere, - Capsule, - Torus, - Cylinder, - Disc, - Star, - ExpandedStar, - Cog, - - Max - } - m_value; - - inline MeshType(Value v) : m_value(v) {} - inline operator Value() { return m_value; } -}; - -//TODO : Add other Build type -struct TexCoordBuildType -{ - enum Value - { - TriangleDefault = 0, - QuadDefault = 0, - BoxDefault = 0, - SphereDefault = 0, - CapsuleDefault = 0, - TorusDefault = 0, - CylinderDefault = 0, - DiscDefault = 0, - StarDefault = 0, - ExpandedStarDefault = 0, - CogDefault = 0, - - //NEVER FORGET TO INCREMENT THIS WHEN ADDING A VALUE - Max = 1 - } - m_value; - - inline TexCoordBuildType() : m_value(TriangleDefault) {} - inline TexCoordBuildType(Value v) : m_value(v) {} - inline TexCoordBuildType(int v) : m_value((Value)v) {} - inline operator Value() { return m_value; } -}; - -struct MeshFaceType -{ - enum Value - { - BoxFront = 0, - BoxLeft = 1, - BoxBack = 2, - BoxRight = 3, - BoxTop = 4, - BoxBottom = 5, - QuadDefault = 0, - - //NEVER FORGET TO INCREMENT THIS WHEN ADDING A VALUE - Max = 6 - } - m_value; - - inline MeshFaceType(Value v) : m_value(v) {} - inline operator Value() { return m_value; } -}; - -struct TexCoordPos -{ - enum Value - { - BL, //BottomLeft - BR, //BottomRight - TL, //TopLeft - TR //TopRight - } - m_value; - - inline TexCoordPos(Value v) : m_value(v) {} - inline operator Value() { return m_value; } -}; - -class EasyMeshBuildData -{ -public: - EasyMeshBuildData() - { - m_color_a = vec4(0.f, 0.f, 0.f, 1.f); - m_color_b = vec4(0.f, 0.f, 0.f, 1.f); - m_texcoord_offset = vec2(0.f); - m_texcoord_offset2 = vec2(0.f); - m_texcoord_scale = vec2(1.f); - m_texcoord_scale2 = vec2(1.f); - m_build_flags = 0; - m_i_cmd = 0; - m_exec_nb = -1; - for (int i = 0; i < MeshType::Max; ++i) - { - m_texcoord_build_type[i] = TexCoordBuildType::TriangleDefault; - m_texcoord_build_type2[i] = TexCoordBuildType::TriangleDefault; - } - } - - inline CommandStack &CmdStack() { return m_stack; } - inline int &Cmdi() { return m_i_cmd; } - inline int &CmdExecNb() { return m_exec_nb; } - inline Array &LoopStack(){ return m_loop_stack; } - inline vec4 &ColorA() { return m_color_a; } - inline vec4 &ColorB() { return m_color_b; } - inline vec2 &TexCoordOffset() { return m_texcoord_offset; } - inline vec2 &TexCoordScale() { return m_texcoord_scale; } - inline vec2 &TexCoordOffset2() { return m_texcoord_offset2; } - inline vec2 &TexCoordScale2() { return m_texcoord_scale2; } - - //UV1 - void SetTexCoordBuildType(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type[mt] & 1); } - TexCoordBuildType GetTexCoordBuildType(MeshType mt) - { - uint32_t flag = (uint32_t)((m_texcoord_build_type[mt] & ~(1)) >> 1); - int i = 0; - while (flag >>= 1) - i++; - return TexCoordBuildType(i); - } - void SetTexCoordCustomBuild(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) - { - if (face >= m_texcoord_custom_build[mt].Count()) - m_texcoord_custom_build[mt].Resize(face + 1); - m_texcoord_custom_build[mt][face].m1 = BL; - m_texcoord_custom_build[mt][face].m2 = TR; - m_texcoord_build_type[mt] |= 1; - } - void ClearTexCoordCustomBuild(MeshType mt) { m_texcoord_build_type[mt] &= ~1; } - /* FIXME : Do something better ? */ - vec2 TexCoord(MeshType mt, TexCoordPos tcp, MeshFaceType face) - { - vec2 BL = vec2(0.f); - vec2 TR = vec2(0.f); - if (m_texcoord_build_type[mt] & 1 && face < m_texcoord_custom_build[mt].Count()) - { - BL = m_texcoord_custom_build[mt][face].m1; - TR = m_texcoord_custom_build[mt][face].m2; - } - else - { - /* unused for now, but will be if new BuildType are added. */ - TexCoordBuildType tcbt = GetTexCoordBuildType(mt); - UNUSED(tcbt); - if (mt == MeshType::Triangle) - mt = mt; - else if (mt == MeshType::Quad) - { - //There's nothin' else than QuadDefault - BL = vec2(0.f); - TR = vec2(1.f); - } - else if (mt == MeshType::Box) - { - vec2 data[][2] = - { //TexCoordBuildType::BoxDefault - { vec2(0.f), vec2(.5f) }, - { vec2(.5f, 0.f), vec2(1.f, .5f) }, - { vec2(0.f), vec2(.5f) }, - { vec2(.5f, 0.f), vec2(1.f, .5f) }, - { vec2(0.f, .5f), vec2(.5f, 1.f) }, - { vec2(.5f, .5f), vec2(1.f, 1.f) } - }; - BL = data[face][0]; //[tcbt] - TR = data[face][1]; //[tcbt] - } - else if (mt == MeshType::Sphere) - mt = mt; - else if (mt == MeshType::Capsule) - mt = mt; - else if (mt == MeshType::Torus) - mt = mt; - else if (mt == MeshType::Cylinder) - mt = mt; - else if (mt == MeshType::Disc) - mt = mt; - else if (mt == MeshType::Star) - mt = mt; - else if (mt == MeshType::ExpandedStar) - mt = mt; - else if (mt == MeshType::Cog) - mt = mt; - } - - vec2 res = vec2(.0f); - if (tcp == TexCoordPos::BL) - res = BL; - else if (tcp == TexCoordPos::BR) - res = vec2(TR.x, BL.y); - else if (tcp == TexCoordPos::TL) - res = vec2(BL.x, TR.y); - else if (tcp == TexCoordPos::TR) - res = TR; - - return res * m_texcoord_scale + m_texcoord_offset2; - } - - //UV2 - void SetTexCoordBuildType2(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type2[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type2[mt] & 1); } - TexCoordBuildType GetTexCoordBuildType2(MeshType mt) - { - uint32_t flag = ((m_texcoord_build_type2[mt] & ~(1)) >> 1); - int i = 0; - while (flag >>= 1) - i++; - return TexCoordBuildType(i); - } - void SetTexCoordCustomBuild2(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) - { - if (face >= m_texcoord_custom_build2[mt].Count()) - m_texcoord_custom_build2[mt].Resize(face + 1); - m_texcoord_custom_build2[mt][face].m1 = BL; - m_texcoord_custom_build2[mt][face].m2 = TR; - m_texcoord_build_type2[mt] |= 1; - } - void ClearTexCoordCustomBuild2(MeshType mt) { m_texcoord_build_type2[mt] &= ~1; } - vec2 TexCoord2(MeshType mt, TexCoordPos tcp, MeshFaceType face) - { - vec2 BL = vec2(0.f); - vec2 TR = vec2(0.f); - if (m_texcoord_build_type2[mt] & 1 && face < m_texcoord_custom_build2[mt].Count()) - { - BL = m_texcoord_custom_build2[mt][face].m1; - TR = m_texcoord_custom_build2[mt][face].m2; - } - else - { - TexCoordBuildType tcbt = GetTexCoordBuildType2(mt); - UNUSED(tcbt); - if (mt == MeshType::Triangle) - mt = mt; - else if (mt == MeshType::Quad) - { - //There's nothin' else than QuadDefault - BL = vec2(0.f); - TR = vec2(1.f); - } - else if (mt == MeshType::Box) - { - vec2 data[][2] = - { //TexCoordBuildType::BoxDefault - { vec2(0.f), vec2(.5f) }, - { vec2(.5f, 0.f), vec2(1.f, .5f) }, - { vec2(0.f), vec2(.5f) }, - { vec2(.5f, 0.f), vec2(1.f, .5f) }, - { vec2(0.f, .5f), vec2(.5f, 1.f) }, - { vec2(.5f, .5f), vec2(1.f, 1.f) } - }; - BL = data[face][0]; //[tcbt] - TR = data[face][1]; //[tcbt] - } - else if (mt == MeshType::Sphere) - mt = mt; - else if (mt == MeshType::Capsule) - mt = mt; - else if (mt == MeshType::Torus) - mt = mt; - else if (mt == MeshType::Cylinder) - mt = mt; - else if (mt == MeshType::Disc) - mt = mt; - else if (mt == MeshType::Star) - mt = mt; - else if (mt == MeshType::ExpandedStar) - mt = mt; - else if (mt == MeshType::Cog) - mt = mt; - } - - vec2 res = vec2(.0f); - if (tcp == TexCoordPos::BL) - res = BL; - else if (tcp == TexCoordPos::BR) - res = vec2(TR.x, BL.y); - else if (tcp == TexCoordPos::TL) - res = vec2(BL.x, TR.y); - else if (tcp == TexCoordPos::TR) - res = TR; - - return res * m_texcoord_scale + m_texcoord_offset2; - } - - inline bool IsEnabled(MeshBuildOperation mbo) { return (m_build_flags & mbo) != 0; } - inline void Enable(MeshBuildOperation mbo) { m_build_flags |= mbo; } - inline void Disable(MeshBuildOperation mbo) { m_build_flags &= ~mbo; } - inline void Toggle(MeshBuildOperation mbo) { m_build_flags ^= mbo; } - inline void Set(MeshBuildOperation mbo, bool value) { if (value) Enable(mbo); else Disable(mbo); } - -public: - CommandStack m_stack; - int m_i_cmd; - int m_exec_nb; - Array m_loop_stack; - vec4 m_color_a; - vec4 m_color_b; - vec2 m_texcoord_offset; - vec2 m_texcoord_offset2; - vec2 m_texcoord_scale; - vec2 m_texcoord_scale2; - Array m_texcoord_custom_build[MeshType::Max]; - Array m_texcoord_custom_build2[MeshType::Max]; - uint32_t m_texcoord_build_type[MeshType::Max]; - uint32_t m_texcoord_build_type2[MeshType::Max]; - uint32_t m_build_flags; -}; - /* A safe enum for MeshCSG operations. */ struct CSGUsage { @@ -612,43 +46,6 @@ struct CSGUsage inline operator Value() { return m_value; } }; -/* A safe enum for VertexDictionnary operations. */ -struct VDictType -{ - enum Value - { - DoesNotExist=-3, - Alone=-2, - Master=-1 - } - m_value; - - inline VDictType(Value v) : m_value(v) {} - inline operator Value() { return m_value; } -}; - -/* TODO : replace VDict by a proper Half-edge system */ -//a class whose goal is to keep a list of the adjacent vertices for mesh operations purposes -class VertexDictionnary -{ -public: - int FindVertexMaster(const int search_idx); - bool FindMatchingVertices(const int search_idx, Array &matching_ids); - bool FindConnectedVertices(const int search_idx, const Array &tri_list, const int tri0, Array &connected_vert, Array const *ignored_tri = nullptr); - bool FindConnectedTriangles(const int search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); - bool FindConnectedTriangles(const ivec2 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); - bool FindConnectedTriangles(const ivec3 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); - void AddVertex(int vert_id, vec3 vert_coord); - void RemoveVertex(int vert_id); - bool GetMasterList(Array &ret_master_list) { ret_master_list = master_list; return ret_master_list.Count() > 0; } - void Clear() { vertex_list.Empty(); } -private: - // - Array vertex_list; - //List of the master_ vertices - Array master_list; -}; - struct Axis { enum Value @@ -1030,6 +427,7 @@ public: private: class EasyMeshBuildData* m_build_data; }; + } /* namespace lol */ #endif /* __EASYMESH_EASYMESH_H__ */ diff --git a/src/easymesh/easymeshbuild.cpp b/src/easymesh/easymeshbuild.cpp new file mode 100644 index 00000000..a0a43019 --- /dev/null +++ b/src/easymesh/easymeshbuild.cpp @@ -0,0 +1,216 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The EasyMesh class +// ------------------ +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" + +namespace lol +{ + +//----------------------------------------------------------------------------- +//helpers func to retrieve a vertex. +int VertexDictionnary::FindVertexMaster(const int search_idx) +{ + //Resolve current vertex idx in the dictionnary (if exist) + for (int j = 0; j < vertex_list.Count(); j++) + if (vertex_list[j].m1 == search_idx) + return vertex_list[j].m3; + return VDictType::DoesNotExist; +} + +//----------------------------------------------------------------------------- +//retrieve a list of matching vertices, doesn't include search_idx. +bool VertexDictionnary::FindMatchingVertices(const int search_idx, Array &matching_ids) +{ + int cur_mast = FindVertexMaster(search_idx); + + if (cur_mast == VDictType::DoesNotExist || cur_mast == VDictType::Alone) + return false; + + if (cur_mast == VDictType::Master) + cur_mast = search_idx; + else + matching_ids << vertex_list[cur_mast].m1; + + for (int j = 0; j < vertex_list.Count(); j++) + if (vertex_list[j].m3 == cur_mast && vertex_list[j].m1 != search_idx) + matching_ids << vertex_list[j].m1; + + return (matching_ids.Count() > 0); +} + +//----------------------------------------------------------------------------- +//Will return connected vertices (through triangles), if returned vertex has matching ones, it only returns the master. +bool VertexDictionnary::FindConnectedVertices(const int search_idx, const Array &tri_list, const int tri0, Array &connected_vert, Array const *ignored_tri) +{ + Array connected_tri; + FindConnectedTriangles(search_idx, tri_list, tri0, connected_tri, ignored_tri); + + for (int i = 0; i < connected_tri.Count(); i++) + { + for (int j = 0; j < 3; j++) + { + int v_indice = tri_list[connected_tri[i] + j]; + if (v_indice != search_idx) + { + int found_master = FindVertexMaster(tri_list[connected_tri[i] + j]); + if (found_master == VDictType::Alone || found_master == VDictType::Master) + found_master = v_indice; + if (found_master != search_idx) + { + bool already_exist = false; + for (int k = 0; !already_exist && k < connected_vert.Count(); k++) + if (connected_vert[k] == found_master) + already_exist = true; + if (!already_exist) + connected_vert << found_master; + } + } + } + } + return (connected_vert.Count() > 0); +} +//----------------------------------------------------------------------------- +bool VertexDictionnary::FindConnectedTriangles(const int search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) +{ + return FindConnectedTriangles(ivec3(search_idx, search_idx, search_idx), tri_list, tri0, connected_tri, ignored_tri); +} +//----------------------------------------------------------------------------- +bool VertexDictionnary::FindConnectedTriangles(const ivec2 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) +{ + return FindConnectedTriangles(ivec3(search_idx, search_idx.x), tri_list, tri0, connected_tri, ignored_tri); +} +//----------------------------------------------------------------------------- +bool VertexDictionnary::FindConnectedTriangles(const ivec3 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri) +{ + int needed_validation = 0; + Array vert_list[3]; + for (int i = 0; i < 3; i++) + { + //Small optim since above func will use this one + if ((i == 1 && search_idx[0] == search_idx[1]) || + (i == 2 && (search_idx[0] == search_idx[2] || search_idx[1] == search_idx[2]))) + continue; + else + { + //increment the validation info, hence empty list aren't taken into account. + needed_validation++; + vert_list[i] << search_idx[i]; + FindMatchingVertices(search_idx[i], vert_list[i]); + } + } + + for (int i = tri0; i < tri_list.Count(); i += 3) + { + if (ignored_tri) + { + bool should_pass = false; + for (int j = 0; !should_pass && j < ignored_tri->Count(); j++) + if ((*ignored_tri)[j] == i) + should_pass = true; + if (should_pass) + continue; + } + int found_validation = 0; + for (int j = 0; j < 3; j++) + { + bool validated = false; + for (int k = 0; !validated && k < vert_list[j].Count(); k++) + for (int l = 0; !validated && l < 3; l++) + if (vert_list[j][k] == tri_list[i + l]) + validated = true; + found_validation += (validated)?(1):(0); + } + //triangle is validated store it + if (found_validation == needed_validation) + connected_tri << i; + } + + return (connected_tri.Count() > 0); +} + +//----------------------------------------------------------------------------- +//Will update the given list with all the vertices on the same spot. +void VertexDictionnary::AddVertex(const int vert_id, const vec3 vert_coord) +{ + for (int j = 0; j < vertex_list.Count(); j++) + if (vertex_list[j].m1 == vert_id) + return; + + //First, build the vertex Dictionnary + int i = 0; + for (; i < master_list.Count(); i++) + { + int cur_mast = master_list[i]; + int cur_id = vertex_list[cur_mast].m1; + vec3 cur_loc = vertex_list[cur_mast].m2; + int &cur_type = vertex_list[cur_mast].m3; + + if (cur_id == vert_id) + return; + + if (sqlength(cur_loc - vert_coord) < CSG_EPSILON) + { + if (cur_type == VDictType::Alone) + cur_type = VDictType::Master; + vertex_list.Push(vert_id, vert_coord, cur_mast); + return; + } + } + + //We're here because we couldn't find any matching vertex + master_list.Push(vertex_list.Count()); + vertex_list.Push(vert_id, vert_coord, VDictType::Alone); +} + +//----------------------------------------------------------------------------- +//Will update the given list with all the vertices on the same spot. +void VertexDictionnary::RemoveVertex(const int vert_id) +{ + int j = 0; + for (; j < vertex_list.Count(); j++) + if (vertex_list[j].m1 == vert_id) + break; + + if (vertex_list[j].m3 == VDictType::Master) + { + int jf = -1; + //change all the master ref in the list + for (int i = 0; i < vertex_list.Count(); i++) + { + if (vertex_list[i].m3 == j) + { + if (jf < 0) + { + jf = i; + vertex_list[i].m3 = VDictType::Master; + } + else + vertex_list[i].m3 = jf; + } + } + } + vertex_list.Remove(j); + for (int i = 0; i < master_list.Count(); i++) + if (master_list[j] == j) + break; +} + +} /* namespace lol */ diff --git a/src/easymesh/easymeshbuild.h b/src/easymesh/easymeshbuild.h new file mode 100644 index 00000000..4785cf6c --- /dev/null +++ b/src/easymesh/easymeshbuild.h @@ -0,0 +1,455 @@ +// +// Lol Engine +// +// Copyright: (c) 2009-2013 Benjamin "Touky" Huet +// (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The EasyMesh class +// ------------------ +// + +#if !defined __EASYMESHBUILD_EASYMESHBUILD_H__ +#define __EASYMESHBUILD_EASYMESHBUILD_H__ + +namespace lol +{ + +struct MeshBuildOperation +{ + enum Value + { + //When this flag is up, negative scaling will not invert faces. + ScaleWinding = (1 << 0), + CommandRecording = (1 << 1), + CommandExecution = (1 << 2), + QuadWeighting = (1 << 3), + IgnoreQuadWeighting = (1 << 4), + PostBuildComputeNormals = (1 << 5), + PreventVertCleanup = (1 << 6), + + All = 0xffffffff + } + m_value; + + inline MeshBuildOperation(Value v) : m_value(v) {} + inline MeshBuildOperation(uint64_t i) : m_value((Value)i) {} + inline operator Value() { return m_value; } +}; + +struct EasyMeshCmdType +{ + enum Value + { + MeshCsg = 0, + + LoopStart, + LoopEnd, + OpenBrace, + CloseBrace, + + ScaleWinding, + QuadWeighting, + PostBuildNormal, + PreventVertCleanup, + SetColorA, + SetColorB, + SetVertColor, + + VerticesMerge, + VerticesSeparate, + + Translate, + Rotate, + RadialJitter, + MeshTranform, + Scale, + DupAndScale, + Chamfer, + + SplitTriangles, + SmoothMesh, + + AppendCylinder, + AppendCapsule, + AppendTorus, + AppendBox, + AppendStar, + AppendExpandedStar, + AppendDisc, + AppendSimpleTriangle, + AppendSimpleQuad, + AppendCog, + + Max + } + m_value; + + inline EasyMeshCmdType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } + inline int Value() { return m_value; } +}; + +struct MeshType +{ + enum Value + { + Triangle = 0, + Quad, + Box, + Sphere, + Capsule, + Torus, + Cylinder, + Disc, + Star, + ExpandedStar, + Cog, + + Max + } + m_value; + + inline MeshType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +//TODO : Add other Build type +struct TexCoordBuildType +{ + enum Value + { + TriangleDefault = 0, + QuadDefault = 0, + BoxDefault = 0, + SphereDefault = 0, + CapsuleDefault = 0, + TorusDefault = 0, + CylinderDefault = 0, + DiscDefault = 0, + StarDefault = 0, + ExpandedStarDefault = 0, + CogDefault = 0, + + //NEVER FORGET TO INCREMENT THIS WHEN ADDING A VALUE + Max = 1 + } + m_value; + + inline TexCoordBuildType() : m_value(TriangleDefault) {} + inline TexCoordBuildType(Value v) : m_value(v) {} + inline TexCoordBuildType(int v) : m_value((Value)v) {} + inline operator Value() { return m_value; } +}; + +struct MeshFaceType +{ + enum Value + { + BoxFront = 0, + BoxLeft = 1, + BoxBack = 2, + BoxRight = 3, + BoxTop = 4, + BoxBottom = 5, + QuadDefault = 0, + + //NEVER FORGET TO INCREMENT THIS WHEN ADDING A VALUE + Max = 6 + } + m_value; + + inline MeshFaceType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +struct TexCoordPos +{ + enum Value + { + BL, //BottomLeft + BR, //BottomRight + TL, //TopLeft + TR //TopRight + } + m_value; + + inline TexCoordPos(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +class EasyMeshBuildData +{ +public: + EasyMeshBuildData() + { + m_color_a = vec4(0.f, 0.f, 0.f, 1.f); + m_color_b = vec4(0.f, 0.f, 0.f, 1.f); + m_texcoord_offset = vec2(0.f); + m_texcoord_offset2 = vec2(0.f); + m_texcoord_scale = vec2(1.f); + m_texcoord_scale2 = vec2(1.f); + m_build_flags = 0; + m_i_cmd = 0; + m_exec_nb = -1; + for (int i = 0; i < MeshType::Max; ++i) + { + m_texcoord_build_type[i] = TexCoordBuildType::TriangleDefault; + m_texcoord_build_type2[i] = TexCoordBuildType::TriangleDefault; + } + } + + inline CommandStack &CmdStack() { return m_stack; } + inline int &Cmdi() { return m_i_cmd; } + inline int &CmdExecNb() { return m_exec_nb; } + inline Array &LoopStack(){ return m_loop_stack; } + inline vec4 &ColorA() { return m_color_a; } + inline vec4 &ColorB() { return m_color_b; } + inline vec2 &TexCoordOffset() { return m_texcoord_offset; } + inline vec2 &TexCoordScale() { return m_texcoord_scale; } + inline vec2 &TexCoordOffset2() { return m_texcoord_offset2; } + inline vec2 &TexCoordScale2() { return m_texcoord_scale2; } + + //UV1 + void SetTexCoordBuildType(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type[mt] & 1); } + TexCoordBuildType GetTexCoordBuildType(MeshType mt) + { + uint32_t flag = (uint32_t)((m_texcoord_build_type[mt] & ~(1)) >> 1); + int i = 0; + while (flag >>= 1) + i++; + return TexCoordBuildType(i); + } + void SetTexCoordCustomBuild(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) + { + if (face >= m_texcoord_custom_build[mt].Count()) + m_texcoord_custom_build[mt].Resize(face + 1); + m_texcoord_custom_build[mt][face].m1 = BL; + m_texcoord_custom_build[mt][face].m2 = TR; + m_texcoord_build_type[mt] |= 1; + } + void ClearTexCoordCustomBuild(MeshType mt) { m_texcoord_build_type[mt] &= ~1; } + /* FIXME : Do something better ? */ + vec2 TexCoord(MeshType mt, TexCoordPos tcp, MeshFaceType face) + { + vec2 BL = vec2(0.f); + vec2 TR = vec2(0.f); + if (m_texcoord_build_type[mt] & 1 && face < m_texcoord_custom_build[mt].Count()) + { + BL = m_texcoord_custom_build[mt][face].m1; + TR = m_texcoord_custom_build[mt][face].m2; + } + else + { + /* unused for now, but will be if new BuildType are added. */ + TexCoordBuildType tcbt = GetTexCoordBuildType(mt); + UNUSED(tcbt); + if (mt == MeshType::Triangle) + mt = mt; + else if (mt == MeshType::Quad) + { + //There's nothin' else than QuadDefault + BL = vec2(0.f); + TR = vec2(1.f); + } + else if (mt == MeshType::Box) + { + vec2 data[][2] = + { //TexCoordBuildType::BoxDefault + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f, .5f), vec2(.5f, 1.f) }, + { vec2(.5f, .5f), vec2(1.f, 1.f) } + }; + BL = data[face][0]; //[tcbt] + TR = data[face][1]; //[tcbt] + } + else if (mt == MeshType::Sphere) + mt = mt; + else if (mt == MeshType::Capsule) + mt = mt; + else if (mt == MeshType::Torus) + mt = mt; + else if (mt == MeshType::Cylinder) + mt = mt; + else if (mt == MeshType::Disc) + mt = mt; + else if (mt == MeshType::Star) + mt = mt; + else if (mt == MeshType::ExpandedStar) + mt = mt; + else if (mt == MeshType::Cog) + mt = mt; + } + + vec2 res = vec2(.0f); + if (tcp == TexCoordPos::BL) + res = BL; + else if (tcp == TexCoordPos::BR) + res = vec2(TR.x, BL.y); + else if (tcp == TexCoordPos::TL) + res = vec2(BL.x, TR.y); + else if (tcp == TexCoordPos::TR) + res = TR; + + return res * m_texcoord_scale + m_texcoord_offset2; + } + + //UV2 + void SetTexCoordBuildType2(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type2[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type2[mt] & 1); } + TexCoordBuildType GetTexCoordBuildType2(MeshType mt) + { + uint32_t flag = ((m_texcoord_build_type2[mt] & ~(1)) >> 1); + int i = 0; + while (flag >>= 1) + i++; + return TexCoordBuildType(i); + } + void SetTexCoordCustomBuild2(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) + { + if (face >= m_texcoord_custom_build2[mt].Count()) + m_texcoord_custom_build2[mt].Resize(face + 1); + m_texcoord_custom_build2[mt][face].m1 = BL; + m_texcoord_custom_build2[mt][face].m2 = TR; + m_texcoord_build_type2[mt] |= 1; + } + void ClearTexCoordCustomBuild2(MeshType mt) { m_texcoord_build_type2[mt] &= ~1; } + vec2 TexCoord2(MeshType mt, TexCoordPos tcp, MeshFaceType face) + { + vec2 BL = vec2(0.f); + vec2 TR = vec2(0.f); + if (m_texcoord_build_type2[mt] & 1 && face < m_texcoord_custom_build2[mt].Count()) + { + BL = m_texcoord_custom_build2[mt][face].m1; + TR = m_texcoord_custom_build2[mt][face].m2; + } + else + { + TexCoordBuildType tcbt = GetTexCoordBuildType2(mt); + UNUSED(tcbt); + if (mt == MeshType::Triangle) + mt = mt; + else if (mt == MeshType::Quad) + { + //There's nothin' else than QuadDefault + BL = vec2(0.f); + TR = vec2(1.f); + } + else if (mt == MeshType::Box) + { + vec2 data[][2] = + { //TexCoordBuildType::BoxDefault + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f, .5f), vec2(.5f, 1.f) }, + { vec2(.5f, .5f), vec2(1.f, 1.f) } + }; + BL = data[face][0]; //[tcbt] + TR = data[face][1]; //[tcbt] + } + else if (mt == MeshType::Sphere) + mt = mt; + else if (mt == MeshType::Capsule) + mt = mt; + else if (mt == MeshType::Torus) + mt = mt; + else if (mt == MeshType::Cylinder) + mt = mt; + else if (mt == MeshType::Disc) + mt = mt; + else if (mt == MeshType::Star) + mt = mt; + else if (mt == MeshType::ExpandedStar) + mt = mt; + else if (mt == MeshType::Cog) + mt = mt; + } + + vec2 res = vec2(.0f); + if (tcp == TexCoordPos::BL) + res = BL; + else if (tcp == TexCoordPos::BR) + res = vec2(TR.x, BL.y); + else if (tcp == TexCoordPos::TL) + res = vec2(BL.x, TR.y); + else if (tcp == TexCoordPos::TR) + res = TR; + + return res * m_texcoord_scale + m_texcoord_offset2; + } + + inline bool IsEnabled(MeshBuildOperation mbo) { return (m_build_flags & mbo) != 0; } + inline void Enable(MeshBuildOperation mbo) { m_build_flags |= mbo; } + inline void Disable(MeshBuildOperation mbo) { m_build_flags &= ~mbo; } + inline void Toggle(MeshBuildOperation mbo) { m_build_flags ^= mbo; } + inline void Set(MeshBuildOperation mbo, bool value) { if (value) Enable(mbo); else Disable(mbo); } + +public: + CommandStack m_stack; + int m_i_cmd; + int m_exec_nb; + Array m_loop_stack; + vec4 m_color_a; + vec4 m_color_b; + vec2 m_texcoord_offset; + vec2 m_texcoord_offset2; + vec2 m_texcoord_scale; + vec2 m_texcoord_scale2; + Array m_texcoord_custom_build[MeshType::Max]; + Array m_texcoord_custom_build2[MeshType::Max]; + uint32_t m_texcoord_build_type[MeshType::Max]; + uint32_t m_texcoord_build_type2[MeshType::Max]; + uint32_t m_build_flags; +}; + +/* A safe enum for VertexDictionnary operations. */ +struct VDictType +{ + enum Value + { + DoesNotExist=-3, + Alone=-2, + Master=-1 + } + m_value; + + inline VDictType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +/* TODO : replace VDict by a proper Half-edge system */ +//a class whose goal is to keep a list of the adjacent vertices for mesh operations purposes +class VertexDictionnary +{ +public: + int FindVertexMaster(const int search_idx); + bool FindMatchingVertices(const int search_idx, Array &matching_ids); + bool FindConnectedVertices(const int search_idx, const Array &tri_list, const int tri0, Array &connected_vert, Array const *ignored_tri = nullptr); + bool FindConnectedTriangles(const int search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); + bool FindConnectedTriangles(const ivec2 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); + bool FindConnectedTriangles(const ivec3 &search_idx, const Array &tri_list, const int tri0, Array &connected_tri, Array const *ignored_tri = nullptr); + void AddVertex(int vert_id, vec3 vert_coord); + void RemoveVertex(int vert_id); + bool GetMasterList(Array &ret_master_list) { ret_master_list = master_list; return ret_master_list.Count() > 0; } + void Clear() { vertex_list.Empty(); } +private: + // + Array vertex_list; + //List of the master_ vertices + Array master_list; +}; + +} /* namespace lol */ + +#endif /* __EASYMESHBUILD_EASYMESHBUILD_H__ */ + diff --git a/src/easymesh/easymeshrender.cpp b/src/easymesh/easymeshrender.cpp new file mode 100644 index 00000000..6e5f5c21 --- /dev/null +++ b/src/easymesh/easymeshrender.cpp @@ -0,0 +1,426 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The EasyMesh class +// ------------------ +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" + +namespace lol +{ + +LOLFX_RESOURCE_DECLARE(shiny); +LOLFX_RESOURCE_DECLARE(shinyflat); +LOLFX_RESOURCE_DECLARE(shinydebugwireframe); +LOLFX_RESOURCE_DECLARE(shinydebuglighting); +LOLFX_RESOURCE_DECLARE(shinydebugnormal); +LOLFX_RESOURCE_DECLARE(shinydebugUV); +LOLFX_RESOURCE_DECLARE(shiny_SK); + +//----------------------------------------------------------------------------- +GpuShaderData::GpuShaderData() +{ + 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; +} + +//----------------------------------------------------------------------------- +GpuShaderData::~GpuShaderData() +{ + m_shader_uniform.Empty(); + m_shader_attrib.Empty(); +} + +//----------------------------------------------------------------------------- +void GpuShaderData::AddUniform(const lol::String &new_uniform) +{ + m_shader_uniform.Push(new_uniform, m_shader->GetUniformLocation(new_uniform.C())); +} + +//----------------------------------------------------------------------------- +void GpuShaderData::AddAttribute(VertexUsage usage, int index) +{ + m_shader_attrib.Push(m_shader->GetAttribLocation(usage, index)); +} + +//----------------------------------------------------------------------------- +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 nullptr; +} + +//----------------------------------------------------------------------------- +ShaderAttrib const *GpuShaderData::GetAttribute(VertexUsage usage, int index) +{ + for (int i = 0; i < m_shader_attrib.Count(); ++i) + if (m_shader_attrib[i].GetUsage() == usage && m_shader_attrib[i].GetIndex() == index) + return &m_shader_attrib[i]; + return nullptr; +} + +//----------------------------------------------------------------------------- +DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode) +{ + bool with_UV = false; + m_render_mode = render_mode; + m_vert_decl_flags = (1 << VertexUsage::Position) | + (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color); + + if (render_mode == DebugRenderMode::Default) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny)); + else if (render_mode == DebugRenderMode::Flat) + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinyflat)); + 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 |= (1 << VertexUsage::TexCoord); + with_UV = true; + } + StoreUniformNames(); + SetupDefaultData(with_UV); +} + +//----------------------------------------------------------------------------- +DefaultShaderData::DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV) + : GpuShaderData(vert_decl_flags, shader, DebugRenderMode::Default) +{ + StoreUniformNames(); + SetupDefaultData(with_UV); +} + +static const String DefaultUniforms[7] = +{ + String("u_Lights"), + String("in_ModelView"), + String("in_View"), + String("in_Inv_View"), + String("in_Proj"), + String("in_NormalMat"), + String("in_Damage") +}; +//----------------------------------------------------------------------------- +void DefaultShaderData::StoreUniformNames() +{ +} + +//----------------------------------------------------------------------------- +void DefaultShaderData::SetupDefaultData(bool with_UV) +{ + UNUSED(with_UV); + for (int i = 0; i < 7; i++) + AddUniform(DefaultUniforms[i]); +} + +//----------------------------------------------------------------------------- +void DefaultShaderData::SetupShaderDatas(mat4 const &model) +{ + mat4 proj = g_scene->GetCamera()->GetProjection(); + mat4 view = g_scene->GetCamera()->GetView(); + mat4 modelview = view * model; + mat3 normalmat = transpose(inverse(mat3(modelview))); + /* FIXME: this should be hidden in the shader */ + Array const &lights = g_scene->GetLights(); + Array light_data; + //This is not very nice, but necessary for emscripten WebGL generation. + float f = 0.f; + + /* FIXME: the 4th component of the position can be used for other things */ + /* FIXME: GetUniform("blabla") is costly */ + for (int i = 0; i < lights.Count(); ++i) + light_data << lights[i]->GetPosition() << lights[i]->GetColor(); + while (light_data.Count() < 8) + light_data << vec4::zero << vec4::zero; + + int i = 0; + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), light_data); + + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), modelview); + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), view); + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), inverse(view)); + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), proj); + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), normalmat); + m_shader->SetUniform(*GetUniform(DefaultUniforms[i++]), f); +} + +//----------------------------------------------------------------------------- +GpuEasyMeshData::GpuEasyMeshData() +{ + m_vertexcount = 0; + m_indexcount = 0; + m_ibo = nullptr; +} + +//----------------------------------------------------------------------------- +GpuEasyMeshData::~GpuEasyMeshData() +{ + m_gpudatas.Empty(); + m_vdatas.Empty(); + if (m_ibo) + delete(m_ibo); +} + +#define BUILD_VFLAG(bool_value, flag_value, check_flag) \ + bool bool_value = (check_flag & (1 << flag_value)) != 0; \ + check_flag &= ~(1 << flag_value); +#define BUILD_VFLAG_OR(bool_value, flag_value, check_flag) \ + bool_value = (bool_value || (check_flag & (1 << flag_value)) != 0); \ + check_flag &= ~(1 << flag_value); +#define BUILD_VFLAG_COUNT(bool_value, flag_value, check_flag, count_value) \ + BUILD_VFLAG(bool_value, flag_value, check_flag) \ + count_value += (int)bool_value; + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::AddGpuData(GpuShaderData* gpudata, EasyMesh* src_mesh) +{ + uint16_t vflags = gpudata->m_vert_decl_flags; + + BUILD_VFLAG(has_position, VertexUsage::Position, vflags); + BUILD_VFLAG(has_normal, VertexUsage::Normal, vflags); + BUILD_VFLAG(has_color, VertexUsage::Color, vflags); + BUILD_VFLAG(has_texcoord, VertexUsage::TexCoord, vflags); + BUILD_VFLAG_OR(has_texcoord, VertexUsage::TexCoordExt, vflags); + ASSERT(!vflags, "Vertex Usage setup is not implemented for %s, feel free to do so.", + VertexUsage::GetNameList(vflags).C()); + + if (has_position) gpudata->AddAttribute(VertexUsage::Position, 0); + if (has_normal) gpudata->AddAttribute(VertexUsage::Normal, 0); + if (has_color) gpudata->AddAttribute(VertexUsage::Color, 0); + if (has_texcoord) gpudata->AddAttribute(VertexUsage::TexCoord, 0); + + 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(); + } + + //init to a minimum of gpudata->m_render_mode size + if (m_gpudatas.Count() <= gpudata->m_render_mode) + { + int i = m_gpudatas.Count(); + int max = gpudata->m_render_mode + 1; + m_gpudatas.Reserve(max); + for (; i < max; i++) + m_gpudatas << nullptr; + } + m_gpudatas[gpudata->m_render_mode] = gpudata; +} + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::SetupVertexData(uint16_t vflags, EasyMesh* src_mesh) +{ + for (int i = 0; i < m_vdatas.Count(); ++i) + if (m_vdatas[i].m1 == vflags) + return; + + VertexDeclaration* new_vdecl = nullptr; + VertexBuffer* new_vbo = nullptr; + void *vbo_data = nullptr; + int vbo_bytes = 0; + +#define COPY_VBO \ + vbo_data = &vertexlist[0]; \ + vbo_bytes = vertexlist.Bytes(); \ + m_vertexcount = vertexlist.Count(); \ + new_vbo = new VertexBuffer(vbo_bytes); \ + void *mesh = new_vbo->Lock(0, 0); \ + memcpy(mesh, vbo_data, vbo_bytes); \ + new_vbo->Unlock(); + + //Keep a count of the flags + uint16_t saveflags = vflags; + int flagnb = 0; + BUILD_VFLAG_COUNT(has_position, VertexUsage::Position, saveflags, flagnb); + BUILD_VFLAG_COUNT(has_normal, VertexUsage::Normal, saveflags, flagnb); + BUILD_VFLAG_COUNT(has_color, VertexUsage::Color, saveflags, flagnb); + BUILD_VFLAG_COUNT(has_texcoord, VertexUsage::TexCoord, saveflags, flagnb); + BUILD_VFLAG_COUNT(has_texcoordExt,VertexUsage::TexCoordExt, saveflags, flagnb); + ASSERT(!saveflags, "Vertex Declaration setup is not implemented for %s, feel free to do so.", + VertexUsage::GetNameList(vflags).C()); + + if (flagnb == 5 && has_position && has_normal && has_color && has_texcoord && has_texcoordExt) + { + 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].m_coord, + src_mesh->m_vert[i].m_normal, + (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), + src_mesh->m_vert[i].m_texcoord); + COPY_VBO; + } + else if (flagnb == 4 && has_position && has_normal && has_color && has_texcoord) + { + 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].m_coord, + src_mesh->m_vert[i].m_normal, + (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), + src_mesh->m_vert[i].m_texcoord.xy); + COPY_VBO; + } + else if (flagnb == 4 && has_position && has_color && has_texcoord && has_texcoordExt) + { + new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::Color, VertexUsage::TexCoord)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_color, src_mesh->m_vert[i].m_texcoord); + COPY_VBO; + } + else if (flagnb == 3 && has_position && has_normal && has_color) + { + 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].m_coord, + src_mesh->m_vert[i].m_normal, + (u8vec4)(src_mesh->m_vert[i].m_color * 255.f)); + COPY_VBO; + } + else if (flagnb == 3 && has_position && has_texcoord && has_texcoordExt) + { + new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::TexCoord)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord); + COPY_VBO; + } + else if (flagnb == 2 && has_position && has_texcoord) + { + new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::TexCoord)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord.xy); + COPY_VBO; + } + else if (flagnb == 2 && has_position && has_color) + { + new_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position, VertexUsage::Color)); + + Array vertexlist; + for (int i = 0; i < src_mesh->m_vert.Count(); i++) + vertexlist.Push(src_mesh->m_vert[i].m_coord, (u8vec4)(src_mesh->m_vert[i].m_color * 255.f)); + COPY_VBO; + } + else + ASSERT(0, "Vertex Declaration combination is not implemented for %s, feel free to do so.", + VertexUsage::GetNameList(vflags).C()); + + m_vdatas.Push(vflags, new_vdecl, new_vbo); +} + +//----------------------------------------------------------------------------- +void GpuEasyMeshData::RenderMeshData(mat4 const &model, int render_mode) +{ + ASSERT(0 <= render_mode && render_mode < m_gpudatas.Count(), "render mode is not in the defined range"); + ASSERT(m_gpudatas[render_mode], "gpu datas for this render mode don't exist"); + GpuShaderData& gpu_sd = *(m_gpudatas[render_mode]); + + 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(); + + BUILD_VFLAG(has_position, VertexUsage::Position, vflags); + BUILD_VFLAG(has_normal, VertexUsage::Normal, vflags); + BUILD_VFLAG(has_color, VertexUsage::Color, vflags); + BUILD_VFLAG(has_texcoord, VertexUsage::TexCoord, vflags); + BUILD_VFLAG_OR(has_texcoord,VertexUsage::TexCoordExt, vflags); + ASSERT(!vflags, "Vertex Stream setup is not implemented for %s, feel free to do so.", + VertexUsage::GetNameList(vflags).C()); + + int idx = 0; + ShaderAttrib Attribs[4] = { lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib() }; + + if (has_position) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Position, 0); + if (has_normal) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Normal, 0); + if (has_color) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::Color, 0); + if (has_texcoord) Attribs[idx++] = *gpu_sd.GetAttribute(VertexUsage::TexCoord, 0); + + vdecl->SetStream(vbo, Attribs[0], Attribs[1], Attribs[2], Attribs[3]); + + m_ibo->Bind(); + vdecl->DrawIndexedElements(MeshPrimitive::Triangles, 0, 0, m_vertexcount, 0, m_indexcount); + m_ibo->Unbind(); + vdecl->Unbind(); +} + +} /* namespace lol */ diff --git a/src/easymesh/easymeshrender.h b/src/easymesh/easymeshrender.h new file mode 100644 index 00000000..7f6002ac --- /dev/null +++ b/src/easymesh/easymeshrender.h @@ -0,0 +1,142 @@ +// +// Lol Engine +// +// Copyright: (c) 2009-2013 Benjamin "Touky" Huet +// (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The EasyMesh class +// ------------------ +// + +#if !defined __EASYMESHRENDER_EASYMESHRENDER_H__ +#define __EASYMESHRENDER_EASYMESHRENDER_H__ + +namespace lol +{ + +//Utility enum for renderers +struct MeshRender +{ + enum Value + { + NeedData, + NeedConvert, + CanRender, + IgnoreRender, + + Max + } + m_value; + + inline MeshRender(Value v) : m_value(v) {} + inline MeshRender() : m_value(NeedData) {} + inline operator Value() { return m_value; } +}; + +//Vertex datas for easymesh vertex list. +//TODO : +struct VertexData +{ + vec3 m_coord; + vec3 m_normal; + vec4 m_color; + vec4 m_texcoord; + ivec4 m_bone_id; + vec4 m_bone_weight; + + VertexData(vec3 new_coord = vec3(0.f), + vec3 new_normal = vec3(0.f, 1.f, 0.f), + vec4 new_color = vec4(0.f), + vec4 new_texcoord = vec4(0.f), + ivec4 new_bone_id = ivec4(0), + vec4 new_bone_weight= vec4(0.f)) + { + m_coord = new_coord; + m_normal = new_normal; + m_color = new_color; + m_texcoord = new_texcoord; + m_bone_id = new_bone_id; + m_bone_weight = new_bone_weight; + } +}; + +//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); + virtual ~GpuShaderData(); + //-- + void AddUniform(const lol::String &new_uniform); + void AddAttribute(VertexUsage usage, int index); + ShaderUniform const *GetUniform(const lol::String &uniform); + ShaderAttrib const *GetAttribute(VertexUsage usage, int index); + //-- + virtual void SetupShaderDatas(mat4 const &model) { UNUSED(model); } + //-- + +protected: + uint16_t m_vert_decl_flags; + Shader* m_shader; + int 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); + virtual ~DefaultShaderData() {} + void StoreUniformNames(); + //--- + void SetupDefaultData(bool with_UV); + virtual void SetupShaderDatas(mat4 const &model); + //-- + Array m_uniform_names; +}; + +class GpuEasyMeshData +{ + friend class EasyMesh; + +public: + //--- + GpuEasyMeshData(); + ~GpuEasyMeshData(); + //--- + void AddGpuData(GpuShaderData* gpudata, class EasyMesh* src_mesh); + void RenderMeshData(mat4 const &model, int render_mode=Video::GetDebugRenderMode()); + bool HasData(int render_mode) { return (0 <= render_mode && render_mode < m_gpudatas.Count() && !!m_gpudatas[render_mode]); } + +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; +}; + +} /* namespace lol */ + +#endif /* __EASYMESHRENDER_EASYMESHRENDER_H__ */ + diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 313471e8..520053d7 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -117,6 +117,8 @@ + + @@ -233,6 +235,7 @@ + @@ -241,6 +244,8 @@ + + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index 49bfb640..78712f7c 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -328,6 +328,12 @@ platform\nacl + + easymesh + + + easymesh + @@ -645,6 +651,13 @@ platform\nacl + + easymesh + + + + easymesh + diff --git a/test/data/mesh-buffer.txt b/test/data/mesh-buffer.txt index 57ff86b7..d87376d4 100644 --- a/test/data/mesh-buffer.txt +++ b/test/data/mesh-buffer.txt @@ -50,7 +50,6 @@ custom setmesh " sc#00f tqw lp 5[tz 11 [lp 6 [tx 5 ty 5 ab 10 ]]] tz -22 - //[sc#66f afcb(10) .25tx0]csgs[sc#fff afcb(10).25t(2)][[sc#6f6 afcb(7).25]csgs[sc#fff afcb(7).25t(1.5)]][[sc#f44 asph4 12t(-2.5)]csga[sc#fff afcb(7).25t(1.4)]csgs[sc#fff afcb(7).25t(2.5)]][[sc#ff0 ato6 2.5 1.2rx90tz-1.25tx-.9][sc#ff0 ab.5 2.1 .5dup[rz90sx.5ty-.8tx-.28]ty.55tx.25tz-.4taz1 1sy.8sx.8ty-.55tx-.25tz.4tz-1.2tx1.2]tz1.25tx1.25dup[sx-1ry90]tz-1.25tx-1.25] "