Просмотр исходного кода

EZMesh : Some files splitup

undefined
Benjamin ‘Touky’ Huet Sam Hocevar <sam@hocevar.net> 11 лет назад
Родитель
Сommit
2b6b50aa26
11 измененных файлов: 1352 добавлений и 1197 удалений
  1. +3
    -0
      src/Makefile.am
  2. +87
    -0
      src/commandstack.h
  3. +0
    -589
      src/easymesh/easymesh.cpp
  4. +5
    -607
      src/easymesh/easymesh.h
  5. +216
    -0
      src/easymesh/easymeshbuild.cpp
  6. +455
    -0
      src/easymesh/easymeshbuild.h
  7. +426
    -0
      src/easymesh/easymeshrender.cpp
  8. +142
    -0
      src/easymesh/easymeshrender.h
  9. +5
    -0
      src/lolcore.vcxproj
  10. +13
    -0
      src/lolcore.vcxproj.filters
  11. +0
    -1
      test/data/mesh-buffer.txt

+ 3
- 0
src/Makefile.am Просмотреть файл

@@ -64,6 +64,9 @@ liblolcore_sources = \
application/application.cpp application/application.h \
eglapp.cpp eglapp.h \
\
commandstack.h \
easymesh/easymeshbuild.cpp easymesh/easymeshbuild.h \
easymesh/easymeshrender.cpp easymesh/easymeshrender.h \
easymesh/easymesh.cpp easymesh/easymesh.h \
easymesh/csgbsp.cpp easymesh/csgbsp.h \
easymesh/shiny.lolfx easymesh/shinyflat.lolfx \


+ 87
- 0
src/commandstack.h Просмотреть файл

@@ -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__ */

+ 0
- 589
src/easymesh/easymesh.cpp Просмотреть файл

@@ -22,409 +22,9 @@
#include "core.h"
#include "easymesh/easymesh-compiler.h"

LOLFX_RESOURCE_DECLARE(shiny);
LOLFX_RESOURCE_DECLARE(shinyflat);
LOLFX_RESOURCE_DECLARE(shinydebugwireframe);
LOLFX_RESOURCE_DECLARE(shinydebuglighting);
LOLFX_RESOURCE_DECLARE(shinydebugnormal);
LOLFX_RESOURCE_DECLARE(shinydebugUV);
LOLFX_RESOURCE_DECLARE(shiny_SK);

namespace lol
{


//-----------------------------------------------------------------------------
GpuShaderData::GpuShaderData()
{
m_render_mode = DebugRenderMode::Default;
}

//-----------------------------------------------------------------------------
GpuShaderData::GpuShaderData(uint16_t vert_decl_flags, Shader* shader, DebugRenderMode render_mode)
{
m_render_mode = render_mode;
m_shader = shader;
m_vert_decl_flags = vert_decl_flags;
}

//-----------------------------------------------------------------------------
GpuShaderData::~GpuShaderData()
{
m_shader_uniform.Empty();
m_shader_attrib.Empty();
}

//-----------------------------------------------------------------------------
void GpuShaderData::AddUniform(const lol::String &new_uniform)
{
m_shader_uniform.Push(new_uniform, m_shader->GetUniformLocation(new_uniform.C()));
}

//-----------------------------------------------------------------------------
void GpuShaderData::AddAttribute(VertexUsage usage, int index)
{
m_shader_attrib.Push(m_shader->GetAttribLocation(usage, index));
}

//-----------------------------------------------------------------------------
ShaderUniform const *GpuShaderData::GetUniform(const lol::String &uniform)
{
for (int i = 0; i < m_shader_uniform.Count(); ++i)
if (m_shader_uniform[i].m1 == uniform)
return &m_shader_uniform[i].m2;
return nullptr;
}

//-----------------------------------------------------------------------------
ShaderAttrib const *GpuShaderData::GetAttribute(VertexUsage usage, int index)
{
for (int i = 0; i < m_shader_attrib.Count(); ++i)
if (m_shader_attrib[i].GetUsage() == usage && m_shader_attrib[i].GetIndex() == index)
return &m_shader_attrib[i];
return nullptr;
}

//-----------------------------------------------------------------------------
DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode)
{
bool with_UV = false;
m_render_mode = render_mode;
m_vert_decl_flags = (1 << VertexUsage::Position) |
(1 << VertexUsage::Normal) |
(1 << VertexUsage::Color);

if (render_mode == DebugRenderMode::Default)
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny));
else if (render_mode == DebugRenderMode::Flat)
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinyflat));
else if (render_mode == DebugRenderMode::Wireframe)
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugwireframe));
else if (render_mode == DebugRenderMode::Lighting)
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebuglighting));
else if (render_mode == DebugRenderMode::Normal)
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugnormal));
else if (render_mode == DebugRenderMode::UV)
{
m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV));
m_vert_decl_flags |= (1 << VertexUsage::TexCoord);
with_UV = true;
}
StoreUniformNames();
SetupDefaultData(with_UV);
}

