source: trunk/src/easymesh/easymesh.cpp @ 2816

Last change on this file since 2816 was 2816, checked in by lolbot, 6 years ago

fixed 542 files out of 2754:

  • removed 0 CR characters
  • removed 0 trailing whitespaces
  • replaced 0 tabs with spaces
  • fixed 542 svn:eol-style properties
  • Property svn:eol-style set to LF
File size: 88.1 KB
RevLine 
[2816]1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//            (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
6//            (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
7//   This program is free software; you can redistribute it and/or
8//   modify it under the terms of the Do What The Fuck You Want To
9//   Public License, Version 2, as published by Sam Hocevar. See
10//   http://www.wtfpl.net/ for more details.
11//
12
13//
14// The EasyMesh class
15// ------------------
16//
17
18#if defined HAVE_CONFIG_H
19#   include "config.h"
20#endif
21
22#include "core.h"
23#include "easymesh/easymesh-compiler.h"
24
25LOLFX_RESOURCE_DECLARE(shiny);
26LOLFX_RESOURCE_DECLARE(shinydebugwireframe);
27LOLFX_RESOURCE_DECLARE(shinydebuglighting);
28LOLFX_RESOURCE_DECLARE(shinydebugnormal);
29LOLFX_RESOURCE_DECLARE(shinydebugUV);
30LOLFX_RESOURCE_DECLARE(shiny_SK);
31
32namespace lol
33{
34
35
36//-----------------------------------------------------------------------------
37GpuShaderData::GpuShaderData()
38{
39    m_render_mode = DebugRenderMode::Default;
40}
41
42//-----------------------------------------------------------------------------
43GpuShaderData::GpuShaderData(uint16_t vert_decl_flags, Shader* shader, DebugRenderMode render_mode)
44{
45    m_render_mode = render_mode;
46    m_shader = shader;
47    m_vert_decl_flags = vert_decl_flags;
48}
49
50//-----------------------------------------------------------------------------
51GpuShaderData::~GpuShaderData()
52{
53    m_shader_uniform.Empty();
54    m_shader_attrib.Empty();
55}
56
57//-----------------------------------------------------------------------------
58void GpuShaderData::AddUniform(const lol::String &new_uniform)
59{
60    m_shader_uniform.Push(new_uniform, m_shader->GetUniformLocation(new_uniform.C()));
61}
62
63//-----------------------------------------------------------------------------
64void GpuShaderData::AddAttribute(const lol::String &new_attribute, VertexUsage usage, int index)
65{
66    m_shader_attrib.Push(new_attribute, m_shader->GetAttribLocation(new_attribute.C(), usage, index));
67}
68
69//-----------------------------------------------------------------------------
70ShaderUniform const *GpuShaderData::GetUniform(const lol::String &uniform)
71{
72    for (int i = 0; i < m_shader_uniform.Count(); ++i)
73        if (m_shader_uniform[i].m1 == uniform)
74            return &m_shader_uniform[i].m2;
75    return nullptr;
76}
77
78//-----------------------------------------------------------------------------
79ShaderAttrib const *GpuShaderData::GetAttribute(const lol::String &attribute)
80{
81    for (int i = 0; i < m_shader_attrib.Count(); ++i)
82        if (m_shader_attrib[i].m1 == attribute)
83            return &m_shader_attrib[i].m2;
84    return nullptr;
85}
86
87//-----------------------------------------------------------------------------
88DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode)
89{
90    bool with_UV = false;
91    m_render_mode = render_mode;
92    m_vert_decl_flags = (1 << VertexUsage::Position) |
93                        (1 << VertexUsage::Normal)   |
94                        (1 << VertexUsage::Color);
95
96    if (render_mode == DebugRenderMode::Default)
97        m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny));
98    else if (render_mode == DebugRenderMode::Wireframe)
99        m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugwireframe));
100    else if (render_mode == DebugRenderMode::Lighting)
101        m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebuglighting));
102    else if (render_mode == DebugRenderMode::Normal)
103        m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugnormal));
104    else if (render_mode == DebugRenderMode::UV)
105    {
106        m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV));
107        m_vert_decl_flags |= (1 << VertexUsage::TexCoord);
108        with_UV = true;
109    }
110    SetupDefaultData(with_UV);
111}
112
113//-----------------------------------------------------------------------------
114DefaultShaderData::DefaultShaderData(uint16_t vert_decl_flags, Shader* shader, bool with_UV)
115    : GpuShaderData(vert_decl_flags, shader, DebugRenderMode::Default)
116{
117    SetupDefaultData(with_UV);
118}
119
120//-----------------------------------------------------------------------------
121void DefaultShaderData::SetupDefaultData(bool with_UV)
122{
123    AddUniform("in_ModelView");
124    AddUniform("in_Inv_ModelView");
125    AddUniform("in_View");
126    AddUniform("in_Inv_View");
127    AddUniform("in_Proj");
128    AddUniform("in_NormalMat");
129    AddUniform("in_Damage");
130    AddUniform("u_Lights");
131}
132
133//-----------------------------------------------------------------------------
134void DefaultShaderData::SetupShaderDatas(mat4 const &model)
135{
136    mat4 proj = g_scene->GetCamera()->GetProjection();
137    mat4 view = g_scene->GetCamera()->GetView();
138    mat4 modelview = view * model;
139    mat3 normalmat = transpose(inverse(mat3(modelview)));
140
141    /* FIXME: this should be hidden in the shader */
142    /* FIXME: the 4th component of the position can be used for other things */
143    /* FIXME: GetUniform("blabla") is costly */
144    Array<Light *> const lights = g_scene->GetLights();
145    Array<vec4> light_data;
146    for (int i = 0; i < lights.Count(); ++i)
147        light_data << lights[i]->GetPosition() << lights[i]->GetColor();
148    while (light_data.Count() < 8)
149        light_data << vec4(0.f) << vec4(0.f);
150    m_shader->SetUniform(*GetUniform("u_Lights"), light_data);
151
152    m_shader->SetUniform(*GetUniform("in_ModelView"), modelview);
153    m_shader->SetUniform(*GetUniform("in_Inv_ModelView"), inverse(modelview));
154    m_shader->SetUniform(*GetUniform("in_View"), view);
155    m_shader->SetUniform(*GetUniform("in_Inv_View"), inverse(view));
156    m_shader->SetUniform(*GetUniform("in_Proj"), proj);
157    m_shader->SetUniform(*GetUniform("in_NormalMat"), normalmat);
158    m_shader->SetUniform(*GetUniform("in_Damage"), 0);
159}
160
161//-----------------------------------------------------------------------------
162GpuEasyMeshData::GpuEasyMeshData()
163{
164    m_vertexcount = 0;
165    m_indexcount = 0;
166    m_ibo = nullptr;
167}
168
169//-----------------------------------------------------------------------------
170GpuEasyMeshData::~GpuEasyMeshData()
171{
172    m_gpudatas.Empty();
173    m_vdatas.Empty();
174    if (m_ibo)
175        delete(m_ibo);
176}
177
178#define BUILD_VFLAG(bool_value, flag_value, check_flag) \
179    bool bool_value = (check_flag & (1 << flag_value)) != 0; \
180    check_flag &= ~(1 << flag_value);
181#define BUILD_VFLAG_OR(bool_value, flag_value, check_flag) \
182    bool_value = (bool_value || (check_flag & (1 << flag_value)) != 0); \
183    check_flag &= ~(1 << flag_value);
184#define BUILD_VFLAG_COUNT(bool_value, flag_value, check_flag, count_value) \
185    BUILD_VFLAG(bool_value, flag_value, check_flag) \
186    count_value += (int)bool_value;
187
188//-----------------------------------------------------------------------------
189void GpuEasyMeshData::AddGpuData(GpuShaderData* gpudata, EasyMesh* src_mesh)
190{
191    uint16_t vflags = gpudata->m_vert_decl_flags;
192
193    BUILD_VFLAG(has_position,    VertexUsage::Position,     vflags);
194    BUILD_VFLAG(has_normal,      VertexUsage::Normal,       vflags);
195    BUILD_VFLAG(has_color,       VertexUsage::Color,        vflags);
196    BUILD_VFLAG(has_texcoord,    VertexUsage::TexCoord,     vflags);
197    BUILD_VFLAG_OR(has_texcoord, VertexUsage::TexCoordExt,  vflags);
198    ASSERT(!vflags, "Vertex Usage setup is not implemented for %s, feel free to do so.",
199           VertexUsage::GetNameList(vflags).C());
200
201    if (has_position)   gpudata->AddAttribute(gpudata->GetInVertexName(),   VertexUsage::Position, 0);
202    if (has_normal)     gpudata->AddAttribute(gpudata->GetInNormalName(),   VertexUsage::Normal, 0);
203    if (has_color)      gpudata->AddAttribute(gpudata->GetInColorName(),    VertexUsage::Color, 0);
204    if (has_texcoord)   gpudata->AddAttribute(gpudata->GetInTexCoordName(), VertexUsage::TexCoord, 0);
205
206    SetupVertexData(gpudata->m_vert_decl_flags, src_mesh);
207
208    if (!m_ibo)
209    {
210        Array<uint16_t> indexlist;
211        for (int i = 0; i < src_mesh->m_indices.Count(); i += 3)
212        {
213            indexlist << src_mesh->m_indices[i + 0];
214            indexlist << src_mesh->m_indices[i + 1];
215            indexlist << src_mesh->m_indices[i + 2];
216        }
217
218        m_ibo = new IndexBuffer(indexlist.Bytes());
219        void *indices = m_ibo->Lock(0, 0);
220        memcpy(indices, &indexlist[0], indexlist.Bytes());
221        m_ibo->Unlock();
222
223        m_indexcount = indexlist.Count();
224    }
225
226    if (m_gpudatas.Count() != DebugRenderMode::Max)
227    {
228        m_gpudatas.Reserve(DebugRenderMode::Max);
229        for (int i = 0; i < DebugRenderMode::Max; i++)
230            m_gpudatas << nullptr;
231    }
232    m_gpudatas[gpudata->m_render_mode] = gpudata;
233}
234
235//-----------------------------------------------------------------------------
236void GpuEasyMeshData::SetupVertexData(uint16_t vflags, EasyMesh* src_mesh)
237{
238    for (int i = 0; i < m_vdatas.Count(); ++i)
239        if (m_vdatas[i].m1 == vflags)
240            return;
241
242    VertexDeclaration* new_vdecl = nullptr;
243    VertexBuffer* new_vbo = nullptr;
244    void *vbo_data = nullptr;
245    int vbo_bytes = 0;
246
247#define COPY_VBO \
248    new_vbo = new VertexBuffer(vbo_bytes); \
249    void *mesh = new_vbo->Lock(0, 0); \
250    memcpy(mesh, vbo_data, vbo_bytes); \
251    new_vbo->Unlock();
252
253    //Keep a count of the flags
254    uint16_t saveflags = vflags;
255    int flagnb = 0;
256    BUILD_VFLAG_COUNT(has_position,   VertexUsage::Position,    saveflags, flagnb);
257    BUILD_VFLAG_COUNT(has_normal,     VertexUsage::Normal,      saveflags, flagnb);
258    BUILD_VFLAG_COUNT(has_color,      VertexUsage::Color,       saveflags, flagnb);
259    BUILD_VFLAG_COUNT(has_texcoord,   VertexUsage::TexCoord,    saveflags, flagnb);
260    BUILD_VFLAG_COUNT(has_texcoordExt,VertexUsage::TexCoordExt, saveflags, flagnb);
261    ASSERT(!saveflags, "Vertex Declaration setup is not implemented for %s, feel free to do so.",
262           VertexUsage::GetNameList(vflags).C());
263
264    if (has_position && has_normal && has_color && has_texcoord && has_texcoordExt && flagnb == 5)
265    {
266        new_vdecl = new VertexDeclaration(
267                         VertexStream<vec3,vec3,u8vec4,vec4>(
268                          VertexUsage::Position,
269                          VertexUsage::Normal,
270                          VertexUsage::Color,
271                          VertexUsage::TexCoord));
272
273        Array<vec3, vec3, u8vec4, vec4> vertexlist;
274        for (int i = 0; i < src_mesh->m_vert.Count(); i++)
275            vertexlist.Push(src_mesh->m_vert[i].m_coord,
276                            src_mesh->m_vert[i].m_normal,
277                            (u8vec4)(src_mesh->m_vert[i].m_color * 255.f),
278                            src_mesh->m_vert[i].m_texcoord);
279
280        vbo_data = &vertexlist[0];
281        vbo_bytes = vertexlist.Bytes();
282        m_vertexcount = vertexlist.Count();
283
284        COPY_VBO;
285    }
286    else if (has_position && has_texcoord && has_texcoordExt && flagnb == 3)
287    {
288        new_vdecl = new VertexDeclaration(VertexStream<vec3,vec4>(VertexUsage::Position, VertexUsage::TexCoord));
289
290        Array<vec3, vec4> vertexlist;
291        for (int i = 0; i < src_mesh->m_vert.Count(); i++)
292            vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord);
293
294        vbo_data = &vertexlist[0];
295        vbo_bytes = vertexlist.Bytes();
296        m_vertexcount = vertexlist.Count();
297
298        COPY_VBO;
299    }
300    else if (has_position && has_texcoord && flagnb == 2)
301    {
302        new_vdecl = new VertexDeclaration(VertexStream<vec3,vec2>(VertexUsage::Position, VertexUsage::TexCoord));
303
304        Array<vec3, vec2> vertexlist;
305        for (int i = 0; i < src_mesh->m_vert.Count(); i++)
306            vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_texcoord.xy);
307
308        vbo_data = &vertexlist[0];
309        vbo_bytes = vertexlist.Bytes();
310        m_vertexcount = vertexlist.Count();
311
312        COPY_VBO;
313    }
314    else if (has_position && has_normal && has_color && has_texcoord && flagnb == 4)
315    {
316        new_vdecl = new VertexDeclaration(
317                         VertexStream<vec3,vec3,u8vec4,vec2>(
318                          VertexUsage::Position,
319                          VertexUsage::Normal,
320                          VertexUsage::Color,
321                          VertexUsage::TexCoord));
322
323        Array<vec3, vec3, u8vec4, vec2> vertexlist;
324        for (int i = 0; i < src_mesh->m_vert.Count(); i++)
325            vertexlist.Push(src_mesh->m_vert[i].m_coord,
326                            src_mesh->m_vert[i].m_normal,
327                            (u8vec4)(src_mesh->m_vert[i].m_color * 255.f),
328                            src_mesh->m_vert[i].m_texcoord.xy);
329
330        vbo_data = &vertexlist[0];
331        vbo_bytes = vertexlist.Bytes();
332        m_vertexcount = vertexlist.Count();
333
334        COPY_VBO;
335    }
336    else if (has_position && has_normal && has_color && flagnb == 3)
337    {
338        new_vdecl = new VertexDeclaration(
339                         VertexStream<vec3,vec3,u8vec4>(
340                          VertexUsage::Position,
341                          VertexUsage::Normal,
342                          VertexUsage::Color));
343
344        Array<vec3,vec3,u8vec4> vertexlist;
345        for (int i = 0; i < src_mesh->m_vert.Count(); i++)
346            vertexlist.Push(src_mesh->m_vert[i].m_coord,
347                            src_mesh->m_vert[i].m_normal,
348                            (u8vec4)(src_mesh->m_vert[i].m_color * 255.f));
349
350        vbo_data = &vertexlist[0];
351        vbo_bytes = vertexlist.Bytes();
352        m_vertexcount = vertexlist.Count();
353
354        COPY_VBO;
355    }
356
357    m_vdatas.Push(vflags, new_vdecl, new_vbo);
358}
359
360//-----------------------------------------------------------------------------
361void GpuEasyMeshData::RenderMeshData(mat4 const &model)
362{
363    DebugRenderMode d = Video::GetDebugRenderMode();
364    GpuShaderData& gpu_sd = *(m_gpudatas[d]);
365
366    int vdecl_idx = 0;
367    for (; vdecl_idx < m_vdatas.Count(); ++vdecl_idx)
368        if (m_vdatas[vdecl_idx].m1 == gpu_sd.m_vert_decl_flags)
369            break;
370
371    if (vdecl_idx >= m_vdatas.Count())
372        return;
373
374    uint16_t vflags = m_vdatas[vdecl_idx].m1;
375    VertexDeclaration* vdecl = m_vdatas[vdecl_idx].m2;
376    VertexBuffer* vbo = m_vdatas[vdecl_idx].m3;
377
378    gpu_sd.m_shader->Bind();
379    gpu_sd.SetupShaderDatas(model);
380
381    vdecl->Bind();
382
383    BUILD_VFLAG(has_position,   VertexUsage::Position,    vflags);
384    BUILD_VFLAG(has_normal,     VertexUsage::Normal,      vflags);
385    BUILD_VFLAG(has_color,      VertexUsage::Color,       vflags);
386    BUILD_VFLAG(has_texcoord,   VertexUsage::TexCoord,    vflags);
387    BUILD_VFLAG_OR(has_texcoord,VertexUsage::TexCoordExt, vflags);
388    ASSERT(!vflags, "Vertex Stream setup is not implemented for %s, feel free to do so.",
389           VertexUsage::GetNameList(vflags).C());
390
391    int idx = 0;
392    ShaderAttrib Attribs[4] = { lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib(), lol::ShaderAttrib() };
393
394    if (has_position)   Attribs[idx++] = *gpu_sd.GetAttribute(gpu_sd.GetInVertexName());
395    if (has_normal)     Attribs[idx++] = *gpu_sd.GetAttribute(gpu_sd.GetInNormalName());
396    if (has_color)      Attribs[idx++] = *gpu_sd.GetAttribute(gpu_sd.GetInColorName());
397    if (has_texcoord)   Attribs[idx++] = *gpu_sd.GetAttribute(gpu_sd.GetInTexCoordName());
398
399    vdecl->SetStream(vbo, Attribs[0], Attribs[1], Attribs[2], Attribs[3]);
400
401    m_ibo->Bind();
402    vdecl->DrawIndexedElements(MeshPrimitive::Triangles, 0, 0, m_vertexcount, 0, m_indexcount);
403    m_ibo->Unbind();
404    vdecl->Unbind();
405}
406
407//-----------------------------------------------------------------------------
408EasyMesh::EasyMesh()
409  : m_build_data(nullptr)
410{
411    m_cursors.Push(0, 0);
412}
413
414//-----------------------------------------------------------------------------
415bool EasyMesh::Compile(char const *command)
416{
417    EasyMeshCompiler mc(*this);
418    return mc.ParseString(command);
419}
420
421//-----------------------------------------------------------------------------
422void EasyMesh::OpenBrace()
423{
424    m_cursors.Push(m_vert.Count(), m_indices.Count());
425}
426
427//-----------------------------------------------------------------------------
428void EasyMesh::CloseBrace()
429{
430    m_cursors.Pop();
431}
432//-----------------------------------------------------------------------------
433void EasyMesh::MeshConvert(GpuShaderData* new_gpu_sdata)
434{
435    delete(m_build_data);
436    m_build_data = nullptr;
437
438    if (new_gpu_sdata)
439    {
440        m_gpu_data.AddGpuData(new_gpu_sdata, this);
441        for (int i = DebugRenderMode::Default + 1; i < DebugRenderMode::Max; i++)
442            m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode(i)), this);
443    }
444}
445
446//-----------------------------------------------------------------------------
447void EasyMesh::MeshConvert(Shader* provided_shader)
448{
449    if (provided_shader)
450    {
451        GpuShaderData *new_gpu_sdata = new DefaultShaderData(((1 << VertexUsage::Position) |
452                                                              (1 << VertexUsage::Normal) |
453                                                              (1 << VertexUsage::Color)),
454                                                              provided_shader,
455                                                              false);
456        m_gpu_data.AddGpuData(new_gpu_sdata, this);
457    }
458    else
459        m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode::Default), this);
460    for (int i = DebugRenderMode::Default + 1; i < DebugRenderMode::Max; i++)
461        m_gpu_data.AddGpuData(new DefaultShaderData(DebugRenderMode(i)), this);
462}
463
464//-----------------------------------------------------------------------------
465void EasyMesh::Render(mat4 const &model)
466{
467    m_gpu_data.RenderMeshData(model);
468}
469
470//-------------------
471// "Collisions" functions
472//-------------------
473#define VX_ALONE -2
474#define VX_MASTER -1
475
476//-----------------------------------------------------------------------------
477//helpers func to retrieve a vertex.
478int VertexDictionnary::FindVertexMaster(const int search_idx)
479{
480    //Resolve current vertex idx in the dictionnary (if exist)
481    for (int j = 0; j < vertex_list.Count(); j++)
482        if (vertex_list[j].m1 == search_idx)
483            return vertex_list[j].m3;
484    return VDictType::DoesNotExist;
485}
486
487//-----------------------------------------------------------------------------
488//retrieve a list of matching vertices, doesn't include search_idx.
489bool VertexDictionnary::FindMatchingVertices(const int search_idx, Array<int> &matching_ids)
490{
491    int cur_mast = FindVertexMaster(search_idx);
492
493    if (cur_mast == VDictType::DoesNotExist || cur_mast == VDictType::Alone)
494        return false;
495
496    if (cur_mast == VDictType::Master)
497        cur_mast = search_idx;
498    else
499        matching_ids << vertex_list[cur_mast].m1;
500
501    for (int j = 0; j < vertex_list.Count(); j++)
502        if (vertex_list[j].m3 == cur_mast && vertex_list[j].m1 != search_idx)
503            matching_ids << vertex_list[j].m1;
504
505    return (matching_ids.Count() > 0);
506}
507
508//-----------------------------------------------------------------------------
509//Will return connected vertices (through triangles), if returned vertex has matching ones, it only returns the master.
510bool VertexDictionnary::FindConnectedVertices(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_vert, Array<int> const *ignored_tri)
511{
512    Array<int> connected_tri;
513    FindConnectedTriangles(search_idx, tri_list, tri0, connected_tri, ignored_tri);
514
515    for (int i = 0; i < connected_tri.Count(); i++)
516    {
517        for (int j = 0; j < 3; j++)
518        {
519            int v_indice = tri_list[connected_tri[i] + j];
520            if (v_indice != search_idx)
521            {
522                int found_master = FindVertexMaster(tri_list[connected_tri[i] + j]);
523                if (found_master == VDictType::Alone || found_master == VDictType::Master)
524                    found_master = v_indice;
525                if (found_master != search_idx)
526                {
527                    bool already_exist = false;
528                    for (int k = 0; !already_exist && k < connected_vert.Count(); k++)
529                        if (connected_vert[k] == found_master)
530                            already_exist = true;
531                    if (!already_exist)
532                        connected_vert << found_master;
533                }
534            }
535        }
536    }
537    return (connected_vert.Count() > 0);
538}
539//-----------------------------------------------------------------------------
540bool VertexDictionnary::FindConnectedTriangles(const int search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri)
541{
542    return FindConnectedTriangles(ivec3(search_idx, search_idx, search_idx), tri_list, tri0, connected_tri, ignored_tri);
543}
544//-----------------------------------------------------------------------------
545bool VertexDictionnary::FindConnectedTriangles(const ivec2 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri)
546{
547    return FindConnectedTriangles(ivec3(search_idx, search_idx.x), tri_list, tri0, connected_tri, ignored_tri);
548}
549//-----------------------------------------------------------------------------
550bool VertexDictionnary::FindConnectedTriangles(const ivec3 &search_idx, const Array<uint16_t> &tri_list, const int tri0, Array<int> &connected_tri, Array<int> const *ignored_tri)
551{
552    int needed_validation = 0;
553    Array<int> vert_list[3];
554    for (int i = 0; i < 3; i++)
555    {
556        //Small optim since above func will use this one
557        if ((i == 1 && search_idx[0] == search_idx[1]) ||
558            (i == 2 && (search_idx[0] == search_idx[2] || search_idx[1] == search_idx[2])))
559            continue;
560        else
561        {
562            //increment the validation info, hence empty list aren't taken into account.
563            needed_validation++;
564            vert_list[i] << search_idx[i];
565            FindMatchingVertices(search_idx[i], vert_list[i]);
566        }
567    }
568
569    for (int i = tri0; i < tri_list.Count(); i += 3)
570    {
571        if (ignored_tri)
572        {
573            bool should_pass = false;
574            for (int j = 0; !should_pass && j < ignored_tri->Count(); j++)
575                if ((*ignored_tri)[j] == i)
576                    should_pass = true;
577            if (should_pass)
578                continue;
579        }
580        int found_validation = 0;
581        for (int j = 0; j < 3; j++)
582        {
583            bool validated = false;
584            for (int k = 0; !validated && k < vert_list[j].Count(); k++)
585                for (int l = 0; !validated && l < 3; l++)
586                    if (vert_list[j][k] == tri_list[i + l])
587                        validated = true;
588            found_validation += (validated)?(1):(0);
589        }
590        //triangle is validated store it
591        if (found_validation == needed_validation)
592            connected_tri << i;
593    }
594
595    return (connected_tri.Count() > 0);
596}
597
598//-----------------------------------------------------------------------------
599//Will update the given list with all the vertices on the same spot.
600void VertexDictionnary::AddVertex(const int vert_id, const vec3 vert_coord)
601{
602    for (int j = 0; j < vertex_list.Count(); j++)
603        if (vertex_list[j].m1 == vert_id)
604            return;
605
606    //First, build the vertex Dictionnary
607    int i = 0;
608    for (; i < master_list.Count(); i++)
609    {
610        int cur_mast  = master_list[i];
611        int cur_id    = vertex_list[cur_mast].m1;
612        vec3 cur_loc  = vertex_list[cur_mast].m2;
613        int &cur_type = vertex_list[cur_mast].m3;
614
615        if (cur_id == vert_id)
616            return;
617
618        if (sqlength(cur_loc - vert_coord) < CSG_EPSILON)
619        {
620            if (cur_type == VDictType::Alone)
621                cur_type = VDictType::Master;
622            vertex_list.Push(vert_id, vert_coord, cur_mast);
623            return;
624        }
625    }
626
627    //We're here because we couldn't find any matching vertex
628    master_list.Push(vertex_list.Count());
629    vertex_list.Push(vert_id, vert_coord, VDictType::Alone);
630}
631
632//-----------------------------------------------------------------------------
633void EasyMesh::MeshCsg(CSGUsage csg_operation)
634{
635    //A vertex dictionnary for vertices on the same spot.
636    Array< int, int > vertex_dict;
637    //This list keeps track of the triangle that will need deletion at the end.
638    Array< int > triangle_to_kill;
639    //Listing for each triangle of the vectors intersecting it. <tri_Id, <Point0, Point1, tri_isec_Normal>>
640    Array< int, Array< vec3, vec3, vec3 > > triangle_isec;
641    //keep a track of the intersection point on the triangle. <pos, side_id>
642    Array< vec3, int > triangle_vertex;
643    for (int k = 0; k < 10; k++)
644        triangle_vertex.Push(vec3(.0f), 0);
645
646    //bsp infos
647    CsgBsp mesh_bsp_0;
648    CsgBsp mesh_bsp_1;
649
650    if (m_cursors.Count() == 0)
651        return;
652
653    //BSP BUILD : We use the brace logic, csg should be used as : "[ exp .... [exp .... csg]]"
654    int cursor_start = (m_cursors.Count() < 2)?(0):(m_cursors[(m_cursors.Count() - 2)].m2);
655    for (int mesh_id = 0; mesh_id < 2; mesh_id++)
656    {
657        int start_point     = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
658        int end_point       = (mesh_id == 0)?(m_cursors.Last().m2):(m_indices.Count());
659        CsgBsp &mesh_bsp  = (mesh_id == 0)?(mesh_bsp_0):(mesh_bsp_1);
660        for (int i = start_point; i < end_point; i += 3)
661            mesh_bsp.AddTriangleToTree(i, m_vert[m_indices[i]].m_coord,
662                                          m_vert[m_indices[i + 1]].m_coord,
663                                          m_vert[m_indices[i + 2]].m_coord);
664    }
665
666    //BSP Useage : let's crunch all triangles on the correct BSP
667    int indices_count = m_indices.Count();
668    for (int mesh_id = 0; mesh_id < 2; mesh_id++)
669    {
670        int start_point     = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
671        int end_point       = (mesh_id == 0)?(m_cursors.Last().m2):(indices_count);
672        CsgBsp &mesh_bsp  = (mesh_id == 0)?(mesh_bsp_1):(mesh_bsp_0);
673        Array< vec3, int, int, float > vert_list;
674        Array< int, int, int, int > tri_list;
675        vec3 n0(.0f); vec3 n1(.0f);
676        vec4 c0(.0f); vec4 c1(.0f);
677
678        //Reserve some memory
679        vert_list.Reserve(3);
680        tri_list.Reserve(3);
681
682        for (int i = start_point; i < end_point; i += 3)
683        {
684            int Result = mesh_bsp.TestTriangleToTree(m_vert[m_indices[i]].m_coord,
685                                                     m_vert[m_indices[i + 1]].m_coord,
686                                                     m_vert[m_indices[i + 2]].m_coord, vert_list, tri_list);
687            int tri_base_idx = m_indices.Count();
688
689            //one split has been done, we need to had the new vertices & the new triangles.
690            if (Result == 1)
691            {
692                triangle_to_kill.Push(i);
693#if 1
694                int base_idx = m_vert.Count();
695                for (int k = 3; k < vert_list.Count(); k++)
696                {
697                    int P0 = (vert_list[k].m2 < 3)?(m_indices[i + vert_list[k].m2]):(base_idx + vert_list[k].m2 - 3);
698                    int P1 = (vert_list[k].m3 < 3)?(m_indices[i + vert_list[k].m3]):(base_idx + vert_list[k].m3 - 3);
699
700                    AddVertex(vert_list[k].m1);
701
702                    //Normal : bad calculations there.
703                    n0 = m_vert[P0].m_normal;
704                    n1 = m_vert[P1].m_normal;
705                    SetCurVertNormal(normalize(n0 + (n1 - n0) * vert_list[k].m4));
706
707#if 1
708                    //Color
709                    c0 = m_vert[P0].m_color;
710                    c1 = m_vert[P1].m_color;
711                    vec4 res = c0 + ((c1 - c0) * vert_list[k].m4);
712                    SetCurVertColor(res);
713#else
714                    if (mesh_id == 0)
715                        SetCurVertColor(vec4(1.0f, .0f, .0f, 1.0f));
716                    else
717                        SetCurVertColor(vec4(.0f, 1.0f, 1.0f, 1.0f));
718#endif
719                }
720                for (int k = 0; k < tri_list.Count(); k++)
721                {
722                    int P0 = (tri_list[k].m2 < 3)?(m_indices[i + tri_list[k].m2]):(base_idx + (tri_list[k].m2 - 3));
723                    int P1 = (tri_list[k].m3 < 3)?(m_indices[i + tri_list[k].m3]):(base_idx + (tri_list[k].m3 - 3));
724                    int P2 = (tri_list[k].m4 < 3)?(m_indices[i + tri_list[k].m4]):(base_idx + (tri_list[k].m4 - 3));
725                    AppendTriangle(P0, P1, P2, 0);
726                }
727#endif
728            }
729#if 1
730            //Main case
731            if (Result >= 0)
732            {
733                for (int k = 0; k < tri_list.Count(); k++)
734                {
735                    int tri_idx = ((tri_list.Count() == 1)?(i):(tri_base_idx + k * 3));
736
737                    //Triangle Kill Test
738                    if (//csgu : CSGUnion() -> m0_Outside + m1_Outside
739                        (csg_operation == CSGUsage::Union && tri_list[k].m1 == LEAF_BACK) ||
740                        //csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
741                        (csg_operation == CSGUsage::Substract &&
742                            ((mesh_id == 0 && tri_list[k].m1 == LEAF_BACK) ||
743                            (mesh_id == 1 && tri_list[k].m1 == LEAF_FRONT))) ||
744                        //csgs : CSGSubstractLoss() -> m0_Outside
745                        (csg_operation == CSGUsage::SubstractLoss &&
746                            ((mesh_id == 0 && tri_list[k].m1 == LEAF_BACK) || mesh_id == 1)) ||
747                        //csga : CSGAnd() -> m0_Inside + m1_Inside
748                        (csg_operation == CSGUsage::And && tri_list[k].m1 == LEAF_FRONT))
749                    {
750                        triangle_to_kill.Push(tri_idx);
751                    }
752
753                    //Triangle Invert Test
754                    if (//csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
755                        (csg_operation == CSGUsage::Substract && mesh_id == 1 && tri_list[k].m1 == LEAF_BACK) ||
756                        //csgx : CSGXor() -> m0_Outside/m0_Inside-inverted + m1_Outside/m1_Inside-inverted
757                        (csg_operation == CSGUsage::Xor && tri_list[k].m1 == LEAF_BACK))
758                    {
759                        //a Xor means we will share vertices with the outside, so duplicate the vertices.
760                        //TODO : This operation disconnect all triangle, in some cases, not a good thing.
761                        if (csg_operation == CSGUsage::Xor)
762                        {
763                            for (int l = 0; l < 3; l++)
764                            {
765                                AddDuplicateVertex(m_indices[tri_idx + l]);
766                                m_indices[tri_idx + l] = m_vert.Count() - 1;
767                            }
768                        }
769                        m_indices[tri_idx + 1] += m_indices[tri_idx + 2];
770                        m_indices[tri_idx + 2]  = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
771                        m_indices[tri_idx + 1]  = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
772                        ComputeNormals(tri_idx, 3);
773                    }
774                }
775            }
776#endif
777            vert_list.Empty();
778            tri_list.Empty();
779        }
780    }
781
782    for (int i = 0; i < m_vert.Count(); i++)
783        if (length(m_vert[i].m_normal) < 1.0f)
784            i = i;
785
786    int dir = 1;
787    for (int i = 0; i >= 0 && i < triangle_to_kill.Count() - 1; i += dir)
788    {
789        if (triangle_to_kill[i] < triangle_to_kill[i + 1] && dir < 0)
790            dir = 1;
791        if (triangle_to_kill[i] == triangle_to_kill[i + 1])
792        {
793            triangle_to_kill.Remove(i);
794            dir = -1;
795        }
796        if (triangle_to_kill[i] > triangle_to_kill[i + 1])
797        {
798            triangle_to_kill[i]     += triangle_to_kill[i + 1];
799            triangle_to_kill[i + 1]  = triangle_to_kill[i] - triangle_to_kill[i + 1];
800            triangle_to_kill[i]      = triangle_to_kill[i] - triangle_to_kill[i + 1];
801            dir = -1;
802        }
803        if (i == 0 && dir == -1)
804            dir = 1;
805    }
806    for (int i = triangle_to_kill.Count() - 1; i >= 0; i--)
807        m_indices.Remove(triangle_to_kill[i], 3);
808
809    m_cursors.Last().m1 = m_vert.Count();
810    m_cursors.Last().m2 = m_indices.Count();
811
812    //DONE for the splitting !
813}
814
815//-----------------------------------------------------------------------------
816void EasyMesh::ToggleScaleWinding()
817{
818    BD()->Toggle(MeshBuildOperation::Scale_Winding);
819}
820
821//-----------------------------------------------------------------------------
822void EasyMesh::SetCurColor(vec4 const &color)
823{
824    BD()->Color() = color;
825}
826
827//-----------------------------------------------------------------------------
828void EasyMesh::SetCurColor2(vec4 const &color)
829{
830    BD()->Color2() = color;
831}
832
833//-----------------------------------------------------------------------------
834void EasyMesh::AddVertex(vec3 const &coord)
835{
836    m_vert.Push(VertexData(coord, vec3(0.f, 1.f, 0.f), BD()->Color()));
837}
838
839//-----------------------------------------------------------------------------
840void EasyMesh::AddDuplicateVertex(int i)
841{
842    m_vert << m_vert[i];
843}
844
845//-----------------------------------------------------------------------------
846void EasyMesh::AddLerpVertex(int i, int j, float alpha)
847{
848    m_vert.Push(VertexData(
849        lol::lerp(m_vert[i].m_coord,    m_vert[j].m_coord,      alpha),
850        lol::lerp(m_vert[i].m_normal,   m_vert[j].m_normal,     alpha),
851        lol::lerp(m_vert[i].m_color,    m_vert[j].m_color,      alpha),
852        lol::lerp(m_vert[i].m_texcoord, m_vert[j].m_texcoord,   alpha),
853        ((alpha < .5f) ? (m_vert[i].m_bone_id) : (m_vert[j].m_bone_id)), /* FIXME ? */
854        lol::lerp(m_vert[i].m_bone_weight, m_vert[j].m_bone_weight, alpha)));
855}
856
857//-----------------------------------------------------------------------------
858void EasyMesh::AppendQuad(int i1, int i2, int i3, int i4, int base)
859{
860    m_indices << base + i1;
861    m_indices << base + i2;
862    m_indices << base + i3;
863
864    m_indices << base + i4;
865    m_indices << base + i1;
866    m_indices << base + i3;
867}
868
869//-----------------------------------------------------------------------------
870void EasyMesh::AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
871{
872    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
873    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
874    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
875
876    m_indices << m_vert.Count(); AddDuplicateVertex(base + i4);
877    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
878    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
879}
880
881//-----------------------------------------------------------------------------
882void EasyMesh::AppendTriangle(int i1, int i2, int i3, int base)
883{
884    m_indices << base + i1;
885    m_indices << base + i2;
886    m_indices << base + i3;
887}
888
889//-----------------------------------------------------------------------------
890void EasyMesh::AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
891{
892    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
893    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
894    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
895}
896
897//-----------------------------------------------------------------------------
898void EasyMesh::ComputeNormals(int start, int vcount)
899{
900    for (int i = 0; i < vcount; i += 3)
901    {
902        vec3 v0 = m_vert[m_indices[start + i + 2]].m_coord
903                - m_vert[m_indices[start + i + 0]].m_coord;
904        vec3 v1 = m_vert[m_indices[start + i + 1]].m_coord
905                - m_vert[m_indices[start + i + 0]].m_coord;
906        vec3 n = normalize(cross(v1, v0));
907
908        for (int j = 0; j < 3; j++)
909            m_vert[m_indices[start + i + j]].m_normal = n;
910    }
911}
912
913//-----------------------------------------------------------------------------
914void EasyMesh::ComputeTexCoord(float uv_scale, int uv_offset)
915{
916    UNUSED(uv_scale, uv_offset);
917#if 0
918    VertexDictionnary vert_dict;
919    Array<int> tri_list;
920
921    tri_list.Reserve(m_indices.Count() - m_cursors.Last().m2);
922    for (int i = m_cursors.Last().m2; i < m_indices.Count(); i++)
923    {
924        vert_dict.AddVertex(m_indices[i], m_vert[m_indices[i]].m_coord);
925        tri_list << m_indices[i];
926    }
927
928    //full triangle count
929    Array<int> tri_done;
930    Array<int> tri_check;
931    int tri_count = (m_indices.Count() - m_cursors.Last().m2) / 3;
932
933    tri_check << tri_list[0];
934
935    while (tri_check.Count())
936    {
937        int cur_tri = tri_check[0];
938        int v[3]   = { tri_list[cur_tri + uv_offset % 3], tri_list[cur_tri + (1 + uv_offset) % 3], tri_list[cur_tri + (2 + uv_offset) % 3] };
939        vec2 uv[3] = { m_vert[tri_list[cur_tri]].m_texcoord.xy, m_vert[tri_list[cur_tri + 1]].m_texcoord.xy, m_vert[tri_list[cur_tri + 2]].m_texcoord.xy };
940        for (int j = 0; j < 3; j++)
941        {
942            if (uv[j] != vec2(-1.0f) && uv[j] == uv[(j + 1) % 3])
943            {
944                uv[0] = vec2(-1.0f);
945                uv[1] = vec2(-1.0f);
946                uv[2] = vec2(-1.0f);
947                break;
948            }
949        }
950        int uv_set = 0;
951        for (int j = 0; j < 3; j++)
952            uv_set += (uv[j].x < 0.f)?(0):(1);
953
954        //this case shouldn't happen.
955        if (uv_set == 1)
956        {
957            /*
958            for (int j = 0; j < 3; j++)
959            {
960                if (uv[j] != vec2(-1.0f))
961                {
962                    uv[(j + 1) % 2] = uv[j] + vec2(.0f, uv_scale * length(m_vert[v[j]].m1 - m_vert[v[(j + 1) % 3]].m1));
963                    uv_set = 2;
964                    break;
965                }
966            }
967            */
968        }
969        //No UV is set, let's do the arbitrary set and use the basic method.
970        if (uv_set == 0)
971        {
972            float new_dot = FLT_MAX;
973            int base_i = 0;
974            for (int j = 0; j < 3; j++)
975            {
976                float tmp_dot = abs(dot(normalize(m_vert[v[(j + 1) % 3]].m_coord - m_vert[v[j]].m_coord),
977                                        normalize(m_vert[v[(j + 2) % 3]].m_coord - m_vert[v[j]].m_coord)));
978                if (tmp_dot < new_dot)
979                {
980                    base_i = j;
981                    new_dot = tmp_dot;
982                }
983            }
984            uv[base_i] = vec2(.0f);
985            uv[(base_i + 1) % 3] = vec2(.0f, uv_scale * length(m_vert[v[base_i]].m_coord - m_vert[v[(base_i + 1) % 3]].m_coord));
986            uv_set = 2;
987        }
988        //2 points have been set, let's figure the third
989        if (uv_set == 2)
990        {
991            {
992                //invert values so the two set uv are in [0, 1] slots.
993                int new_v[3];
994                vec2 new_uv[3];
995                bool ignore_set = false;
996                if (uv[0].x >= 0.f && uv[1].x < 0.f)
997                {
998                    new_v[0] = v[2]; new_v[1] = v[0]; new_v[2] = v[1];
999                    new_uv[0] = uv[2]; new_uv[1] = uv[0]; new_uv[2] = uv[1];
1000                }
1001                else if (uv[0].x < 0.f && uv[1].x >= 0.f)
1002                {
1003                    new_v[0] = v[1]; new_v[1] = v[2]; new_v[2] = v[0];
1004                    new_uv[0] = uv[1]; new_uv[1] = uv[2]; new_uv[2] = uv[0];
1005                }
1006                else
1007                    ignore_set = true;
1008                if (!ignore_set)
1009                {
1010                    v[0]  = new_v[0];  v[1]  = new_v[1];  v[2]  = new_v[2];
1011                    uv[0] = new_uv[0]; uv[1] = new_uv[1]; uv[2] = new_uv[2];
1012                }
1013            }
1014
1015            //Do this to be sure the normal is OK.
1016            ComputeNormals(cur_tri, 3);
1017            vec3 v01 = normalize(m_vert[v[1]].m_coord - m_vert[v[0]].m_coord);
1018            vec3 v02 = m_vert[v[2]].m_coord - m_vert[v[0]].m_coord;
1019            vec3 v_dir = normalize(cross(m_vert[m_indices[cur_tri]].m_normal, v01));
1020            vec2 texu_dir = uv[1] - uv[0];
1021            vec2 texv_dir = vec2(texu_dir.y, texu_dir.x);
1022            //Final calculations
1023            uv[2] = texu_dir * dot(v01, v02) + texv_dir * dot(v_dir, v02);
1024
1025            //Set UV on ALL matching vertices!
1026            Array<int> matching_vert;
1027            for (int i = 0; i < 3; i++)
1028            {
1029#if 1
1030                //This marks all same position UV to the same values
1031                //Deactivation is a test.
1032                matching_vert << v[i];
1033                vert_dict.FindMatchingVertices(v[i], matching_vert);
1034                for (int j = 0; j < matching_vert.Count(); j++)
1035                    if (m_vert[matching_vert[j]].m_texcoord.xy == vec2(-1.0f))
1036                        m_vert[matching_vert[j]].m_texcoord = vec4(abs(uv[i]), m_vert[matching_vert[j]].m_texcoord.zw);
1037#else
1038                m_vert[v[i]].m_texcoord = abs(uv[i]);
1039#endif
1040            }
1041
1042            tri_done << cur_tri;
1043            tri_check.Remove(0);
1044
1045            //Get connected triangles and go from there.
1046            for (int j = 0; j < 3; j++)
1047            {
1048#if 1
1049                //This finds triangle that are connected to this triangle
1050                vert_dict.FindConnectedTriangles(ivec2(v[j], v[(j + 1) % 3]), tri_list, tri_check, &tri_done);
1051#else
1052                //This finds triangle that are connected to the vertices of this triangle
1053                vert_dict.FindConnectedTriangles(v[j], tri_list, tri_check, &tri_done);
1054#endif
1055            }
1056        }
1057        else if (uv_set == 3)
1058        {
1059            for (int j = 0; j < 3; j++)
1060            {
1061                m_vert[tri_list[cur_tri]].m_texcoord     = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri]].m_texcoord.zw);
1062                m_vert[tri_list[cur_tri + 1]].m_texcoord = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri + 1]].m_texcoord.zw);
1063                m_vert[tri_list[cur_tri + 2]].m_texcoord = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri + 2]].m_texcoord.zw);
1064            }
1065
1066            //uv[0] = vec2(-1.0f);
1067            //uv[1] = vec2(-1.0f);
1068            //uv[2] = vec2(-1.0f);
1069            /*
1070            bool tri_present = false;
1071            for (int j = 0; j < tri_done.Count(); j++)
1072                if (cur_tri == tri_done[j])
1073                    tri_present = true;
1074            if (!tri_present)
1075                tri_done << cur_tri;
1076            tri_check.Remove(0);
1077            */
1078        }
1079
1080        if (tri_check.Count() == 0 && tri_done.Count() != tri_count)
1081        {
1082            //look for unset triangle
1083            for (int i = 0; !tri_check.Count() && i < tri_list.Count(); i += 3)
1084            {
1085                bool tri_present = false;
1086                for (int j = 0; j < tri_done.Count(); j++)
1087                    if (i == tri_done[j])
1088                        tri_present = true;
1089                if (!tri_present)
1090                    tri_check << i;
1091            }
1092        }
1093    }
1094#endif
1095}
1096
1097//-----------------------------------------------------------------------------
1098void EasyMesh::SetVertColor(vec4 const &color)
1099{
1100    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
1101        m_vert[i].m_color = color;
1102}
1103
1104//-----------------------------------------------------------------------------
1105void EasyMesh::SetTexCoordData(vec2 const &new_offset, vec2 const &new_scale)
1106{
1107    BD()->TexCoordOffset() = new_offset;
1108    BD()->TexCoordScale() = new_scale;
1109}
1110
1111//-----------------------------------------------------------------------------
1112void EasyMesh::SetTexCoordData2(vec2 const &new_offset, vec2 const &new_scale)
1113{
1114    BD()->TexCoordOffset2() = new_offset;
1115    BD()->TexCoordScale2() = new_scale;
1116}
1117
1118//-----------------------------------------------------------------------------
1119void EasyMesh::SetCurVertNormal(vec3 const &normal)
1120{
1121    m_vert[m_vert.Count() - 1].m_normal = normal;
1122}
1123
1124//-----------------------------------------------------------------------------
1125void EasyMesh::SetCurVertColor(vec4 const &color)
1126{
1127    m_vert[m_vert.Count() - 1].m_color = color;
1128}
1129
1130//-----------------------------------------------------------------------------
1131void EasyMesh::SetCurVertTexCoord(vec2 const &texcoord)
1132{
1133    m_vert[m_vert.Count() - 1].m_texcoord = vec4(texcoord, m_vert[m_vert.Count() - 1].m_texcoord.zw);
1134}
1135
1136//-----------------------------------------------------------------------------
1137void EasyMesh::SetCurVertTexCoord2(vec2 const &texcoord)
1138{
1139    m_vert[m_vert.Count() - 1].m_texcoord = vec4(m_vert[m_vert.Count() - 1].m_texcoord.xy, texcoord);
1140}
1141
1142//-----------------------------------------------------------------------------
1143void EasyMesh::Translate(vec3 const &v)
1144{
1145    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
1146        m_vert[i].m_coord += v;
1147}
1148
1149//-----------------------------------------------------------------------------
1150void EasyMesh::RotateX(float angle) { Rotate(angle, vec3(1, 0, 0)); }
1151void EasyMesh::RotateY(float angle) { Rotate(angle, vec3(0, 1, 0)); }
1152void EasyMesh::RotateZ(float angle) { Rotate(angle, vec3(0, 0, 1)); }
1153
1154//-----------------------------------------------------------------------------
1155void EasyMesh::Rotate(float angle, vec3 const &axis)
1156{
1157    mat3 m = mat3::rotate(angle, axis);
1158    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
1159    {
1160        m_vert[i].m_coord  = m * m_vert[i].m_coord;
1161        m_vert[i].m_normal = m * m_vert[i].m_normal;
1162    }
1163}
1164
1165//-----------------------------------------------------------------------------
1166void EasyMesh::RadialJitter(float r)
1167{
1168    Array<int> Welded;
1169    Welded.Push(-1);
1170    for (int i = m_cursors.Last().m1 + 1; i < m_vert.Count(); i++)
1171    {
1172        int j, k;
1173        for (j = m_cursors.Last().m1, k = 0; j < i; j++, k++)
1174        {
1175            if(Welded[k] < 0)
1176            {
1177                vec3 diff = m_vert[i].m_coord - m_vert[j].m_coord;
1178
1179                if(diff.x > 0.1f || diff.x < -0.1f)
1180                    continue;
1181
1182                if(diff.y > 0.1f || diff.y < -0.1f)
1183                    continue;
1184
1185                if(diff.z > 0.1f || diff.z < -0.1f)
1186                    continue;
1187
1188                break;
1189            }
1190        }
1191
1192        if(j == i)
1193            Welded.Push(-1);
1194        else
1195            Welded.Push(j);
1196    }
1197
1198    int i, j;
1199    for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++)
1200    {
1201        if(Welded[j] == -1)
1202            m_vert[i].m_coord *= 1.0f + rand(r);
1203        else
1204            m_vert[i].m_coord = m_vert[Welded[j]].m_coord;
1205    }
1206
1207    ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2);
1208}
1209
1210//-----------------------------------------------------------------------------
1211void EasyMesh::TaperX(float ny, float nz, float xoff, int absolute) { DoMeshTransform(MeshTransform::Taper, Axis::X, Axis::X, ny, nz, xoff, absolute); }
1212void EasyMesh::TaperY(float nx, float nz, float yoff, int absolute) { DoMeshTransform(MeshTransform::Taper, Axis::Y, Axis::Y, nz, nx, yoff, absolute); }
1213void EasyMesh::TaperZ(float nx, float ny, float zoff, int absolute) { DoMeshTransform(MeshTransform::Taper, Axis::Z, Axis::Z, nx, ny, zoff, absolute); }
1214
1215//-----------------------------------------------------------------------------
1216void EasyMesh::TwistX(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::X, Axis::X, t, t, toff, 0); }
1217void EasyMesh::TwistY(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::Y, Axis::Y, t, t, toff, 0); }
1218void EasyMesh::TwistZ(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::Z, Axis::Z, t, t, toff, 0); }
1219
1220//-----------------------------------------------------------------------------
1221void EasyMesh::ShearX(float ny, float nz, float xoff, int absolute) { DoMeshTransform(MeshTransform::Shear, Axis::X, Axis::X, ny, nz, xoff, absolute); }
1222void EasyMesh::ShearY(float nx, float nz, float yoff, int absolute) { DoMeshTransform(MeshTransform::Shear, Axis::Y, Axis::Y, nz, nx, yoff, absolute); }
1223void EasyMesh::ShearZ(float nx, float ny, float zoff, int absolute) { DoMeshTransform(MeshTransform::Shear, Axis::Z, Axis::Z, nx, ny, zoff, absolute); }
1224
1225//-----------------------------------------------------------------------------
1226void EasyMesh::StretchX(float ny, float nz, float xoff) { DoMeshTransform(MeshTransform::Stretch, Axis::X, Axis::X, ny, nz, xoff, 0); }
1227void EasyMesh::StretchY(float nx, float nz, float yoff) { DoMeshTransform(MeshTransform::Stretch, Axis::Y, Axis::Y, nz, nx, yoff, 0); }
1228void EasyMesh::StretchZ(float nx, float ny, float zoff) { DoMeshTransform(MeshTransform::Stretch, Axis::Z, Axis::Z, nx, ny, zoff, 0); }
1229
1230//-----------------------------------------------------------------------------
1231void EasyMesh::BendXY(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::X, Axis::Y, t, t, toff, 0); }
1232void EasyMesh::BendXZ(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::X, Axis::Z, t, t, toff, 0); }
1233void EasyMesh::BendYX(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Y, Axis::X, t, t, toff, 0); }
1234void EasyMesh::BendYZ(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Y, Axis::Z, t, t, toff, 0); }
1235void EasyMesh::BendZX(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Z, Axis::X, t, t, toff, 0); }
1236void EasyMesh::BendZY(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Z, Axis::Y, t, t, toff, 0); }
1237
1238//-----------------------------------------------------------------------------
1239void EasyMesh::DoMeshTransform(MeshTransform ct, Axis axis0, Axis axis1, float n0, float n1, float noff, int absolute)
1240{
1241    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
1242    {
1243        switch (ct)
1244        {
1245            case MeshTransform::Taper:
1246            {
1247                float value = m_vert[i].m_coord[axis0];
1248                if (absolute) value = abs(value);
1249                m_vert[i].m_coord[(axis0 + 1) % 3] *= max(0.f, 1.f + (n0 * value + noff));
1250                m_vert[i].m_coord[(axis0 + 2) % 3] *= max(0.f, 1.f + (n1 * value + noff));
1251                break;
1252            }
1253            case MeshTransform::Twist:
1254            {
1255                vec3 rotaxis = vec3(1.f); rotaxis[(axis0 + 1) % 3] = .0f; rotaxis[(axis0 + 2) % 3] = .0f;
1256                m_vert[i].m_coord = mat3::rotate(m_vert[i].m_coord[axis0] * n0 + noff, rotaxis) * m_vert[i].m_coord;
1257                break;
1258            }
1259            case MeshTransform::Shear:
1260            {
1261                float value = m_vert[i].m_coord[axis0];
1262                if (absolute) value = abs(value);
1263                m_vert[i].m_coord[(axis0 + 1) % 3] += (n0 * value + noff);
1264                m_vert[i].m_coord[(axis0 + 2) % 3] += (n1 * value + noff);
1265                break;
1266            }
1267            case MeshTransform::Stretch:
1268            {
1269                //float value = abs(m_vert[i].m1[axis0]);
1270                //m_vert[i].m1[(axis0 + 1) % 3] += (lol::pow(value, n0) + noff);
1271                //m_vert[i].m1[(axis0 + 2) % 3] += (lol::pow(value, n1) + noff);
1272                break;
1273            }
1274            case MeshTransform::Bend:
1275            {
1276                vec3 rotaxis = vec3(1.f); rotaxis[(axis1 + 1) % 3] = .0f; rotaxis[(axis1 + 2) % 3] = .0f;
1277                m_vert[i].m_coord = mat3::rotate(m_vert[i].m_coord[axis0] * n0 + noff, rotaxis) * m_vert[i].m_coord;
1278                break;
1279            }
1280        }
1281    }
1282    ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2);
1283}
1284
1285//-----------------------------------------------------------------------------
1286void EasyMesh::Scale(vec3 const &s)
1287{
1288    vec3 const invs = vec3(1) / s;
1289
1290    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
1291    {
1292        m_vert[i].m_coord *= s;
1293        m_vert[i].m_normal = normalize(m_vert[i].m_normal * invs);
1294    }
1295
1296    /* Flip winding if the scaling involves mirroring */
1297    if (!BD()->IsEnabled(MeshBuildOperation::Scale_Winding) && s.x * s.y * s.z < 0)
1298    {
1299        for (int i = m_cursors.Last().m2; i < m_indices.Count(); i += 3)
1300        {
1301            uint16_t tmp = m_indices[i + 0];
1302            m_indices[i + 0] = m_indices[i + 1];
1303            m_indices[i + 1] = tmp;
1304        }
1305    }
1306}
1307
1308//-----------------------------------------------------------------------------
1309void EasyMesh::MirrorX() { DupAndScale(vec3(-1, 1, 1)); }
1310void EasyMesh::MirrorY() { DupAndScale(vec3(1, -1, 1)); }
1311void EasyMesh::MirrorZ() { DupAndScale(vec3(1, 1, -1)); }
1312
1313//-----------------------------------------------------------------------------
1314void EasyMesh::DupAndScale(vec3 const &s)
1315{
1316    int vlen = m_vert.Count() - m_cursors.Last().m1;
1317    int tlen = m_indices.Count() - m_cursors.Last().m2;
1318
1319    for (int i = 0; i < vlen; i++)
1320        AddDuplicateVertex(m_cursors.Last().m1++);
1321
1322    for (int i = 0; i < tlen; i++)
1323        m_indices << m_indices[m_cursors.Last().m2++] + vlen;
1324
1325    Scale(s);
1326
1327    m_cursors.Last().m1 -= vlen;
1328    m_cursors.Last().m2 -= tlen;
1329}
1330
1331//-----------------------------------------------------------------------------
1332void EasyMesh::AppendCylinder(int nsides, float h, float d1, float d2,
1333                              int dualside, int smooth, int close)
1334{
1335    //XXX : This operation is done to convert radius to diameter without changing all the code.
1336    float r1 = d1 * .5f;
1337    float r2 = d2 * .5f;
1338
1339    //SAVE
1340    vec4 Saved_Color = BD()->Color();
1341    vec4 Saved_Color2 = BD()->Color2();
1342    vec2 Save_texcoord_offset = BD()->TexCoordOffset();
1343    vec2 Save_texcoord_scale = BD()->TexCoordScale();
1344
1345    int vbase = m_vert.Count();
1346
1347    mat3 rotmat = mat3::rotate(360.0f / (float)nsides, 0.f, 1.f, 0.f);
1348    vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n;
1349    vec2 uv1(.0f, .0f), uv2(.0f, 1.0f), uvadd(1.0f / (float)nsides, .0f);
1350    if (close)
1351        SetTexCoordData(vec2(.0f), vec2(1.0f, .5f));
1352
1353    /* Construct normal */
1354    if (r2 != .0f)
1355        n = vec3(r2, h * .5f, 0.f);
1356    else
1357        n = vec3(r1, h * .5f, 0.f);
1358    n.y = r1 * (r1 - r2) / h;
1359    if (!smooth)
1360        n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n;
1361    n = normalize(n);
1362
1363    /* FIXME: normals should be flipped in two-sided mode, but that
1364     * means duplicating the vertices again... */
1365    for (int i = 0; i < nsides; i++)
1366    {
1367        AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); SetCurVertTexCoord2(uv1);
1368        AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); SetCurVertTexCoord2(uv2);
1369        SetCurVertColor(BD()->Color2());
1370
1371        if (smooth)
1372        {
1373            int j = (i + 1) % nsides;
1374            AppendQuad(j * 2, j * 2 + 1, i * 2 + 1, i * 2, vbase);
1375            if (dualside)
1376                AppendQuad(i * 2, i * 2 + 1, j * 2 + 1, j * 2, vbase);
1377        }
1378
1379        p1 = rotmat * p1; uv1 += uvadd;
1380        p2 = rotmat * p2; uv2 += uvadd;
1381
1382        if (!smooth)
1383        {
1384            AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); SetCurVertTexCoord2(uv1);
1385            AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); SetCurVertTexCoord2(uv2);
1386            SetCurVertColor(BD()->Color2());
1387
1388            AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase);
1389            if (dualside)
1390                AppendQuad(i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, vbase);
1391        }
1392
1393        n = rotmat * n;
1394    }
1395
1396    if (close)
1397    {
1398        //START
1399        OpenBrace();
1400        //LOWER DISC
1401        SetTexCoordData(vec2(.0f, .5f), vec2(.5f, .5f));
1402        SetCurColor(BD()->Color());
1403        AppendDisc(nsides, d1);
1404        Translate(vec3(.0f, h, .0f));
1405        RotateX(180.0f);
1406        //UPPER DISC
1407        SetTexCoordData(vec2(.5f, .5f), vec2(.5f, .5f));
1408        SetCurColor(BD()->Color2());
1409        AppendDisc(nsides, d2);
1410        Translate(vec3(.0f, h * .5f, .0f));
1411        CloseBrace();
1412    }
1413    //RESTORE
1414    SetCurColor(Saved_Color);
1415    SetCurColor2(Saved_Color2);
1416    SetTexCoordData(Save_texcoord_offset, Save_texcoord_scale);
1417}
1418
1419//-----------------------------------------------------------------------------
1420void EasyMesh::AppendSphere(int ndivisions, float d)
1421{
1422    AppendCapsule(ndivisions, 0.f, d);
1423}
1424
1425//-----------------------------------------------------------------------------
1426void EasyMesh::AppendCapsule(int ndivisions, float h, float d)
1427{
1428    //XXX : This operation is done to convert radius to diameter without changing all the code.
1429    float r = d * .5f;
1430
1431    int ibase = m_indices.Count();
1432
1433    Array<vec3> vertices;
1434    float uv_h = 0;
1435    float uv_r = 0;
1436
1437    /* FIXME: we don't know how to handle even-divided capsules, so we
1438     * force the count to be odd. */
1439    if (h)
1440    {
1441        ndivisions |= 1;
1442        //calculate uv h&r percents
1443        uv_h = (float)h / (float)(h + r * 2);
1444        uv_r = (float)r / (float)(h + r * 2);
1445    }
1446
1447    /* Fill in the icosahedron vertices, rotating them so that there
1448     * is a vertex at [0 1 0] and [0 -1 0] after normalisation. */
1449    float phi = 0.5f + 0.5f * sqrt(5.f);
1450    mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / F_PI),
1451                            vec3(0.f, 0.f, 1.f));
1452    for (int i = 0; i < 4; i++)
1453    {
1454        float x = (i & 1) ? 0.5f : -0.5f;
1455        float y = (i & 2) ? phi * 0.5f : phi * -0.5f;
1456        vertices << mat * vec3(x, y, 0.f);
1457        vertices << mat * vec3(0.f, x, y);
1458        vertices << mat * vec3(y, 0.f, x);
1459    }
1460
1461    static int const trilist[] =
1462    {
1463        0, 1, 2, 2, 4, 6, 3, 8, 1, 9, 4, 8,
1464        7, 0, 5, 7, 11, 3, 10, 5, 6, 10, 9, 11,
1465
1466        0, 3, 1, 7, 3, 0, 1, 4, 2, 8, 4, 1,
1467        2, 5, 0, 6, 5, 2, 6, 9, 10, 4, 9, 6,
1468        7, 10, 11, 5, 10, 7, 8, 11, 9, 3, 11, 8
1469    };
1470
1471    for (unsigned i = 0; i < sizeof(trilist) / sizeof(*trilist); i += 3)
1472    {
1473        vec3 const &a = vertices[trilist[i]];
1474        vec3 const &b = vertices[trilist[i + 1]];
1475        vec3 const &c = vertices[trilist[i + 2]];
1476
1477        vec3 const vb = 1.f / ndivisions * (b - a);
1478        vec3 const vc = 1.f / ndivisions * (c - a);
1479
1480        int line = ndivisions + 1;
1481
1482        for (int v = 0, x = 0, y = 0; x < ndivisions + 1; v++)
1483        {
1484            vec3 p[] = { a + (float)x * vb + (float)y * vc,
1485                         p[0] + vb,
1486                         p[0] + vc,
1487                         p[0] + vb + vc };
1488            vec2 uv[4];
1489
1490            /* FIXME: when we normalise here, we get a volume that is slightly
1491             * smaller than the sphere of radius 1, since we are not using
1492             * the midradius. */
1493            for (int k = 0; k < 4; k++)
1494            {
1495                //keep normalized until the end of the UV calculations
1496                p[k] = normalize(p[k]);
1497
1498                uv[k].x = (lol::atan2(p[k].z, p[k].x) + F_PI) / (F_PI * 2.f);
1499                if (abs(p[k].y) >= 1.0f)
1500                    uv[k].x = -1.f;
1501                uv[k].y = lol::atan2(p[k].y, dot(p[k], normalize(p[k] * vec3(1.f,0.f,1.f)))) / F_PI + 0.5f;
1502                if (h)
1503                {
1504                    if (uv[k].y > .5f)
1505                        uv[k].y = uv_r + uv_h + (uv[k].y - .5f) * uv_r * 2.f;
1506                    else
1507                        uv[k].y *= uv_r * 2.f;
1508                }
1509                p[k] *= r;
1510            }
1511
1512            /* If this is a capsule, grow in the Y direction */
1513            if (h > 0.f)
1514            {
1515                for (int k = 0; k < 4; k++)
1516                    p[k].y += (p[k].y > 0.f) ? 0.5f * h : -0.5f * h;
1517            }
1518
1519            /* Add zero, one or two triangles */
1520            int id[] = { 0, 1, 2,
1521                         1, 3 ,2 };
1522            int l = 6;
1523            while ((l -= 3) >= 0)
1524            {
1525                if ((l == 0 && y < line - 1) || (l == 3 && y < line - 2))
1526                {
1527                    int k = -1;
1528                    while (++k < 3)
1529                    {
1530                        int rid[] = { id[k + l], id[(k + 1) % 3 + l] };
1531                        if (uv[rid[0]].x >= .0f &&
1532                            uv[rid[1]].x >= .0f &&
1533                            abs(uv[rid[0]].x - uv[rid[1]].x) > .5f)
1534                        {
1535                            if (uv[rid[0]].x < uv[rid[1]].x)
1536                                uv[rid[0]].x += 1.0f;
1537                            else
1538                                uv[rid[1]].x += 1.0f;
1539                        }
1540                    }
1541                    k = -1;
1542                    while (++k < 3)
1543                    {
1544                        int rid[] = { id[k + l], id[(k + 1) % 3 + l], id[(k + 2) % 3 + l] };
1545                        AddVertex(p[rid[0]]);
1546                        vec2 new_uv;
1547                        if (uv[rid[0]].x < .0f)
1548                            new_uv = vec2((uv[rid[1]].x + uv[rid[2]].x) * .5f, uv[rid[0]].y);
1549                        else
1550                            new_uv = uv[rid[0]];
1551                        SetCurVertTexCoord(vec2(0.f, 1.f) - new_uv);
1552                        SetCurVertTexCoord2(vec2(0.f, 1.f) - new_uv);
1553                    }
1554                    AppendTriangle(0, 2, 1, m_vert.Count() - 3);
1555                }
1556            }
1557
1558            y++;
1559            if (y == line)
1560            {
1561                x++;
1562                y = 0;
1563                line--;
1564            }
1565        }
1566    }
1567
1568    ComputeNormals(ibase, m_indices.Count() - ibase);
1569}
1570
1571//-----------------------------------------------------------------------------
1572void EasyMesh::AppendTorus(int ndivisions, float d1, float d2)
1573{
1574    //XXX : This operation is done to convert radius to diameter without changing all the code.
1575    float r1 = d1 * .5f;
1576    float r2 = d2 * .5f;
1577
1578    int ibase = m_indices.Count();
1579    int nidiv = ndivisions; /* Cross-section */
1580    int njdiv = ndivisions; /* Full circumference */
1581
1582    for (int j = 0; j < njdiv; j++)
1583    for (int i = 0; i < 2 * nidiv; i++)
1584    {
1585        for (int di = 0; di < 2; di++)
1586        for (int dj = 0; dj < 2; dj++)
1587        {
1588            int i2 = (i + di) % nidiv;
1589            int j2 = (j + dj) % njdiv;
1590
1591            //Location on the donut
1592            float x = 0.5f * (r2 - r1) * (float)lol::cos(2.f * F_PI * i2 / nidiv) + 0.5f * (r1 + r2);
1593            float y = 0.5f * (r2 - r1) * (float)lol::sin(2.f * F_PI * i2 / nidiv);
1594            float z = 0.0f;
1595
1596            //Center circle
1597            float ca = (float)lol::cos(2.f * F_PI * j2 / njdiv);
1598            float sa = (float)lol::sin(2.f * F_PI * j2 / njdiv);
1599
1600            //Actual location
1601            float x2 = x * ca - z * sa;
1602            float z2 = z * ca + x * sa;
1603
1604            AddVertex(vec3(x2, y, z2));
1605            SetCurVertTexCoord(vec2((float)(i + di) / (float)nidiv, (float)(j + dj) / (float)nidiv));
1606            SetCurVertTexCoord2(vec2((float)(i + di) / (float)nidiv, (float)(j + dj) / (float)nidiv));
1607        }
1608
1609        AppendTriangle(0, 2, 3, m_vert.Count() - 4);
1610        AppendTriangle(0, 3, 1, m_vert.Count() - 4);
1611    }
1612
1613    ComputeNormals(ibase, m_indices.Count() - ibase);
1614}
1615
1616//-----------------------------------------------------------------------------
1617void EasyMesh::AppendBox(vec3 const &size, float chamf)
1618{
1619    AppendBox(size, chamf, false);
1620}
1621
1622//-----------------------------------------------------------------------------
1623void EasyMesh::AppendSmoothChamfBox(vec3 const &size, float chamf)
1624{
1625    AppendBox(size, chamf, true);
1626}
1627
1628//-----------------------------------------------------------------------------
1629void EasyMesh::AppendFlatChamfBox(vec3 const &size, float chamf)
1630{
1631    AppendBox(size, chamf, false);
1632}
1633
1634//-----------------------------------------------------------------------------
1635void EasyMesh::AppendBox(vec3 const &size, float chamf, bool smooth)
1636{
1637    if (chamf < 0.0f)
1638    {
1639        AppendBox(size + vec3(chamf * 2.0f), -chamf, smooth);
1640        return;
1641    }
1642
1643    int vbase = m_vert.Count();
1644    int ibase = m_indices.Count();
1645
1646    vec3 d = size * 0.5f;
1647
1648    MeshType mt = MeshType::Box;
1649    TexCoordPos bl = TexCoordPos::BL;
1650    TexCoordPos br = TexCoordPos::BR;
1651    TexCoordPos tl = TexCoordPos::TL;
1652    TexCoordPos tr = TexCoordPos::TR;
1653
1654    //--
1655    //Side vertices
1656    //--
1657    MeshFaceType mft = MeshFaceType::BoxFront;
1658    AddVertex(vec3(-d.x, -d.y, -d.z - chamf));
1659    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1660    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1661    //--
1662    AddVertex(vec3(-d.x, +d.y, -d.z - chamf));
1663    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1664    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1665    //--
1666    AddVertex(vec3(+d.x, +d.y, -d.z - chamf));
1667    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1668    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1669    //--
1670    AddVertex(vec3(+d.x, -d.y, -d.z - chamf));
1671    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1672    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1673
1674    //--
1675    mft = MeshFaceType::BoxLeft;
1676    AddVertex(vec3(-d.x - chamf, -d.y, +d.z));
1677    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1678    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1679    //--
1680    AddVertex(vec3(-d.x - chamf, +d.y, +d.z));
1681    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1682    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1683    //--
1684    AddVertex(vec3(-d.x - chamf, +d.y, -d.z));
1685    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1686    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1687    //--
1688    AddVertex(vec3(-d.x - chamf, -d.y, -d.z));
1689    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1690    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1691
1692    //--
1693    mft = MeshFaceType::BoxBack;
1694    AddVertex(vec3(+d.x, -d.y, +d.z + chamf));
1695    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1696    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1697    //--
1698    AddVertex(vec3(+d.x, +d.y, +d.z + chamf));
1699    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1700    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1701    //--
1702    AddVertex(vec3(-d.x, +d.y, +d.z + chamf));
1703    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1704    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1705    //--
1706    AddVertex(vec3(-d.x, -d.y, +d.z + chamf));
1707    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1708    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1709
1710    //--
1711    mft = MeshFaceType::BoxRight;
1712    AddVertex(vec3(+d.x + chamf, -d.y, -d.z));
1713    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1714    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1715    //--
1716    AddVertex(vec3(+d.x + chamf, +d.y, -d.z));
1717    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1718    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1719    //--
1720    AddVertex(vec3(+d.x + chamf, +d.y, +d.z));
1721    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1722    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1723    //--
1724    AddVertex(vec3(+d.x + chamf, -d.y, +d.z));
1725    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1726    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1727
1728    //--
1729    //Bottom vertices
1730    //--
1731    mft = MeshFaceType::BoxBottom;
1732    AddVertex(vec3(-d.x, -d.y - chamf, +d.z));
1733    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1734    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1735    //--
1736    AddVertex(vec3(-d.x, -d.y - chamf, -d.z));
1737    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1738    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1739    //--
1740    AddVertex(vec3(+d.x, -d.y - chamf, -d.z));
1741    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1742    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1743    //--
1744    AddVertex(vec3(+d.x, -d.y - chamf, +d.z));
1745    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1746    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1747
1748    //--
1749    //Top vertices
1750    //--
1751    mft = MeshFaceType::BoxTop;
1752    AddVertex(vec3(-d.x, +d.y + chamf, -d.z));
1753    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1754    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1755    //--
1756    AddVertex(vec3(-d.x, +d.y + chamf, +d.z));
1757    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1758    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1759    //--
1760    AddVertex(vec3(+d.x, +d.y + chamf, +d.z));
1761    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1762    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1763    //--
1764    AddVertex(vec3(+d.x, +d.y + chamf, -d.z));
1765    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1766    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1767
1768    /* The 6 quads on each side of the box */
1769    for (int i = 0; i < 24; i += 4)
1770        AppendQuad(i, i + 1, i + 2, i + 3, vbase);
1771
1772    ComputeNormals(ibase, m_indices.Count() - ibase);
1773    ibase = m_indices.Count();
1774
1775    /* The 8 quads at each edge of the box */
1776    if (chamf)
1777    {
1778        static int const quadlist[48] =
1779        {
1780            0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
1781            2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
1782            1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
1783        };
1784
1785        for (int i = 0; i < 48; i += 4)
1786        {
1787            if (smooth)
1788                AppendQuad(quadlist[i], quadlist[i + 1],
1789                           quadlist[i + 2], quadlist[i + 3], vbase);
1790            else
1791                AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
1792                                 quadlist[i + 2], quadlist[i + 3], vbase);
1793        }
1794    }
1795
1796    /* The 8 triangles at each corner of the box */
1797    if (chamf)
1798    {
1799        static int const trilist[24] =
1800        {
1801            3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
1802            2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
1803        };
1804
1805        for (int i = 0; i < 24; i += 3)
1806        {
1807            if (smooth)
1808                AppendTriangle(trilist[i], trilist[i + 1],
1809                               trilist[i + 2], vbase);
1810            else
1811                AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
1812                                             trilist[i + 2], vbase);
1813        }
1814    }
1815
1816    if (!smooth)
1817        ComputeNormals(ibase, m_indices.Count() - ibase);
1818}
1819
1820//-----------------------------------------------------------------------------
1821void EasyMesh::AppendStar(int nbranches, float d1, float d2,
1822                          int fade, int fade2)
1823{
1824    //XXX : This operation is done to convert radius to diameter without changing all the code.
1825    float r1 = d1 * .5f;
1826    float r2 = d2 * .5f;
1827
1828    //TODO: It would probably be good to think of another way of UV painting this, like "branch repeating"
1829    int vbase = m_vert.Count();
1830    float maxr = max(r1, r2);
1831
1832    AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f));
1833
1834    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
1835    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
1836    vec3 uv1(0.f, 0.f, -.5f * ((float)r1 / maxr)),
1837         uv2(0.f, 0.f, -.5f * ((float)r2 / maxr));
1838
1839    p2 = rotmat * p2; uv2 = rotmat * uv2;
1840    rotmat = rotmat * rotmat;
1841
1842    for (int i = 0; i < nbranches; i++)
1843    {
1844        AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); SetCurVertTexCoord2(uv1.xz + vec2(.5f));
1845        if (fade2)
1846            SetCurVertColor(BD()->Color2());
1847
1848        AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); SetCurVertTexCoord2(uv2.xz + vec2(.5f));
1849        if (fade)
1850            SetCurVertColor(BD()->Color2());
1851
1852        AppendQuad(0, 2 * i + 1, 2 * i + 2, (2 * i + 3) % (2 * nbranches),
1853                   vbase);
1854
1855        p1 = rotmat * p1; uv1 = rotmat * uv1;
1856        p2 = rotmat * p2; uv2 = rotmat * uv2;
1857    }
1858}
1859
1860//-----------------------------------------------------------------------------
1861void EasyMesh::AppendExpandedStar(int nbranches, float d1, float d2, float extrad)
1862{
1863    //XXX : This operation is done to convert radius to diameter without changing all the code.
1864    float r1 = d1 * .5f;
1865    float r2 = d2 * .5f;
1866    float extrar = extrad * .5f;
1867
1868    int vbase = m_vert.Count();
1869    float maxr = (float)max(max(r1, r2), max(r1 + extrar, r2 + extrar));
1870
1871    AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f));
1872
1873    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
1874    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f),
1875         p3(r1 + extrar, 0.f, 0.f), p4(r2 + extrar, 0.f, 0.f);;
1876    vec3 uv1(0.f, 0.f, -.5f * ((float)r1 / maxr)),
1877         uv2(0.f, 0.f, -.5f * ((float)r2 / maxr)),
1878         uv3(0.f, 0.f, -.5f * ((float)(r1 + extrar) / maxr)),
1879         uv4(0.f, 0.f, -.5f * ((float)(r2 + extrar) / maxr));
1880
1881    p2 = rotmat * p2; uv2 = rotmat * uv2;
1882    p4 = rotmat * p4; uv4 = rotmat * uv4;
1883    rotmat = rotmat * rotmat;
1884
1885    for (int i = 0; i < nbranches; i++)
1886    {
1887        AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); SetCurVertTexCoord2(uv1.xz + vec2(.5f));
1888        AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); SetCurVertTexCoord2(uv2.xz + vec2(.5f));
1889        AddVertex(p3); SetCurVertTexCoord(uv3.xz + vec2(.5f)); SetCurVertTexCoord2(uv3.xz + vec2(.5f)); SetCurVertColor(BD()->Color2());
1890        AddVertex(p4); SetCurVertTexCoord(uv4.xz + vec2(.5f)); SetCurVertTexCoord2(uv4.xz + vec2(.5f)); SetCurVertColor(BD()->Color2());
1891
1892        int j = (i + 1) % nbranches;
1893        AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase);
1894        AppendQuad(4 * i + 1, 4 * i + 3, 4 * i + 4, 4 * i + 2, vbase);
1895        AppendQuad(4 * j + 1, 4 * i + 2, 4 * i + 4, 4 * j + 3, vbase);
1896
1897        p1 = rotmat * p1; uv1 = rotmat * uv1;
1898        p2 = rotmat * p2; uv2 = rotmat * uv2;
1899        p3 = rotmat * p3; uv3 = rotmat * uv3;
1900        p4 = rotmat * p4; uv4 = rotmat * uv4;
1901    }
1902}
1903
1904//-----------------------------------------------------------------------------
1905void EasyMesh::AppendDisc(int nsides, float d, int fade)
1906{
1907    //XXX : This operation is done to convert radius to diameter without changing all the code.
1908    float r = d * .5f;
1909
1910    int vbase = m_vert.Count();
1911
1912    AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f));
1913
1914    mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
1915    vec3 p1(r, 0.f, 0.f);
1916    vec3 uv(.5f, .0f, .0f);
1917
1918    for (int i = 0; i < nsides; i++)
1919    {
1920        AddVertex(p1); SetCurVertTexCoord(uv.xz + vec2(.5f, .5f)); SetCurVertTexCoord2(uv.xz + vec2(.5f, .5f));
1921        if (fade)
1922            SetCurVertColor(BD()->Color2());
1923        AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase);
1924        p1 = rotmat * p1;
1925        uv = rotmat * uv;
1926    }
1927}
1928
1929//-----------------------------------------------------------------------------
1930void EasyMesh::AppendSimpleTriangle(float d, int fade)
1931{
1932    //XXX : This operation is done to convert radius to diameter without changing all the code.
1933    float size = d * .5f;
1934
1935    mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f);
1936    vec3 p(0.f, 0.f, size);
1937
1938    AddVertex(p); SetCurVertTexCoord(vec2(.5f, 0.133975f)); SetCurVertTexCoord2(vec2(.5f, 0.133975f));
1939    p = m * p;
1940    AddVertex(p); SetCurVertTexCoord(vec2(0.f, 1.f)); SetCurVertTexCoord2(vec2(0.f, 1.f));
1941    if (fade)
1942        SetCurVertColor(BD()->Color2());
1943    p = m * p;
1944    AddVertex(p); SetCurVertTexCoord(vec2(1.f, 1.f)); SetCurVertTexCoord2(vec2(1.f, 1.f));
1945    if (fade)
1946        SetCurVertColor(BD()->Color2());
1947
1948    AppendTriangle(0, 1, 2, m_vert.Count() - 3);
1949}
1950
1951//-----------------------------------------------------------------------------
1952void EasyMesh::AppendSimpleQuad(float size, int fade)
1953{
1954    AppendSimpleQuad(vec2(size * .5f), vec2(size * -.5f), 0.f, fade);
1955}
1956
1957//-----------------------------------------------------------------------------
1958void EasyMesh::AppendSimpleQuad(vec2 p1, vec2 p2, float z, int fade)
1959{
1960    MeshType mt = MeshType::Quad;
1961    MeshFaceType mft = MeshFaceType::QuadDefault;
1962
1963    //--
1964    AddVertex(vec3(p2.x, z, -p1.y));
1965    TexCoordPos br = TexCoordPos::BR;
1966    SetCurVertTexCoord(BD()->TexCoord(mt, br, mft));
1967    SetCurVertTexCoord2(BD()->TexCoord2(mt, br, mft));
1968    //--
1969    AddVertex(vec3(p2.x, z, -p2.y));
1970    TexCoordPos bl = TexCoordPos::BL;
1971    SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft));
1972    SetCurVertTexCoord2(BD()->TexCoord2(mt, bl, mft));
1973    //--
1974    AddVertex(vec3(p1.x, z, -p2.y));
1975    TexCoordPos tl = TexCoordPos::TL;
1976    SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft));
1977    SetCurVertTexCoord2(BD()->TexCoord2(mt, tl, mft));
1978    if (fade) SetCurVertColor(BD()->Color2());
1979    //--
1980    AddVertex(vec3(p1.x, z, -p1.y));
1981    TexCoordPos tr = TexCoordPos::TR;
1982    SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft));
1983    SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft));
1984    if (fade) SetCurVertColor(BD()->Color2());
1985
1986    AppendQuad(0, 1, 2, 3, m_vert.Count() - 4);
1987    ComputeNormals(m_indices.Count() - 6, 6);
1988}
1989
1990//-----------------------------------------------------------------------------
1991void EasyMesh::AppendCog(int nbsides, float h, float d10, float d20,
1992                         float d1, float d2, float d12, float d22,
1993                         float sidemul, int offset)
1994{
1995    //XXX : This operation is done to convert radius to diameter without changing all the code.
1996    float r10 = d10 * .5f;
1997    float r20 = d20 * .5f;
1998    float r1  = d1  * .5f;
1999    float r2  = d2  * .5f;
2000    float r12 = d12 * .5f;
2001    float r22 = d22 * .5f;
2002
2003    int ibase = m_indices.Count();
2004    int vbase = m_vert.Count();
2005
2006    /* FIXME: enforce this some other way */
2007    if (r12 < 0)
2008        h = -h;
2009
2010    mat3 rotmat = mat3::rotate(180.0f / nbsides, 0.f, 1.f, 0.f);
2011    mat3 smat1 = mat3::rotate(sidemul * 180.0f / nbsides, 0.f, 1.f, 0.f);
2012    mat3 smat2 = mat3::rotate(sidemul * -360.0f / nbsides, 0.f, 1.f, 0.f);
2013
2014    vec3 p[12];
2015
2016    //Upper points
2017    p[0] = vec3(r10, h * .5f, 0.f);
2018    p[1] = rotmat * p[0];
2019    p[2] = vec3(r1, h * .5f, 0.f);
2020    p[3] = rotmat * p[2];
2021    p[4] = smat1 * (rotmat * vec3(r1 + r12, h * .5f, 0.f));
2022    p[5] = smat2 * (rotmat * p[4]);
2023
2024    //Lower points
2025    p[6] = vec3(r20, h * -.5f, 0.f);
2026    p[7] = rotmat * p[6];
2027    p[8] = vec3(r2, h * -.5f, 0.f);
2028    p[9] = rotmat * p[8];
2029    p[10] = smat1 * (rotmat * vec3(r2 + r22, h * -.5f, 0.f));
2030    p[11] = smat2 * (rotmat * p[10]);
2031
2032    if (offset & 1)
2033        for (int n = 0; n < 12; n++)
2034            p[n] = rotmat * p[n];
2035
2036    rotmat = rotmat * rotmat;
2037
2038    //UV base computation
2039    float maxr = max(max(r1 + r12, r2 + r22), max(r10, r20));
2040    float InLn = length(p[1] - p[0]);
2041    float CogLn[8] = { .0f, .0f, .0f, .0f, .0f, .0f, .0f, .0f };
2042    for (int i = 0; i < 3; i++)
2043    {
2044        for (int j = 0, k = 2; j < 8 && k < 12; j += 4, k += 6)
2045        {
2046            CogLn[j + i] = length(p[k + i + 1] - p[k + i]);
2047            CogLn[j + 3] += CogLn[j + i];
2048            if (i == 1) //Add 3to4 twice since it's automatically completed by +1 loop.
2049                CogLn[j + 3] += CogLn[j + i];
2050        }
2051    }
2052
2053    //Choose the biggest cog length
2054    int CogSrc = (CogLn[7] > CogLn[3])?(4):(0);
2055    CogLn[3] = CogLn[CogSrc + 3];
2056    for (int i = 0; i < 3; i++)
2057        CogLn[i] = CogLn[CogSrc + i] / CogLn[CogSrc + 3];
2058
2059    //Calculate Cog Modifiers
2060    vec2 InUV[2] = { vec2(.0f), vec2(.5f) };
2061    vec2 CogUV[2] = { vec2(.0f), vec2(.5f) };
2062    vec2 upadd = vec2(.25f, .75f);
2063    vec2 lowadd = vec2(.75f, .75f);
2064    {
2065        if (h < InLn)
2066        {
2067            InUV[0].x  = 1.0f;
2068            InUV[0].y  = h / InLn;
2069            InUV[1].x  = .0f;
2070            InUV[1].y -= InUV[0].y * .5f;
2071        }
2072        else
2073        {
2074            InUV[0].x  = InLn / h;
2075            InUV[0].y  = 1.0f;
2076            InUV[1].x -= InUV[0].x * .5f;
2077            InUV[1].y = .0f;
2078        }
2079        if (h < CogLn[3])
2080        {
2081            CogUV[0].x  = 1.0f;
2082            CogUV[0].y  = h / CogLn[3];
2083            CogUV[1].x  = .0f;
2084            CogUV[1].y -= CogUV[0].y * .5f;
2085        }
2086        else
2087        {
2088            CogUV[0].x  = CogLn[3] / h;
2089            CogUV[0].y  = 1.0f;
2090            CogUV[1].x -= CogUV[0].x * .5f;
2091            CogUV[1].y  = .0f;
2092        }
2093        if (InUV[0].x + CogUV[0].x < .5f)
2094        {
2095            InUV[1].x = .0f;
2096            CogUV[1].x = .5f - CogUV[0].x;
2097            upadd  = vec2(.75f, .25f);
2098            lowadd = vec2(.75f, .75f);
2099        }
2100        else if (InUV[0].y + CogUV[0].y < .5f)
2101        {
2102            InUV[1].y = .0f;
2103            CogUV[1].y = .5f - CogUV[0].y;
2104        }
2105        else
2106        {
2107            InUV[0] *= .5f;
2108            InUV[1] *= .5f;
2109            CogUV[0] *= .5f;
2110            CogUV[1] *= .5f;
2111            InUV[1] += vec2(.5f, .0f);
2112        }
2113    }
2114
2115    //Build UV tab
2116    vec2 uv[12]; float CogSz;
2117    //Upper points
2118    CogSz = 1.0f - CogLn[1];
2119    uv[0]  = vec2(0.f,   0.f) * InUV[0]  + InUV[1];
2120    uv[1]  = vec2(1.f,   0.f) * InUV[0]  + InUV[1];
2121    uv[5]  = vec2(CogSz, 0.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[2];
2122    uv[4]  = vec2(CogSz, 0.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[1];
2123    uv[3]  = vec2(CogSz, 0.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[0];
2124    uv[2]  = vec2(0.f,   0.f) * CogUV[0] + CogUV[1];
2125
2126    //Lower points
2127    CogSz = 1.0f - CogLn[1];
2128    uv[6]  = vec2(0.f,   1.f) * InUV[0]  + InUV[1];
2129    uv[7]  = vec2(1.f,   1.f) * InUV[0]  + InUV[1];
2130    uv[11] = vec2(CogSz, 1.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[2];
2131    uv[10] = vec2(CogSz, 1.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[1];
2132    uv[ 9] = vec2(CogSz, 1.f) * CogUV[0] + CogUV[1]; CogSz -= CogLn[0];
2133    uv[ 8] = vec2(0.f,   1.f) * CogUV[0] + CogUV[1];
2134
2135    //Gear generation loop
2136    for (int i = 0; i < nbsides; i++)
2137    {
2138        int j = 3 * 12 * i,
2139            k = 3 * 12 * ((i + 1) % nbsides);
2140
2141        int q[] = { /* The top and bottom faces */
2142                    j, j, j, j,
2143                    j, j, j, j,
2144                    j, j, k, k,
2145                    k, k, j, j,
2146                    j, j, j, k,
2147                    k, j, j, j,
2148                    /* The inner side quads */
2149                    j, j, j, j,
2150                    j, k, k, j,
2151                    /* The outer side quads */
2152                    j, j, j, j,
2153                    j, j, j, j,
2154                    j, j, j, j,
2155                    k, j, j, k
2156                    };
2157        int m[] = { /* The top and bottom faces */
2158                    0,  2,  3,  1,
2159                    7,  9,  8,  6,
2160                    1,  3,  2,  0,
2161                    6,  8,  9,  7,
2162                    3,  4,  5,  2,
2163                    8, 11, 10,  9,
2164                    /* The inner side quads */
2165                    0,  1,  7,  6,
2166                    1,  0,  6,  7,
2167                    /* The outer side quads */
2168                    3,  2,  8,  9,
2169                    4,  3,  9, 10,
2170                    5,  4, 10, 11,
2171                    2,  5, 11, 8
2172                    };
2173        int a[] = { /* The top and bottom faces */
2174                    0, 0, 0, 0,
2175                    0, 0, 0, 0,
2176                    0, 0, 0, 0,
2177                    0, 0, 0, 0,
2178                    0, 0, 0, 0,
2179                    0, 0, 0, 0,
2180                    /* The inner side quads */
2181                    1, 1, 1, 1,
2182                    2, 2, 2, 2,
2183                    /* The outer side quads */
2184                    1, 1, 1, 1,
2185                    1, 2, 2, 1,
2186                    1, 2, 2, 1,
2187                    2, 2, 2, 2
2188                    };
2189
2190        /* Each vertex will share three faces, so three different
2191         * normals, therefore we add each vertex three times. */
2192        for (int n = 0; n < 3 * 12; n++)
2193        {
2194            int d = n / 3;
2195            int e = d % 6;
2196            AddVertex(p[d]);
2197            if (n % 3 == 0) //Top-Bottom logic
2198            {
2199                vec2 tmp = (p[d].xz / maxr);
2200                vec2 add;
2201                if (d >= 6)
2202                {
2203                    tmp *= -1.0f;
2204                    add = lowadd;
2205                }
2206                else
2207                    add = upadd;
2208                SetCurVertTexCoord(tmp * vec2(.25f) + add);
2209                SetCurVertTexCoord2(tmp * vec2(.25f) + add);
2210            }
2211            else if (e == 0 || e == 1) //inner Logic
2212            {
2213                SetCurVertTexCoord(uv[d]);
2214                SetCurVertTexCoord2(uv[d]);
2215            }
2216            else //Cog logic
2217            {
2218                if (e == 2 && n % 3 == 2)
2219                {
2220                    SetCurVertTexCoord(vec2(1.f, (d == 2)?(0.f):(1.f)) * CogUV[0] + CogUV[1]);
2221                    SetCurVertTexCoord2(vec2(1.f, (d == 2)?(0.f):(1.f)) * CogUV[0] + CogUV[1]);
2222                }
2223                else
2224                {
2225                    SetCurVertTexCoord(uv[d]);
2226                    SetCurVertTexCoord2(uv[d]);
2227                }
2228            }
2229            if (d >= 6)
2230                SetCurVertColor(BD()->Color2());
2231        }
2232
2233        int l = -4;
2234        while ((l += 4) < 48)
2235            AppendQuad(q[l + 0] + m[l + 0] * 3 + a[l + 0],
2236                       q[l + 1] + m[l + 1] * 3 + a[l + 1],
2237                       q[l + 2] + m[l + 2] * 3 + a[l + 2],
2238                       q[l + 3] + m[l + 3] * 3 + a[l + 3],
2239                       vbase);
2240
2241        for (int n = 0; n < 12; n++)
2242            p[n] = rotmat * p[n];
2243    }
2244
2245    ComputeNormals(ibase, m_indices.Count() - ibase);
2246}
2247
2248//-----------------------------------------------------------------------------
2249void EasyMesh::Chamfer(float f)
2250{
2251    int vlen = m_vert.Count() - m_cursors.Last().m1;
2252    int ilen = m_indices.Count() - m_cursors.Last().m2;
2253
2254    /* Step 1: enumerate all faces. This is done by merging triangles
2255     * that are coplanar and share an edge. */
2256    int *triangle_classes = new int[ilen / 3];
2257    for (int i = 0; i < ilen / 3; i++)
2258        triangle_classes[i] = -1;
2259
2260    for (int i = 0; i < ilen / 3; i++)
2261    {
2262
2263    }
2264
2265    /* Fun shit: reduce all triangles */
2266    int *vertices = new int[vlen];
2267    memset(vertices, 0, vlen * sizeof(int));
2268    for (int i = 0; i < ilen; i++)
2269        vertices[m_indices[i]]++;
2270
2271    for (int i = 0; i < ilen / 3; i++)
2272
2273    {
2274    #if 0
2275        if (vertices[m_indices[i * 3]] > 1)
2276            continue;
2277        if (vertices[m_indices[i * 3 + 1]] > 1)
2278            continue;
2279        if (vertices[m_indices[i * 3 + 2]] > 1)
2280            continue;
2281    #endif
2282
2283        vec3 bary = 1.f / 3.f * (m_vert[m_indices[i * 3]].m_coord +
2284                                 m_vert[m_indices[i * 3 + 1]].m_coord +
2285                                 m_vert[m_indices[i * 3 + 2]].m_coord);
2286        for (int k = 0; k < 3; k++)
2287        {
2288            vec3 &p = m_vert[m_indices[i * 3 + k]].m_coord;
2289            p -= normalize(p - bary) * f;
2290        }
2291    }
2292}
2293
2294//-----------------------------------------------------------------------------
2295void EasyMesh::SplitTriangles(int pass) { SplitTriangles(pass, nullptr); }
2296
2297//-----------------------------------------------------------------------------
2298void EasyMesh::SplitTriangles(int pass, VertexDictionnary *vert_dict)
2299{
2300    while (pass--)
2301    {
2302        int trimax = m_indices.Count();
2303        for (int i = m_cursors.Last().m2; i < trimax; i += 3)
2304        {
2305            int vbase = m_vert.Count();
2306            int j = -1;
2307            while (++j < 3)
2308            {
2309                AddLerpVertex(m_indices[i + j], m_indices[i + (j + 1) % 3], .5f);
2310                if (vert_dict)
2311                    vert_dict->AddVertex(vbase + j, m_vert[vbase + j].m_coord);
2312            }
2313            //Add new triangles
2314            AppendTriangle(vbase, m_indices[i + 1], vbase + 1, 0);
2315            AppendTriangle(vbase + 2, vbase + 1, m_indices[i + 2], 0);
2316            AppendTriangle(vbase, vbase + 1, vbase + 2, 0);
2317            //Change current triangle
2318            m_indices[i + 1] = vbase;
2319            m_indices[i + 2] = vbase + 2;
2320        }
2321    }
2322    ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2);
2323}
2324
2325//-----------------------------------------------------------------------------
2326//TODO : Add an half-edges implementation to refine smooth.
2327//TODO : Smooth should only use connected vertices that are on edges of the mesh (See box).
2328void EasyMesh::SmoothMesh(int main_pass, int split_per_main_pass, int smooth_per_main_pass)
2329{
2330    VertexDictionnary vert_dict;
2331    Array<vec3> smooth_buf[2];
2332    Array<int> master_list;
2333    Array<int> matching_ids;
2334    Array<int> connected_vert;
2335    int smbuf = 0;
2336
2337    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
2338        vert_dict.AddVertex(i, m_vert[i].m_coord);
2339
2340    while (main_pass--)
2341    {
2342        int split_pass = split_per_main_pass;
2343        int smooth_pass = smooth_per_main_pass;
2344
2345        SplitTriangles(split_pass, &vert_dict);
2346
2347        matching_ids.Reserve(m_vert.Count() - m_cursors.Last().m1);
2348        connected_vert.Reserve(m_vert.Count() - m_cursors.Last().m1);
2349        smooth_buf[0].Resize(m_vert.Count() - m_cursors.Last().m1);
2350        smooth_buf[1].Resize(m_vert.Count() - m_cursors.Last().m1);
2351
2352        for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
2353            smooth_buf[smbuf][i - m_cursors.Last().m1] = m_vert[i].m_coord;
2354
2355        while (smooth_pass--)
2356        {
2357            master_list.Empty();
2358            if (vert_dict.GetMasterList(master_list))
2359            {
2360                for (int i = 0; i < master_list.Count(); i++)
2361                {
2362                    connected_vert.Empty();
2363                    if (vert_dict.FindConnectedVertices(master_list[i], m_indices, m_cursors.Last().m2, connected_vert))
2364                    {
2365                        //Calculate vertices sum
2366                        vec3 vert_sum = vec3(.0f);
2367                        for (int j = 0; j < connected_vert.Count(); j++)
2368                            vert_sum += smooth_buf[smbuf][connected_vert[j] - m_cursors.Last().m1];
2369
2370                        //Calculate new master vertex
2371                        float n = (float)connected_vert.Count();
2372                        //b(n) = 5/4 - pow(3 + 2 * cos(2.f * F_PI / n), 2) / 32
2373                        float beta = 3.f + 2.f * cos(2.f * F_PI / n);
2374                        beta = 5.f / 4.f - beta * beta / 32.f;
2375                        //a(n) = n * (1 - b(n)) / b(n)
2376                        float alpha = (n * (1 - beta)) / beta;
2377                        //V = (a(n) * v + v1 + ... + vn) / (a(n) + n)
2378                        vec3 new_vert = (alpha * smooth_buf[smbuf][master_list[i] - m_cursors.Last().m1] + vert_sum) / (alpha + n);
2379
2380                        //Set all matching vertices to new value
2381                        matching_ids.Empty();
2382                        matching_ids << master_list[i];
2383                        vert_dict.FindMatchingVertices(master_list[i], matching_ids);
2384                        for (int j = 0; j < matching_ids.Count(); j++)
2385                            smooth_buf[1 - smbuf][matching_ids[j] - m_cursors.Last().m1] = new_vert;
2386                    }
2387                }
2388            }
2389            smbuf = 1 - smbuf;
2390        }
2391
2392        for (int i = 0; i < smooth_buf[smbuf].Count(); i++)
2393            m_vert[i + m_cursors.Last().m1].m_coord = smooth_buf[smbuf][i];
2394    }
2395}
2396
2397} /* namespace lol */
Note: See TracBrowser for help on using the repository browser.