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

Last change on this file since 2879 was 2879, checked in by touky, 6 years ago

btPhysTest : Added a new test mode called "CAT_MODE". Try it out at your own risks.

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