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

Last change on this file since 2480 was 2480, checked in by sam, 7 years ago

build: fix a few compiler warnings here and there.

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