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