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

Last change on this file since 2430 was 2430, checked in by lolbot, 7 years ago

fixed 4 files out of 2475:

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