| @@ -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 \ | |||
| @@ -0,0 +1,87 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||
| // (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // 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<int, int, int> m_commands; | |||
| Array<float> m_floats; | |||
| Array<int> 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__ */ | |||
| @@ -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<Light *> const &lights = g_scene->GetLights(); | |||
| Array<vec4> 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<uint16_t> 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<vec3,vec3,u8vec4,vec4>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color, | |||
| VertexUsage::TexCoord)); | |||
| Array<vec3, vec3, u8vec4, vec4> 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<vec3,vec3,u8vec4,vec2>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color, | |||
| VertexUsage::TexCoord)); | |||
| Array<vec3, vec3, u8vec4, vec2> 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<vec3,vec4,vec4>(VertexUsage::Position, VertexUsage::Color, VertexUsage::TexCoord)); | |||
| Array<vec3, vec4, vec4> 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<vec3,vec3,u8vec4>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color)); | |||
| Array<vec3,vec3,u8vec4> 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<vec3,vec4>(VertexUsage::Position, VertexUsage::TexCoord)); | |||
| Array<vec3, vec4> 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<vec3,vec2>(VertexUsage::Position, VertexUsage::TexCoord)); | |||
| Array<vec3, vec2> 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<vec3,u8vec4>(VertexUsage::Position, VertexUsage::Color)); | |||
| Array<vec3, u8vec4> 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<int> &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<uint16_t> &tri_list, const int tri0, Array<int> &connected_vert, Array<int> const *ignored_tri) | |||
| { | |||
| Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri) | |||
| { | |||
| int needed_validation = 0; | |||
| Array<int> 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) | |||
| { | |||
| @@ -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<int, int, int> m_commands; | |||
| Array<float> m_floats; | |||
| Array<int> 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 : <COORD, NORM, COLOR, UV> | |||
| 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<lol::String, ShaderUniform> m_shader_uniform; | |||
| Array<ShaderAttrib> 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<String> 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<GpuShaderData*> m_gpudatas; | |||
| //uint16_t are the vdecl/vbo flags to avoid copy same vdecl several times. | |||
| Array<uint16_t, VertexDeclaration*, | |||
| VertexBuffer*> 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<int, int> &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<int, int> 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<vec2, vec2> m_texcoord_custom_build[MeshType::Max]; | |||
| Array<vec2, vec2> 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<int> &matching_ids); | |||
| bool FindConnectedVertices(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_vert, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const ivec2 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const ivec3 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| void AddVertex(int vert_id, vec3 vert_coord); | |||
| void RemoveVertex(int vert_id); | |||
| bool GetMasterList(Array<int> &ret_master_list) { ret_master_list = master_list; return ret_master_list.Count() > 0; } | |||
| void Clear() { vertex_list.Empty(); } | |||
| private: | |||
| //<VertexId, VertexLocation, VertexMasterId> | |||
| Array<int, vec3, int> vertex_list; | |||
| //List of the master_ vertices | |||
| Array<int> master_list; | |||
| }; | |||
| struct Axis | |||
| { | |||
| enum Value | |||
| @@ -1030,6 +427,7 @@ public: | |||
| private: | |||
| class EasyMeshBuildData* m_build_data; | |||
| }; | |||
| } /* namespace lol */ | |||
| #endif /* __EASYMESH_EASYMESH_H__ */ | |||
| @@ -0,0 +1,216 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // (c) 2009-2013 Cédric Lecacheur <jordx@free.fr> | |||
| // (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||
| // 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<int> &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<uint16_t> &tri_list, const int tri0, Array<int> &connected_vert, Array<int> const *ignored_tri) | |||
| { | |||
| Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> 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<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri) | |||
| { | |||
| int needed_validation = 0; | |||
| Array<int> 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 */ | |||
| @@ -0,0 +1,455 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||
| // (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // (c) 2009-2013 Cédric Lecacheur <jordx@free.fr> | |||
| // 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<int, int> &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<int, int> 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<vec2, vec2> m_texcoord_custom_build[MeshType::Max]; | |||
| Array<vec2, vec2> 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<int> &matching_ids); | |||
| bool FindConnectedVertices(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_vert, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const ivec2 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| bool FindConnectedTriangles(const ivec3 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri = nullptr); | |||
| void AddVertex(int vert_id, vec3 vert_coord); | |||
| void RemoveVertex(int vert_id); | |||
| bool GetMasterList(Array<int> &ret_master_list) { ret_master_list = master_list; return ret_master_list.Count() > 0; } | |||
| void Clear() { vertex_list.Empty(); } | |||
| private: | |||
| //<VertexId, VertexLocation, VertexMasterId> | |||
| Array<int, vec3, int> vertex_list; | |||
| //List of the master_ vertices | |||
| Array<int> master_list; | |||
| }; | |||
| } /* namespace lol */ | |||
| #endif /* __EASYMESHBUILD_EASYMESHBUILD_H__ */ | |||
| @@ -0,0 +1,426 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // (c) 2009-2013 Cédric Lecacheur <jordx@free.fr> | |||
| // (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||
| // 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<Light *> const &lights = g_scene->GetLights(); | |||
| Array<vec4> 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<uint16_t> 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<vec3,vec3,u8vec4,vec4>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color, | |||
| VertexUsage::TexCoord)); | |||
| Array<vec3, vec3, u8vec4, vec4> 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<vec3,vec3,u8vec4,vec2>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color, | |||
| VertexUsage::TexCoord)); | |||
| Array<vec3, vec3, u8vec4, vec2> 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<vec3,vec4,vec4>(VertexUsage::Position, VertexUsage::Color, VertexUsage::TexCoord)); | |||
| Array<vec3, vec4, vec4> 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<vec3,vec3,u8vec4>( | |||
| VertexUsage::Position, | |||
| VertexUsage::Normal, | |||
| VertexUsage::Color)); | |||
| Array<vec3,vec3,u8vec4> 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<vec3,vec4>(VertexUsage::Position, VertexUsage::TexCoord)); | |||
| Array<vec3, vec4> 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<vec3,vec2>(VertexUsage::Position, VertexUsage::TexCoord)); | |||
| Array<vec3, vec2> 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<vec3,u8vec4>(VertexUsage::Position, VertexUsage::Color)); | |||
| Array<vec3, u8vec4> 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 */ | |||
| @@ -0,0 +1,142 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||
| // (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // (c) 2009-2013 Cédric Lecacheur <jordx@free.fr> | |||
| // 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 : <COORD, NORM, COLOR, UV> | |||
| 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<lol::String, ShaderUniform> m_shader_uniform; | |||
| Array<ShaderAttrib> 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<String> 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<GpuShaderData*> m_gpudatas; | |||
| //uint16_t are the vdecl/vbo flags to avoid copy same vdecl several times. | |||
| Array<uint16_t, VertexDeclaration*, | |||
| VertexBuffer*> 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__ */ | |||
| @@ -117,6 +117,8 @@ | |||
| <ClCompile Include="easymesh\csgbsp.cpp" /> | |||
| <ClCompile Include="easymesh\easymesh-compiler.cpp" /> | |||
| <ClCompile Include="easymesh\easymesh.cpp" /> | |||
| <ClCompile Include="easymesh\easymeshbuild.cpp" /> | |||
| <ClCompile Include="easymesh\easymeshrender.cpp" /> | |||
| <ClCompile Include="eglapp.cpp" /> | |||
| <ClCompile Include="emitter.cpp" /> | |||
| <ClCompile Include="entity.cpp" /> | |||
| @@ -233,6 +235,7 @@ | |||
| <ClInclude Include="application\application.h" /> | |||
| <ClInclude Include="audio.h" /> | |||
| <ClInclude Include="camera.h" /> | |||
| <ClInclude Include="commandstack.h" /> | |||
| <ClInclude Include="core.h" /> | |||
| <ClInclude Include="debug\fps.h" /> | |||
| <ClInclude Include="debug\record.h" /> | |||
| @@ -241,6 +244,8 @@ | |||
| <ClInclude Include="easymesh\csgbsp.h" /> | |||
| <ClInclude Include="easymesh\easymesh-compiler.h" /> | |||
| <ClInclude Include="easymesh\easymesh.h" /> | |||
| <ClInclude Include="easymesh\easymeshbuild.h" /> | |||
| <ClInclude Include="easymesh\easymeshrender.h" /> | |||
| <ClInclude Include="eglapp.h" /> | |||
| <ClInclude Include="emitter.h" /> | |||
| <ClInclude Include="entity.h" /> | |||
| @@ -328,6 +328,12 @@ | |||
| <ClCompile Include="platform\nacl\opengl_context.cpp"> | |||
| <Filter>platform\nacl</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="easymesh\easymeshrender.cpp"> | |||
| <Filter>easymesh</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="easymesh\easymeshbuild.cpp"> | |||
| <Filter>easymesh</Filter> | |||
| </ClCompile> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ClInclude Include="debug\fps.h"> | |||
| @@ -645,6 +651,13 @@ | |||
| <ClInclude Include="platform\nacl\opengl_context_ptrs.h"> | |||
| <Filter>platform\nacl</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="easymesh\easymeshrender.h"> | |||
| <Filter>easymesh</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="commandstack.h" /> | |||
| <ClInclude Include="easymesh\easymeshbuild.h"> | |||
| <Filter>easymesh</Filter> | |||
| </ClInclude> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <LolFxCompile Include="gpu\emptymaterial.lolfx"> | |||
| @@ -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] | |||
| " | |||