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

Last change on this file since 2507 was 2507, checked in by touky, 7 years ago

easymesh : Vertex attribute name can now be customize. Vertex declaration code simplification, ASSERT is more understandable.

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