| @@ -64,6 +64,9 @@ liblolcore_sources = \ | |||||
| application/application.cpp application/application.h \ | application/application.cpp application/application.h \ | ||||
| eglapp.cpp eglapp.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/easymesh.cpp easymesh/easymesh.h \ | ||||
| easymesh/csgbsp.cpp easymesh/csgbsp.h \ | easymesh/csgbsp.cpp easymesh/csgbsp.h \ | ||||
| easymesh/shiny.lolfx easymesh/shinyflat.lolfx \ | 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 "core.h" | ||||
| #include "easymesh/easymesh-compiler.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 | 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() | EasyMesh::EasyMesh() | ||||
| : m_build_data(nullptr) | : m_build_data(nullptr) | ||||
| @@ -696,195 +296,6 @@ bool EasyMesh::SetRender(bool should_render) | |||||
| // "Collisions" functions | // "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) | void EasyMesh::MeshCsg(CSGUsage csg_operation) | ||||
| { | { | ||||
| @@ -15,582 +15,16 @@ | |||||
| // ------------------ | // ------------------ | ||||
| // | // | ||||
| #include "commandstack.h" | |||||
| #include "easymeshrender.h" | |||||
| #include "easymeshbuild.h" | |||||
| #if !defined __EASYMESH_EASYMESH_H__ | #if !defined __EASYMESH_EASYMESH_H__ | ||||
| #define __EASYMESH_EASYMESH_H__ | #define __EASYMESH_EASYMESH_H__ | ||||
| namespace lol | 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. */ | /* A safe enum for MeshCSG operations. */ | ||||
| struct CSGUsage | struct CSGUsage | ||||
| { | { | ||||
| @@ -612,43 +46,6 @@ struct CSGUsage | |||||
| inline operator Value() { return m_value; } | 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 | struct Axis | ||||
| { | { | ||||
| enum Value | enum Value | ||||
| @@ -1030,6 +427,7 @@ public: | |||||
| private: | private: | ||||
| class EasyMeshBuildData* m_build_data; | class EasyMeshBuildData* m_build_data; | ||||
| }; | }; | ||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| #endif /* __EASYMESH_EASYMESH_H__ */ | #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\csgbsp.cpp" /> | ||||
| <ClCompile Include="easymesh\easymesh-compiler.cpp" /> | <ClCompile Include="easymesh\easymesh-compiler.cpp" /> | ||||
| <ClCompile Include="easymesh\easymesh.cpp" /> | <ClCompile Include="easymesh\easymesh.cpp" /> | ||||
| <ClCompile Include="easymesh\easymeshbuild.cpp" /> | |||||
| <ClCompile Include="easymesh\easymeshrender.cpp" /> | |||||
| <ClCompile Include="eglapp.cpp" /> | <ClCompile Include="eglapp.cpp" /> | ||||
| <ClCompile Include="emitter.cpp" /> | <ClCompile Include="emitter.cpp" /> | ||||
| <ClCompile Include="entity.cpp" /> | <ClCompile Include="entity.cpp" /> | ||||
| @@ -233,6 +235,7 @@ | |||||
| <ClInclude Include="application\application.h" /> | <ClInclude Include="application\application.h" /> | ||||
| <ClInclude Include="audio.h" /> | <ClInclude Include="audio.h" /> | ||||
| <ClInclude Include="camera.h" /> | <ClInclude Include="camera.h" /> | ||||
| <ClInclude Include="commandstack.h" /> | |||||
| <ClInclude Include="core.h" /> | <ClInclude Include="core.h" /> | ||||
| <ClInclude Include="debug\fps.h" /> | <ClInclude Include="debug\fps.h" /> | ||||
| <ClInclude Include="debug\record.h" /> | <ClInclude Include="debug\record.h" /> | ||||
| @@ -241,6 +244,8 @@ | |||||
| <ClInclude Include="easymesh\csgbsp.h" /> | <ClInclude Include="easymesh\csgbsp.h" /> | ||||
| <ClInclude Include="easymesh\easymesh-compiler.h" /> | <ClInclude Include="easymesh\easymesh-compiler.h" /> | ||||
| <ClInclude Include="easymesh\easymesh.h" /> | <ClInclude Include="easymesh\easymesh.h" /> | ||||
| <ClInclude Include="easymesh\easymeshbuild.h" /> | |||||
| <ClInclude Include="easymesh\easymeshrender.h" /> | |||||
| <ClInclude Include="eglapp.h" /> | <ClInclude Include="eglapp.h" /> | ||||
| <ClInclude Include="emitter.h" /> | <ClInclude Include="emitter.h" /> | ||||
| <ClInclude Include="entity.h" /> | <ClInclude Include="entity.h" /> | ||||
| @@ -328,6 +328,12 @@ | |||||
| <ClCompile Include="platform\nacl\opengl_context.cpp"> | <ClCompile Include="platform\nacl\opengl_context.cpp"> | ||||
| <Filter>platform\nacl</Filter> | <Filter>platform\nacl</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="easymesh\easymeshrender.cpp"> | |||||
| <Filter>easymesh</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="easymesh\easymeshbuild.cpp"> | |||||
| <Filter>easymesh</Filter> | |||||
| </ClCompile> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <ClInclude Include="debug\fps.h"> | <ClInclude Include="debug\fps.h"> | ||||
| @@ -645,6 +651,13 @@ | |||||
| <ClInclude Include="platform\nacl\opengl_context_ptrs.h"> | <ClInclude Include="platform\nacl\opengl_context_ptrs.h"> | ||||
| <Filter>platform\nacl</Filter> | <Filter>platform\nacl</Filter> | ||||
| </ClInclude> | </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> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <LolFxCompile Include="gpu\emptymaterial.lolfx"> | <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#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] | //[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] | ||||
| " | " | ||||