//-----------------------------------------------------------------------------
DefaultShaderData::DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV)
: GpuShaderData(vert_decl_flags, shader, DebugRenderMode::Default)
{
StoreUniformNames();
SetupDefaultData(with_UV);
}

static const String DefaultUniforms[7] =
{
String("u_Lights"),
String("in_ModelView"),
String("in_View"),
String("in_Inv_View"),
String("in_Proj"),
String("in_NormalMat"),
String("in_Damage")
};
//-----------------------------------------------------------------------------
void DefaultShaderData::StoreUniformNames()
{
}

//-----------------------------------------------------------------------------
void DefaultShaderData::SetupDefaultData(bool with_UV)
{
UNUSED(with_UV);
for (int i = 0; i < 7; i++)
AddUniform(DefaultUniforms[i]);
}

//-----------------------------------------------------------------------------
void DefaultShaderData::SetupShaderDatas(mat4 const &model)
{
mat4 proj = g_scene->GetCamera()->GetProjection();
mat4 view = g_scene->GetCamera()->GetView();
mat4 modelview = view * model;
mat3 normalmat = transpose(inverse(mat3(modelview)));
/* FIXME: this should be hidden in the shader */
Array<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)
{


+ 5
- 607
src/easymesh/easymesh.h Просмотреть файл

@@ -15,582 +15,16 @@
// ------------------
//

#include "commandstack.h"
#include "easymeshrender.h"
#include "easymeshbuild.h"

#if !defined __EASYMESH_EASYMESH_H__
#define __EASYMESH_EASYMESH_H__

namespace lol
{

//Utility struct to convert command code to pseudo-bytecode
struct CommandStack
{
private:
Array<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__ */


+ 216
- 0
src/easymesh/easymeshbuild.cpp Просмотреть файл

@@ -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 */

+ 455
- 0
src/easymesh/easymeshbuild.h Просмотреть файл

@@ -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__ */


+ 426
- 0
src/easymesh/easymeshrender.cpp Просмотреть файл

@@ -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 */

+ 142
- 0
src/easymesh/easymeshrender.h Просмотреть файл

@@ -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__ */


+ 5
- 0
src/lolcore.vcxproj Просмотреть файл

@@ -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" />


+ 13
- 0
src/lolcore.vcxproj.filters Просмотреть файл

@@ -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">


+ 0
- 1
test/data/mesh-buffer.txt Просмотреть файл

@@ -50,7 +50,6 @@ custom setmesh "
sc#00f tqw lp 5[tz 11 [lp 6 [tx 5 ty 5 ab 10 ]]] tz -22
//[sc#66f afcb(10) .25tx0]csgs[sc#fff afcb(10).25t(2)][[sc#6f6 afcb(7).25]csgs[sc#fff afcb(7).25t(1.5)]][[sc#f44 asph4 12t(-2.5)]csga[sc#fff afcb(7).25t(1.4)]csgs[sc#fff afcb(7).25t(2.5)]][[sc#ff0 ato6 2.5 1.2rx90tz-1.25tx-.9][sc#ff0 ab.5 2.1 .5dup[rz90sx.5ty-.8tx-.28]ty.55tx.25tz-.4taz1 1sy.8sx.8ty-.55tx-.25tz.4tz-1.2tx1.2]tz1.25tx1.25dup[sx-1ry90]tz-1.25tx-1.25]
"


Загрузка…
Отмена
Сохранить