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

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

render : Added DebugRenderMode & corresponding shaders. naive (VERY) implementation in MeshViewer.

File size: 45.1 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
48EasyMesh::EasyMesh()
49  : m_color(0), m_color2(0), m_ignore_winding_on_scale(0)
50{
51    m_cursors.Push(0, 0);
52}
53
54bool EasyMesh::Compile(char const *command)
55{
56    EasyMeshCompiler mc(*this);
57    return mc.ParseString(command);
58}
59
60void EasyMesh::OpenBrace()
61{
62    m_cursors.Push(m_vert.Count(), m_indices.Count());
63}
64
65void EasyMesh::CloseBrace()
66{
67    m_cursors.Pop();
68}
69
70void EasyMesh::MeshConvert(Shader* provided_shader)
71{
72    for (int i = 0; i < DebugRenderMode::Max; i++)
73    {
74        if (i == DebugRenderMode::Default)
75        {
76            if(provided_shader == NULL)
77                m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shiny));
78            else
79                m_gpu.shader << provided_shader;
80        }
81        else if (i == DebugRenderMode::Wireframe)
82                m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugwireframe));
83        else if (i == DebugRenderMode::Lighting)
84                m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebuglighting));
85        else if (i == DebugRenderMode::Normal)
86                m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugnormal));
87        else if (i == DebugRenderMode::UV)
88                m_gpu.shader << Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV));
89
90        m_gpu.modelview << m_gpu.shader.Last()->GetUniformLocation("in_ModelView");
91        m_gpu.view << m_gpu.shader.Last()->GetUniformLocation("in_View");
92        m_gpu.invview << m_gpu.shader.Last()->GetUniformLocation("in_Inv_View");
93        m_gpu.proj << m_gpu.shader.Last()->GetUniformLocation("in_Proj");
94        m_gpu.normalmat << m_gpu.shader.Last()->GetUniformLocation("in_NormalMat");
95        m_gpu.damage << m_gpu.shader.Last()->GetUniformLocation("in_Damage");
96        m_gpu.lights << m_gpu.shader.Last()->GetUniformLocation("u_Lights");
97        m_gpu.coord << m_gpu.shader.Last()->GetAttribLocation("in_Vertex",
98                                              VertexUsage::Position, 0);
99        m_gpu.norm << m_gpu.shader.Last()->GetAttribLocation("in_Normal",
100                                             VertexUsage::Normal, 0);
101        m_gpu.color << m_gpu.shader.Last()->GetAttribLocation("in_Color",
102                                              VertexUsage::Color, 0);
103    }
104
105    m_gpu.vdecl = new VertexDeclaration(
106        VertexStream<vec3,vec3,u8vec4>(VertexUsage::Position,
107                                       VertexUsage::Normal,
108                                       VertexUsage::Color));
109
110    Array<vec3,vec3,u8vec4> vertexlist;
111    for (int i = 0; i < m_vert.Count(); i++)
112        vertexlist.Push(m_vert[i].m1,
113                        m_vert[i].m2,
114                        (u8vec4)(m_vert[i].m3 * 255.f));
115
116    Array<uint16_t> indexlist;
117    for (int i = 0; i < m_indices.Count(); i += 3)
118    {
119        indexlist << m_indices[i + 0];
120        indexlist << m_indices[i + 1];
121        indexlist << m_indices[i + 2];
122    }
123
124    m_gpu.vbo = new VertexBuffer(vertexlist.Bytes());
125    void *mesh = m_gpu.vbo->Lock(0, 0);
126    memcpy(mesh, &vertexlist[0], vertexlist.Bytes());
127    m_gpu.vbo->Unlock();
128
129    m_gpu.ibo = new IndexBuffer(indexlist.Bytes());
130    void *indices = m_gpu.ibo->Lock(0, 0);
131    memcpy(indices, &indexlist[0], indexlist.Bytes());
132    m_gpu.ibo->Unlock();
133
134    m_gpu.vertexcount = vertexlist.Count();
135    m_gpu.indexcount = indexlist.Count();
136}
137
138void EasyMesh::Render(mat4 const &model, float damage)
139{
140    DebugRenderMode d = Video::GetDebugRenderMode();
141
142    mat4 modelview = Scene::GetDefault()->GetViewMatrix() * model;
143    mat3 normalmat = transpose(inverse(mat3(modelview)));
144
145    m_gpu.shader[d]->Bind();
146
147    /* FIXME: this should be hidden in the shader */
148    /* FIXME: the 4th component of the position can be used for other things */
149    Array<Light *> const lights = Scene::GetDefault()->GetLights();
150    Array<vec4> light_data;
151    for (int i = 0; i < lights.Count(); ++i)
152        light_data << lights[i]->GetPosition() << lights[i]->GetColor();
153    while (light_data.Count() < 8)
154        light_data << vec4(0.f) << vec4(0.f);
155    m_gpu.shader[d]->SetUniform(m_gpu.lights[d], light_data);
156
157    m_gpu.shader[d]->SetUniform(m_gpu.modelview[d], modelview);
158    m_gpu.shader[d]->SetUniform(m_gpu.view[d], Scene::GetDefault()->GetViewMatrix());
159    m_gpu.shader[d]->SetUniform(m_gpu.invview[d], inverse(Scene::GetDefault()->GetViewMatrix()));
160    m_gpu.shader[d]->SetUniform(m_gpu.proj[d], Scene::GetDefault()->GetProjMatrix());
161    m_gpu.shader[d]->SetUniform(m_gpu.normalmat[d], normalmat);
162    m_gpu.shader[d]->SetUniform(m_gpu.damage[d], damage);
163    m_gpu.vdecl->Bind();
164    m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord[d], m_gpu.norm[d], m_gpu.color[d]);
165    m_gpu.ibo->Bind();
166    m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles,
167                                     0, 0, m_gpu.vertexcount,
168                                     0, m_gpu.indexcount);
169    m_gpu.ibo->Unbind();
170    m_gpu.vdecl->Unbind();
171}
172
173
174//-------------------
175// "Collisions" functions
176//-------------------
177#define VX_ALONE -2
178#define VX_MASTER -1
179
180//helpers func to retrieve a vertex.
181int FindVertexInDict(int search_idx, Array< int, int > const &vertex_dict)
182{
183    //Resolve current vertex idx in the dictionnary (if exist)
184    for (int j = 0; j < vertex_dict.Count(); j++)
185        if (vertex_dict[j].m1 == search_idx)
186            return j;
187    return -1;
188}
189
190//helpers func to retrieve a triangle.
191int FindTriangleInDict(int search_idx, Array< int, Array< vec3, vec3, vec3 > > const &triangle_isec)
192{
193    //Resolve current vertex idx in the dictionnary (if exist)
194    for (int j = 0; j < triangle_isec.Count(); j++)
195        if (triangle_isec[j].m1 == search_idx)
196            return j;
197    return -1;
198}
199
200//Will update the given list with all the vertices on the same spot.
201void EasyMesh::UpdateVertexDict(Array< int, int > &vertex_dict)
202{
203    //First, build the vertex Dictionnary
204    for (int i = 0; i < m_vert.Count(); i++)
205    {
206        int CurIdx = FindVertexInDict(i, vertex_dict);
207
208        //go through all vertices and do the match-up.
209        if (CurIdx == -1)
210        {
211            for (int j = i + 1; j < m_vert.Count(); j++)
212            {
213                if (sqlength(m_vert[i].m1 - m_vert[j].m1) < CSG_EPSILON)
214                {
215                    if (CurIdx == -1)
216                    {
217                        CurIdx = vertex_dict.Count();
218                        vertex_dict.Push(i, VX_MASTER);
219                    }
220                    vertex_dict.Push(j, CurIdx);
221                }
222            }
223        }
224    }
225}
226
227void EasyMesh::MeshCsg(CSGUsage csg_operation)
228{
229    //A vertex dictionnary for vertices on the same spot.
230    Array< int, int > vertex_dict;
231    //This list keeps track of the triangle that will need deletion at the end.
232    Array< int > triangle_to_kill;
233    //Listing for each triangle of the vectors intersecting it. <tri_Id, <Point0, Point1, tri_isec_Normal>>
234    Array< int, Array< vec3, vec3, vec3 > > triangle_isec;
235    //keep a track of the intersection point on the triangle. <pos, side_id>
236    Array< vec3, int > triangle_vertex;
237    for (int k = 0; k < 10; k++)
238        triangle_vertex.Push(vec3(.0f), 0);
239
240    //bsp infos
241    CsgBsp mesh_bsp_0;
242    CsgBsp mesh_bsp_1;
243
244    if (m_cursors.Count() == 0)
245        return;
246
247    //BSP BUILD : We use the brace logic, csg should be used as : "[ exp .... [exp .... csg]]"
248    int cursor_start = (m_cursors.Count() < 2)?(0):(m_cursors[(m_cursors.Count() - 2)].m2);
249    for (int mesh_id = 0; mesh_id < 2; mesh_id++)
250    {
251        int start_point     = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
252        int end_point       = (mesh_id == 0)?(m_cursors.Last().m2):(m_indices.Count());
253        CsgBsp &mesh_bsp  = (mesh_id == 0)?(mesh_bsp_0):(mesh_bsp_1);
254        for (int i = start_point; i < end_point; i += 3)
255            mesh_bsp.AddTriangleToTree(i, m_vert[m_indices[i]].m1, m_vert[m_indices[i + 1]].m1, m_vert[m_indices[i + 2]].m1);
256    }
257
258    //BSP Useage : let's crunch all triangles on the correct BSP
259    int indices_count = m_indices.Count();
260    for (int mesh_id = 0; mesh_id < 2; mesh_id++)
261    {
262        int start_point     = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
263        int end_point       = (mesh_id == 0)?(m_cursors.Last().m2):(indices_count);
264        CsgBsp &mesh_bsp  = (mesh_id == 0)?(mesh_bsp_1):(mesh_bsp_0);
265        Array< vec3, int, int, float > vert_list;
266        Array< int, int, int, int > tri_list;
267        vec3 n0(.0f); vec3 n1(.0f);
268        vec4 c0(.0f); vec4 c1(.0f);
269
270        //Reserve some memory
271        vert_list.Reserve(3);
272        tri_list.Reserve(3);
273
274        for (int i = start_point; i < end_point; i += 3)
275        {
276            int Result = mesh_bsp.TestTriangleToTree(m_vert[m_indices[i]].m1, m_vert[m_indices[i + 1]].m1, m_vert[m_indices[i + 2]].m1, vert_list, tri_list);
277            int tri_base_idx = m_indices.Count();
278
279            //one split has been done, we need to had the new vertices & the new triangles.
280            if (Result == 1)
281            {
282                triangle_to_kill.Push(i);
283#if 1
284                int base_idx = m_vert.Count();
285                for (int k = 3; k < vert_list.Count(); k++)
286                {
287                    int P0 = (vert_list[k].m2 < 3)?(m_indices[i + vert_list[k].m2]):(base_idx + vert_list[k].m2 - 3);
288                    int P1 = (vert_list[k].m3 < 3)?(m_indices[i + vert_list[k].m3]):(base_idx + vert_list[k].m3 - 3);
289
290                    AddVertex(vert_list[k].m1);
291
292                    //Normal : bad calculations there.
293                    n0 = m_vert[P0].m2;
294                    n1 = m_vert[P1].m2;
295                    SetCurVertNormal(normalize(n0 + (n1 - n0) * vert_list[k].m4));
296
297#if 1
298                    //Color
299                    c0 = m_vert[P0].m3;
300                    c1 = m_vert[P1].m3;
301                    vec4 res = c0 + ((c1 - c0) * vert_list[k].m4);
302                    SetCurVertColor(res);
303#else
304                    if (mesh_id == 0)
305                        SetCurVertColor(vec4(1.0f, .0f, .0f, 1.0f));
306                    else
307                        SetCurVertColor(vec4(.0f, 1.0f, 1.0f, 1.0f));
308#endif
309                }
310                for (int k = 0; k < tri_list.Count(); k++)
311                {
312                    int P0 = (tri_list[k].m2 < 3)?(m_indices[i + tri_list[k].m2]):(base_idx + (tri_list[k].m2 - 3));
313                    int P1 = (tri_list[k].m3 < 3)?(m_indices[i + tri_list[k].m3]):(base_idx + (tri_list[k].m3 - 3));
314                    int P2 = (tri_list[k].m4 < 3)?(m_indices[i + tri_list[k].m4]):(base_idx + (tri_list[k].m4 - 3));
315                    AppendTriangle(P0, P1, P2, 0);
316                }
317#endif
318            }
319#if 1
320            //Main case
321            if (Result >= 0)
322            {
323                for (int k = 0; k < tri_list.Count(); k++)
324                {
325                    int tri_idx = ((tri_list.Count() == 1)?(i):(tri_base_idx + k * 3));
326
327                    //Triangle Kill Test
328                    if (//csgu : CSGUnion() -> m0_Outside + m1_Outside
329                        (csg_operation == CSGUsage::Union && tri_list[k].m1 == LEAF_BACK) ||
330                        //csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
331                        (csg_operation == CSGUsage::Substract &&
332                            ((mesh_id == 0 && tri_list[k].m1 == LEAF_BACK) ||
333                            (mesh_id == 1 && tri_list[k].m1 == LEAF_FRONT))) ||
334                        //csgs : CSGSubstractLoss() -> m0_Outside
335                        (csg_operation == CSGUsage::SubstractLoss &&
336                            ((mesh_id == 0 && tri_list[k].m1 == LEAF_BACK) || mesh_id == 1)) ||
337                        //csga : CSGAnd() -> Inside + Inside
338                        (csg_operation == CSGUsage::And && tri_list[k].m1 == LEAF_FRONT))
339                    {
340                        triangle_to_kill.Push(tri_idx);
341                    }
342
343                    //Triangle Invert Test
344                    if (//csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
345                        (csg_operation == CSGUsage::Substract && mesh_id == 1 && tri_list[k].m1 == LEAF_BACK) ||
346                        //csgx : CSGXor() -> Outside/Inside-inverted + Outside/Inside-inverted
347                        (csg_operation == CSGUsage::Xor && tri_list[k].m1 == LEAF_BACK))
348                    {
349                        //a Xor means we will share vertices with the outside, so duplicate the vertices.
350                        //TODO : This operation disconnect all triangle, in some cases, not a good thing.
351                        if (csg_operation == CSGUsage::Xor)
352                        {
353                            for (int l = 0; l < 3; l++)
354                            {
355                                AddDuplicateVertex(m_indices[tri_idx + l]);
356                                m_indices[tri_idx + l] = m_vert.Count() - 1;
357                            }
358                        }
359                        m_indices[tri_idx + 1] += m_indices[tri_idx + 2];
360                        m_indices[tri_idx + 2]  = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
361                        m_indices[tri_idx + 1]  = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
362                        ComputeNormals(tri_idx, 3);
363                    }
364                }
365            }
366#endif
367            vert_list.Empty();
368            tri_list.Empty();
369        }
370    }
371
372    for (int i = 0; i < m_vert.Count(); i++)
373        if (length(m_vert[i].m2) < 1.0f)
374            i = i;
375
376    int dir = 1;
377    for (int i = 0; i >= 0 && i < triangle_to_kill.Count() - 1; i += dir)
378    {
379        if (triangle_to_kill[i] < triangle_to_kill[i + 1] && dir < 0)
380            dir = 1;
381        if (triangle_to_kill[i] == triangle_to_kill[i + 1])
382        {
383            triangle_to_kill.Remove(i);
384            dir = -1;
385        }
386        if (triangle_to_kill[i] > triangle_to_kill[i + 1])
387        {
388            triangle_to_kill[i]     += triangle_to_kill[i + 1];
389            triangle_to_kill[i + 1]  = triangle_to_kill[i] - triangle_to_kill[i + 1];
390            triangle_to_kill[i]      = triangle_to_kill[i] - triangle_to_kill[i + 1];
391            dir = -1;
392        }
393        if (i == 0 && dir == -1)
394            dir = 1;
395    }
396    for (int i = triangle_to_kill.Count() - 1; i >= 0; i--)
397        m_indices.Remove(triangle_to_kill[i], 3);
398
399    m_cursors.Last().m1 = m_vert.Count();
400    m_cursors.Last().m2 = m_indices.Count();
401
402#if 0
403    UpdateVertexDict(vertex_dict);
404
405    for (int t0 = 0; t0 < m_indices.Count(); t0 += 3)
406    {
407        for (int t1 = t0 + 3; t1 < m_indices.Count(); t1 += 3)
408        {
409            int CommonVertices = 0;
410            //Search for common vertices, if > 1 the two triangle share a side, so no split is required.
411            for (int k = 0; k < 3; k++)
412            {
413                int ref_master = FindVertexInDict(m_indices[t0 + k], vertex_dict);
414                if (ref_master != -1)
415                {
416                    if (vertex_dict[ref_master].m2 != VX_MASTER)
417                        ref_master = vertex_dict[ref_master].m2;
418                    for (int l = 0; l < 3; l++)
419                    {
420                        int test_master = FindVertexInDict(m_indices[t1 + l], vertex_dict);
421                        if (test_master != -1)
422                        {
423                            if (vertex_dict[test_master].m2 != VX_MASTER)
424                                test_master = vertex_dict[test_master].m2;
425                            if (test_master == ref_master)
426                            {
427                                CommonVertices++;
428                                break;
429                            }
430                        }
431                    }
432                }
433            }
434
435            if (CommonVertices < 2)
436            {
437                vec3 iP0, iP1;
438                //Build the triangle intersection list
439                if (TriangleIsectTriangle(m_vert[m_indices[t0]].m1, m_vert[m_indices[t0 + 1]].m1, m_vert[m_indices[t0 + 2]].m1,
440                                          m_vert[m_indices[t1]].m1, m_vert[m_indices[t1 + 1]].m1, m_vert[m_indices[t1 + 2]].m1,
441                                          iP0, iP1))
442                {
443                    int CurIdx = FindTriangleInDict(t0, triangle_isec);
444                    if (CurIdx == -1)
445                    {
446                        CurIdx = triangle_isec.Count();
447                        triangle_isec.Push(t0, Array<vec3, vec3, vec3>());
448                    }
449                    triangle_isec[CurIdx].m2.Push(iP0, iP1, vec3(.0f));
450                    CurIdx = FindTriangleInDict(t1, triangle_isec);
451                    if (CurIdx == -1)
452                    {
453                        CurIdx = triangle_isec.Count();
454                        triangle_isec.Push(t1, Array<vec3, vec3, vec3>());
455                    }
456                    triangle_isec[CurIdx].m2.Push(iP0, iP1, vec3(.0f));
457                }
458            }
459        }
460    }
461
462    /* seems to be counter-productive in some rare cases. */
463    /*
464    //Every intersection has been found, let's remove those that exist twice.
465    for(int i = 0; i < triangle_isec.Count(); i++)
466    {
467        for(int j = 0; j < triangle_isec[i].m2.Count(); j++)
468        {
469            for(int k = j + 1; k < triangle_isec[i].m2.Count(); k++)
470            {
471                //if the two Dir-vector are parallel & the fist Dir-vector is parallel to the (P0, P1)-vector, this is the same intersection, so kill it.
472                if (abs(dot(normalize(triangle_isec[i].m2[j].m2 - triangle_isec[i].m2[j].m1),
473                            normalize(triangle_isec[i].m2[k].m2 - triangle_isec[i].m2[k].m1)))
474                        >= 1.0 &&
475                    abs(dot(normalize(triangle_isec[i].m2[j].m2 - triangle_isec[i].m2[j].m1),
476                            normalize(triangle_isec[i].m2[k].m1 - triangle_isec[i].m2[j].m1)))
477                        >= 1.0 )
478                    triangle_isec[i].m2.Remove(k--);
479            }
480        }
481    }
482    */
483
484    //Now, the triangle intersection tab should be nice and cosy, so we can start actually cutting some triangles.
485    vec3 isecV[2] = { vec3(.0f), vec3(.0f) };
486    int isecI[2] = { -1, -1 };
487    int v_idx0 = 0; int v_idx1 = 0;
488    int new_v_idx[2] = { 0, 0 };
489    vec3 n0(.0f); vec3 n1(.0f);
490    vec4 c0(.0f); vec4 c1(.0f);
491    for(int i = 0; i < triangle_isec.Count(); i++)
492    {
493        int tri_idx = triangle_isec[i].m1;
494        for(int j = 0; j < triangle_isec[i].m2.Count(); j++)
495        {
496            //Get intersection on actual triangle sides.
497            if (RayIsectTriangleSide(m_vert[m_indices[tri_idx]].m1, m_vert[m_indices[tri_idx + 1]].m1, m_vert[m_indices[tri_idx + 2]].m1,
498                                     triangle_isec[i].m2[j].m1, triangle_isec[i].m2[j].m2,
499                                     isecV[0], isecI[0], isecV[1], isecI[1]))
500            {
501                //Check if the found intersections point are in the triangle. If not, ignore.
502                //Cases are :
503                //  1) at least one dot is negative (one point in the triangle).
504                //  2) the two dot are positive but the intersection point are on all parts of the triangle, and therefore negative.
505                //If one of the point is on one side, some calculations tweak are needed.
506                //If the two points are on the triangle sides, just go with it.
507                bool should_proceed_with_cutting = true;
508                //find out if points are on one of the side
509                int p0_tri_idx = ((sqlength(triangle_isec[i].m2[j].m1 - isecV[0]) < CSG_EPSILON)?(0):(
510                                    (sqlength(triangle_isec[i].m2[j].m1 - isecV[1]) < CSG_EPSILON)?(1):(-1)));
511                int p1_tri_idx = ((sqlength(triangle_isec[i].m2[j].m2 - isecV[0]) < CSG_EPSILON)?(0):(
512                                    (sqlength(triangle_isec[i].m2[j].m2 - isecV[1]) < CSG_EPSILON)?(1):(-1)));
513                if (p0_tri_idx < 0 || p1_tri_idx < 0)
514                {
515                    float dot0 = (p0_tri_idx >= 0)?(1.0f):(dot(triangle_isec[i].m2[j].m1 - isecV[0],
516                                                               triangle_isec[i].m2[j].m1 - isecV[1]));
517                    float dot1 = (p1_tri_idx >= 0)?(1.0f):(dot(triangle_isec[i].m2[j].m2 - isecV[0],
518                                                               triangle_isec[i].m2[j].m2 - isecV[1]));
519                    float dot2 = dot(triangle_isec[i].m2[j].m1 - isecV[(p0_tri_idx == -1)?(0):(1 - p0_tri_idx)],
520                                     triangle_isec[i].m2[j].m2 - isecV[(p1_tri_idx == -1)?(0):(1 - p1_tri_idx)]);
521                    should_proceed_with_cutting = (((dot0 < .0f) || dot1 < .0f) || (dot0 > .0f && dot1 > .0f && dot2 < .0f));
522                }
523                if (should_proceed_with_cutting)
524                {
525                    //Add the new vertices
526                    int b_idx = 0;
527                    for(int k = 0; k < 2; k++)
528                    {
529                        if (b_idx == isecI[k])
530                            b_idx++;
531
532                        new_v_idx[k] = m_vert.Count();
533                        AddVertex(isecV[k]);
534                        //bad calculations of normal there.
535                        n0 = m_vert[m_indices[tri_idx + isecI[k]]].m2;
536                        n1 = m_vert[m_indices[tri_idx + (isecI[k] + 1) % 3]].m2;
537                        SetCurVertNormal(normalize((n0 + n1) * .5f));
538                        //color
539#if 0
540                        c0 = m_vert[m_indices[tri_idx + isecI[k]]].m3;
541                        c1 = m_vert[m_indices[tri_idx + (isecI[k] + 1) % 3]].m3;
542                        SetCurVertColor((c0 + c1) * .5f);
543#else
544                        SetCurVertColor(vec4(1.0f, 0.0f, 0.0f, 1.0f));
545#endif
546                    }
547
548                    //small trick, b_idx is the side index that has no intersection.
549                    v_idx0 = (b_idx == 1)?(1):(0);
550                    v_idx1 = (b_idx == 1)?(0):(1);
551
552                    //Add the new triangles
553                    AppendTriangle(m_indices[tri_idx + b_idx],              new_v_idx[v_idx0], new_v_idx[v_idx1], 0);
554                    AppendTriangle(m_indices[tri_idx + ((b_idx + 2) % 3)],  new_v_idx[v_idx1], new_v_idx[v_idx0], 0);
555                    //Replace the current triangle by on of the new one, instead of erasing it.
556                    m_indices[tri_idx + ((b_idx + 2) % 3)] = new_v_idx[v_idx0];
557
558                    if (j + 1 < triangle_isec[i].m2.Count())
559                    {
560                        triangle_isec[i].m2.Remove(j--);
561                        //add the two new triangle to the checklist.
562                        triangle_isec.Push(m_indices.Count() - 6, triangle_isec[i].m2);
563                        triangle_isec.Push(m_indices.Count() - 3, triangle_isec[i].m2);
564                    }
565                }
566            }
567        }
568    }
569#endif
570    //DONE for the splitting !
571}
572
573
574//-------------------
575
576void EasyMesh::ToggleScaleWinding()
577{
578    m_ignore_winding_on_scale = !m_ignore_winding_on_scale;
579}
580
581void EasyMesh::SetCurColor(vec4 const &color)
582{
583    m_color = color;
584}
585
586void EasyMesh::SetCurColor2(vec4 const &color)
587{
588    m_color2 = color;
589}
590
591void EasyMesh::AddVertex(vec3 const &coord)
592{
593    //TODO : m_vert.Push(coord, vec3(0.f, 1.f, 0.f), m_color, ivec2(0), vec2(0));
594    m_vert.Push(coord, vec3(0.f, 1.f, 0.f), m_color);
595}
596
597void EasyMesh::AddDuplicateVertex(int i)
598{
599    m_vert << m_vert[i];
600}
601
602void EasyMesh::AppendQuad(int i1, int i2, int i3, int i4, int base)
603{
604    m_indices << base + i1;
605    m_indices << base + i2;
606    m_indices << base + i3;
607
608    m_indices << base + i4;
609    m_indices << base + i1;
610    m_indices << base + i3;
611}
612
613void EasyMesh::AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
614{
615    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
616    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
617    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
618
619    m_indices << m_vert.Count(); AddDuplicateVertex(base + i4);
620    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
621    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
622}
623
624void EasyMesh::AppendTriangle(int i1, int i2, int i3, int base)
625{
626    m_indices << base + i1;
627    m_indices << base + i2;
628    m_indices << base + i3;
629}
630
631void EasyMesh::AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
632{
633    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
634    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
635    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
636}
637
638void EasyMesh::ComputeNormals(int start, int vcount)
639{
640    for (int i = 0; i < vcount; i += 3)
641    {
642        vec3 v0 = m_vert[m_indices[start + i + 2]].m1
643                - m_vert[m_indices[start + i + 0]].m1;
644        vec3 v1 = m_vert[m_indices[start + i + 1]].m1
645                - m_vert[m_indices[start + i + 0]].m1;
646        vec3 n = normalize(cross(v1, v0));
647
648        for (int j = 0; j < 3; j++)
649            m_vert[m_indices[start + i + j]].m2 = n;
650    }
651}
652
653void EasyMesh::SetVertColor(vec4 const &color)
654{
655    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
656        m_vert[i].m3 = color;
657}
658
659void EasyMesh::SetCurVertNormal(vec3 const &normal)
660{
661    m_vert[m_vert.Count() - 1].m2 = normal;
662}
663
664void EasyMesh::SetCurVertColor(vec4 const &color)
665{
666    m_vert[m_vert.Count() - 1].m3 = color;
667}
668
669void EasyMesh::Translate(vec3 const &v)
670{
671    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
672        m_vert[i].m1 += v;
673}
674
675void EasyMesh::RotateX(float t) { Rotate(t, vec3(1, 0, 0)); }
676void EasyMesh::RotateY(float t) { Rotate(t, vec3(0, 1, 0)); }
677void EasyMesh::RotateZ(float t) { Rotate(t, vec3(0, 0, 1)); }
678
679void EasyMesh::Rotate(float t, vec3 const &axis)
680{
681    mat3 m = mat3::rotate(t, axis);
682    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
683    {
684        m_vert[i].m1 = m * m_vert[i].m1;
685        m_vert[i].m2 = m * m_vert[i].m2;
686    }
687}
688
689void EasyMesh::RadialJitter(float r)
690{
691    Array<int> Welded;
692    Welded.Push(-1);
693    for (int i = m_cursors.Last().m1 + 1; i < m_vert.Count(); i++)
694    {
695        int j, k;
696        for (j = m_cursors.Last().m1, k = 0; j < i; j++, k++)
697        {
698            if(Welded[k] < 0)
699            {
700                vec3 diff = m_vert[i].m1 - m_vert[j].m1;
701
702                if(diff.x > 0.1f || diff.x < -0.1f)
703                    continue;
704
705                if(diff.y > 0.1f || diff.y < -0.1f)
706                    continue;
707
708                if(diff.z > 0.1f || diff.z < -0.1f)
709                    continue;
710
711                break;
712            }
713        }
714
715        if(j == i)
716            Welded.Push(-1);
717        else
718            Welded.Push(j);
719    }
720
721    int i, j;
722    for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++)
723    {
724        if(Welded[j] == -1)
725            m_vert[i].m1 *= 1.0f + RandF(r);
726        else
727            m_vert[i].m1 = m_vert[Welded[j]].m1;
728    }
729
730    ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2);
731}
732
733void EasyMesh::TaperX(float y, float z, float xoff)
734{
735    /* FIXME: this code breaks normals! */
736    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
737    {
738        m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.x + xoff);
739        m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.x + xoff);
740    }
741}
742
743void EasyMesh::TaperY(float x, float z, float yoff)
744{
745    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
746    {
747        m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.y + yoff);
748        m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.y + yoff);
749    }
750}
751
752void EasyMesh::TaperZ(float x, float y, float zoff)
753{
754    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
755    {
756        m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.z + zoff);
757        m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.z + zoff);
758    }
759}
760
761void EasyMesh::Scale(vec3 const &s)
762{
763    vec3 const invs = vec3(1) / s;
764
765    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
766    {
767        m_vert[i].m1 *= s;
768        m_vert[i].m2 = normalize(m_vert[i].m2 * invs);
769    }
770
771    /* Flip winding if the scaling involves mirroring */
772    if (!m_ignore_winding_on_scale && s.x * s.y * s.z < 0)
773    {
774        for (int i = m_cursors.Last().m2; i < m_indices.Count(); i += 3)
775        {
776            uint16_t tmp = m_indices[i + 0];
777            m_indices[i + 0] = m_indices[i + 1];
778            m_indices[i + 1] = tmp;
779        }
780    }
781}
782
783void EasyMesh::MirrorX() { DupAndScale(vec3(-1, 1, 1)); }
784void EasyMesh::MirrorY() { DupAndScale(vec3(1, -1, 1)); }
785void EasyMesh::MirrorZ() { DupAndScale(vec3(1, 1, -1)); }
786
787void EasyMesh::DupAndScale(vec3 const &s)
788{
789    int vlen = m_vert.Count() - m_cursors.Last().m1;
790    int tlen = m_indices.Count() - m_cursors.Last().m2;
791
792    for (int i = 0; i < vlen; i++)
793        AddDuplicateVertex(m_cursors.Last().m1++);
794
795    for (int i = 0; i < tlen; i++)
796        m_indices << m_indices[m_cursors.Last().m2++] + vlen;
797
798    Scale(s);
799
800    m_cursors.Last().m1 -= vlen;
801    m_cursors.Last().m2 -= tlen;
802}
803
804void EasyMesh::AppendCylinder(int nsides, float h, float r1, float r2,
805                    int dualside, int smooth)
806{
807    int vbase = m_vert.Count();
808
809    mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
810    vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n;
811
812    /* Construct normal */
813    if (r2 != .0f)
814        n = vec3(r2, h * .5f, 0.f);
815    else
816        n = vec3(r1, h * .5f, 0.f);
817    n.y = r1 * (r1 - r2) / h;
818    if (!smooth)
819        n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n;
820    n = normalize(n);
821
822    /* FIXME: normals should be flipped in two-sided mode, but that
823     * means duplicating the vertices again... */
824    for (int i = 0; i < nsides; i++)
825    {
826        AddVertex(p1); SetCurVertNormal(n);
827        AddVertex(p2); SetCurVertNormal(n);
828        SetCurVertColor(m_color2);
829
830        if (smooth)
831        {
832            int j = (i + 1) % nsides;
833            AppendQuad(j * 2, j * 2 + 1, i * 2 + 1, i * 2, vbase);
834            if (dualside)
835                AppendQuad(i * 2, i * 2 + 1, j * 2 + 1, j * 2, vbase);
836        }
837
838        p1 = rotmat * p1;
839        p2 = rotmat * p2;
840
841        if (!smooth)
842        {
843            AddVertex(p1); SetCurVertNormal(n);
844            AddVertex(p2); SetCurVertNormal(n);
845            SetCurVertColor(m_color2);
846
847            AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase);
848            if (dualside)
849                AppendQuad(i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, vbase);
850        }
851
852        n = rotmat * n;
853    }
854}
855
856void EasyMesh::AppendCapsule(int ndivisions, float h, float r)
857{
858    int ibase = m_indices.Count();
859
860    Array<vec3> vertices;
861
862    /* FIXME: we don't know how to handle even-divided capsules, so we
863     * force the count to be odd. */
864    if (h)
865        ndivisions |= 1;
866
867    /* Fill in the icosahedron vertices, rotating them so that there
868     * is a vertex at [0 1 0] and [0 -1 0] after normalisation. */
869    float phi = 0.5f + 0.5f * sqrt(5.f);
870    mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / (float)M_PI),
871                            vec3(0.f, 0.f, 1.f));
872    for (int i = 0; i < 4; i++)
873    {
874        float x = (i & 1) ? 0.5f : -0.5f;
875        float y = (i & 2) ? phi * 0.5f : phi * -0.5f;
876        vertices << mat * vec3(x, y, 0.f);
877        vertices << mat * vec3(0.f, x, y);
878        vertices << mat * vec3(y, 0.f, x);
879    }
880
881    static int const trilist[] =
882    {
883        0, 1, 2, 2, 4, 6, 3, 8, 1, 9, 4, 8,
884        7, 0, 5, 7, 11, 3, 10, 5, 6, 10, 9, 11,
885
886        0, 3, 1, 7, 3, 0, 1, 4, 2, 8, 4, 1,
887        2, 5, 0, 6, 5, 2, 6, 9, 10, 4, 9, 6,
888        7, 10, 11, 5, 10, 7, 8, 11, 9, 3, 11, 8
889    };
890
891    for (unsigned i = 0; i < sizeof(trilist) / sizeof(*trilist); i += 3)
892    {
893        vec3 const &a = vertices[trilist[i]];
894        vec3 const &b = vertices[trilist[i + 1]];
895        vec3 const &c = vertices[trilist[i + 2]];
896
897        vec3 const vb = 1.f / ndivisions * (b - a);
898        vec3 const vc = 1.f / ndivisions * (c - a);
899
900        int line = ndivisions + 1;
901
902        for (int v = 0, x = 0, y = 0; x < ndivisions + 1; v++)
903        {
904            vec3 p[] = { a + (float)x * vb + (float)y * vc,
905                         p[0] + vb,
906                         p[0] + vc,
907                         p[0] + vb + vc };
908
909            /* FIXME: when we normalise here, we get a volume that is slightly
910             * smaller than the sphere of radius 1, since we are not using
911             * the midradius. */
912            for (int k = 0; k < 4; k++)
913                p[k] = normalize(p[k]) * r;
914
915            /* If this is a capsule, grow in the Z direction */
916            if (h > 0.f)
917            {
918                for (int k = 0; k < 4; k++)
919                    p[k].y += (p[k].y > 0.f) ? 0.5f * h : -0.5f * h;
920            }
921
922            /* Add zero, one or two triangles */
923            if (y < line - 1)
924            {
925                AddVertex(p[0]);
926                AddVertex(p[1]);
927                AddVertex(p[2]);
928                AppendTriangle(0, 2, 1, m_vert.Count() - 3);
929            }
930
931            if (y < line - 2)
932            {
933                AddVertex(p[1]);
934                AddVertex(p[3]);
935                AddVertex(p[2]);
936                AppendTriangle(0, 2, 1, m_vert.Count() - 3);
937            }
938
939            y++;
940            if (y == line)
941            {
942                x++;
943                y = 0;
944                line--;
945            }
946        }
947    }
948
949    ComputeNormals(ibase, m_indices.Count() - ibase);
950}
951
952void EasyMesh::AppendSphere(int ndivisions, vec3 const &size)
953{
954    OpenBrace();
955    AppendCapsule(ndivisions, 0.f, 1.f);
956    Scale(size);
957    CloseBrace();
958}
959
960void EasyMesh::AppendTorus(int ndivisions, float r1, float r2)
961{
962    int ibase = m_indices.Count();
963    int nidiv = ndivisions; /* Cross-section */
964    int njdiv = ndivisions; /* Full circumference */
965
966    for (int j = 0; j < njdiv; j++)
967    for (int i = 0; i < 2 * nidiv; i++)
968    {
969        for (int di = 0; di < 2; di++)
970        for (int dj = 0; dj < 2; dj++)
971        {
972            int i2 = (i + di) % nidiv;
973            int j2 = (j + dj) % njdiv;
974            float x = 0.5f * (r1 + r2) + 0.5f * (r2 - r1) * (float)lol::cos(2.0 * M_PI * i2 / nidiv);
975            float y = 0.5f * (r2 - r1) * (float)lol::sin(2.0 * M_PI * i2 / nidiv);
976            float z = 0.0f;
977
978            float ca = (float)lol::cos(2.0 * M_PI * j2 / njdiv);
979            float sa = (float)lol::sin(2.0 * M_PI * j2 / njdiv);
980            float x2 = x * ca - z * sa;
981            float z2 = z * ca + x * sa;
982
983            AddVertex(vec3(x2, y, z2));
984        }
985
986        AppendTriangle(0, 2, 3, m_vert.Count() - 4);
987        AppendTriangle(0, 3, 1, m_vert.Count() - 4);
988    }
989
990    ComputeNormals(ibase, m_indices.Count() - ibase);
991}
992
993void EasyMesh::AppendBox(vec3 const &size, float chamf)
994{
995    AppendBox(size, chamf, false);
996}
997
998void EasyMesh::AppendSmoothChamfBox(vec3 const &size, float chamf)
999{
1000    AppendBox(size, chamf, true);
1001}
1002
1003void EasyMesh::AppendFlatChamfBox(vec3 const &size, float chamf)
1004{
1005    AppendBox(size, chamf, false);
1006}
1007
1008void EasyMesh::AppendBox(vec3 const &size, float chamf, bool smooth)
1009{
1010    if (chamf < 0.0f)
1011    {
1012        AppendBox(size + vec3(chamf * 2.0f), -chamf, smooth);
1013        return;
1014    }
1015
1016    int vbase = m_vert.Count();
1017    int ibase = m_indices.Count();
1018
1019    vec3 d = size * 0.5f;
1020
1021    AddVertex(vec3(-d.x, -d.y, -d.z - chamf));
1022    AddVertex(vec3(-d.x, +d.y, -d.z - chamf));
1023    AddVertex(vec3(+d.x, +d.y, -d.z - chamf));
1024    AddVertex(vec3(+d.x, -d.y, -d.z - chamf));
1025
1026    AddVertex(vec3(-d.x - chamf, -d.y, +d.z));
1027    AddVertex(vec3(-d.x - chamf, +d.y, +d.z));
1028    AddVertex(vec3(-d.x - chamf, +d.y, -d.z));
1029    AddVertex(vec3(-d.x - chamf, -d.y, -d.z));
1030
1031    AddVertex(vec3(+d.x, -d.y, +d.z + chamf));
1032    AddVertex(vec3(+d.x, +d.y, +d.z + chamf));
1033    AddVertex(vec3(-d.x, +d.y, +d.z + chamf));
1034    AddVertex(vec3(-d.x, -d.y, +d.z + chamf));
1035
1036    AddVertex(vec3(+d.x + chamf, -d.y, -d.z));
1037    AddVertex(vec3(+d.x + chamf, +d.y, -d.z));
1038    AddVertex(vec3(+d.x + chamf, +d.y, +d.z));
1039    AddVertex(vec3(+d.x + chamf, -d.y, +d.z));
1040
1041    AddVertex(vec3(-d.x, -d.y - chamf, +d.z));
1042    AddVertex(vec3(-d.x, -d.y - chamf, -d.z));
1043    AddVertex(vec3(+d.x, -d.y - chamf, -d.z));
1044    AddVertex(vec3(+d.x, -d.y - chamf, +d.z));
1045
1046    AddVertex(vec3(-d.x, +d.y + chamf, -d.z));
1047    AddVertex(vec3(-d.x, +d.y + chamf, +d.z));
1048    AddVertex(vec3(+d.x, +d.y + chamf, +d.z));
1049    AddVertex(vec3(+d.x, +d.y + chamf, -d.z));
1050
1051    /* The 6 quads on each side of the box */
1052    for (int i = 0; i < 24; i += 4)
1053        AppendQuad(i, i + 1, i + 2, i + 3, vbase);
1054
1055    ComputeNormals(ibase, m_indices.Count() - ibase);
1056    ibase = m_indices.Count();
1057
1058    /* The 8 quads at each edge of the box */
1059    if (chamf)
1060    {
1061        static int const quadlist[48] =
1062        {
1063            0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
1064            2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
1065            1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
1066        };
1067
1068        for (int i = 0; i < 48; i += 4)
1069        {
1070            if (smooth)
1071                AppendQuad(quadlist[i], quadlist[i + 1],
1072                           quadlist[i + 2], quadlist[i + 3], vbase);
1073            else
1074                AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
1075                                 quadlist[i + 2], quadlist[i + 3], vbase);
1076        }
1077    }
1078
1079    /* The 8 triangles at each corner of the box */
1080    if (chamf)
1081    {
1082        static int const trilist[24] =
1083        {
1084            3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
1085            2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
1086        };
1087
1088        for (int i = 0; i < 24; i += 3)
1089        {
1090            if (smooth)
1091                AppendTriangle(trilist[i], trilist[i + 1],
1092                               trilist[i + 2], vbase);
1093            else
1094                AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
1095                                             trilist[i + 2], vbase);
1096        }
1097    }
1098
1099    if (!smooth)
1100        ComputeNormals(ibase, m_indices.Count() - ibase);
1101}
1102
1103void EasyMesh::AppendStar(int nbranches, float r1, float r2,
1104                          int fade, int fade2)
1105{
1106    int vbase = m_vert.Count();
1107
1108    AddVertex(vec3(0.f, 0.f, 0.f));
1109
1110    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
1111    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
1112
1113    p2 = rotmat * p2;
1114    rotmat = rotmat * rotmat;
1115
1116    for (int i = 0; i < nbranches; i++)
1117    {
1118        AddVertex(p1);
1119        if (fade2)
1120            SetCurVertColor(m_color2);
1121
1122        AddVertex(p2);
1123        if (fade)
1124            SetCurVertColor(m_color2);
1125
1126        AppendQuad(0, 2 * i + 1, 2 * i + 2, (2 * i + 3) % (2 * nbranches),
1127                   vbase);
1128
1129        p1 = rotmat * p1;
1130        p2 = rotmat * p2;
1131    }
1132}
1133
1134void EasyMesh::AppendExpandedStar(int nbranches, float r1,
1135                                  float r2, float extrar)
1136{
1137    int vbase = m_vert.Count();
1138
1139    AddVertex(vec3(0.f, 0.f, 0.f));
1140
1141    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
1142    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f),
1143         p3(r1 + extrar, 0.f, 0.f), p4(r2 + extrar, 0.f, 0.f);;
1144
1145    p2 = rotmat * p2;
1146    p4 = rotmat * p4;
1147    rotmat = rotmat * rotmat;
1148
1149    for (int i = 0; i < nbranches; i++)
1150    {
1151        AddVertex(p1);
1152        AddVertex(p2);
1153        AddVertex(p3); SetCurVertColor(m_color2);
1154        AddVertex(p4); SetCurVertColor(m_color2);
1155
1156        int j = (i + 1) % nbranches;
1157        AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase);
1158        AppendQuad(4 * i + 1, 4 * i + 3, 4 * i + 4, 4 * i + 2, vbase);
1159        AppendQuad(4 * j + 1, 4 * i + 2, 4 * i + 4, 4 * j + 3, vbase);
1160
1161        p1 = rotmat * p1;
1162        p2 = rotmat * p2;
1163        p3 = rotmat * p3;
1164        p4 = rotmat * p4;
1165    }
1166}
1167
1168void EasyMesh::AppendDisc(int nsides, float r, int fade)
1169{
1170    int vbase = m_vert.Count();
1171
1172    AddVertex(vec3(0.f, 0.f, 0.f));
1173
1174    mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
1175    vec3 p1(r, 0.f, 0.f);
1176
1177    for (int i = 0; i < nsides; i++)
1178    {
1179        AddVertex(p1);
1180        if (fade)
1181            SetCurVertColor(m_color2);
1182        AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase);
1183        p1 = rotmat * p1;
1184    }
1185}
1186
1187void EasyMesh::AppendSimpleTriangle(float size, int fade)
1188{
1189    mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f);
1190    vec3 p(0.f, 0.f, size);
1191
1192    AddVertex(p);
1193    p = m * p;
1194    AddVertex(p);
1195    if (fade)
1196        SetCurVertColor(m_color2);
1197    p = m * p;
1198    AddVertex(p);
1199    if (fade)
1200        SetCurVertColor(m_color2);
1201
1202    AppendTriangle(0, 1, 2, m_vert.Count() - 3);
1203}
1204
1205void EasyMesh::AppendSimpleQuad(float size, int fade)
1206{
1207    AppendSimpleQuad(vec2(size * .5f), vec2(size * -.5f), 0.f, fade);
1208}
1209
1210void EasyMesh::AppendSimpleQuad(vec2 p1, vec2 p2, float z, int fade)
1211{
1212    AddVertex(vec3(p2.x, z, -p1.y));
1213    AddVertex(vec3(p2.x, z, -p2.y));
1214    AddVertex(vec3(p1.x, z, -p2.y));
1215    if (fade)
1216        SetCurVertColor(m_color2);
1217    AddVertex(vec3(p1.x, z, -p1.y));
1218    if (fade)
1219        SetCurVertColor(m_color2);
1220
1221    AppendQuad(3, 2, 1, 0, m_vert.Count() - 4);
1222    ComputeNormals(m_indices.Count() - 6, 6);
1223}
1224
1225void EasyMesh::AppendCog(int nbsides, float h, float r10, float r20,
1226                         float r1, float r2, float r12, float r22,
1227                         float sidemul, int offset)
1228{
1229    int ibase = m_indices.Count();
1230    int vbase = m_vert.Count();
1231
1232    /* FIXME: enforce this some other way */
1233    if (r12 < 0)
1234        h = -h;
1235
1236    mat3 rotmat = mat3::rotate(180.0f / nbsides, 0.f, 1.f, 0.f);
1237    mat3 smat1 = mat3::rotate(sidemul * 180.0f / nbsides, 0.f, 1.f, 0.f);
1238    mat3 smat2 = mat3::rotate(sidemul * -360.0f / nbsides, 0.f, 1.f, 0.f);
1239
1240    vec3 p[12];
1241
1242    p[0] = vec3(r10, h * .5f, 0.f);
1243    p[1] = rotmat * p[0];
1244    p[2] = vec3(r1, h * .5f, 0.f);
1245    p[3] = rotmat * p[2];
1246    p[4] = smat1 * (rotmat * vec3(r1 + r12, h * .5f, 0.f));
1247    p[5] = smat2 * (rotmat * p[4]);
1248
1249    p[6] = vec3(r20, h * -.5f, 0.f);
1250    p[7] = rotmat * p[6];
1251    p[8] = vec3(r2, h * -.5f, 0.f);
1252    p[9] = rotmat * p[8];
1253    p[10] = smat1 * (rotmat * vec3(r2 + r22, h * -.5f, 0.f));
1254    p[11] = smat2 * (rotmat * p[10]);
1255
1256    if (offset & 1)
1257        for (int n = 0; n < 12; n++)
1258            p[n] = rotmat * p[n];
1259
1260    rotmat = rotmat * rotmat;
1261
1262    for (int i = 0; i < nbsides; i++)
1263    {
1264        /* Each vertex will share three faces, so three different
1265         * normals, therefore we add each vertex three times. */
1266        for (int n = 0; n < 3 * 12; n++)
1267        {
1268            AddVertex(p[n / 3]);
1269            if (n / 3 >= 6)
1270                SetCurVertColor(m_color2);
1271        }
1272
1273        int j = 3 * 12 * i, k = 3 * 12 * ((i + 1) % nbsides);
1274
1275        /* The top and bottom faces */
1276        AppendQuad(j, j + 6, j + 9, j + 3, vbase);
1277        AppendQuad(j + 21, j + 27, j + 24, j + 18, vbase);
1278        AppendQuad(j + 3, j + 9, k + 6, k, vbase);
1279        AppendQuad(k + 18, k + 24, j + 27, j + 21, vbase);
1280        AppendQuad(j + 9, j + 12, j + 15, k + 6, vbase);
1281        AppendQuad(k + 24, j + 33, j + 30, j + 27, vbase);
1282
1283        /* The inner side quads */
1284        AppendQuad(j + 1, j + 4, j + 22, j + 19, vbase);
1285        AppendQuad(j + 5, k + 2, k + 20, j + 23, vbase);
1286
1287        /* The outer side quads */
1288        AppendQuad(j + 10, j + 7, j + 25, j + 28, vbase);
1289        AppendQuad(j + 13, j + 11, j + 29, j + 31, vbase);
1290        AppendQuad(j + 16, j + 14, j + 32, j + 34, vbase);
1291        AppendQuad(k + 8, j + 17, j + 35, k + 26, vbase);
1292
1293        for (int n = 0; n < 12; n++)
1294            p[n] = rotmat * p[n];
1295    }
1296
1297    ComputeNormals(ibase, m_indices.Count() - ibase);
1298}
1299
1300void EasyMesh::Chamfer(float f)
1301{
1302    int vlen = m_vert.Count() - m_cursors.Last().m1;
1303    int ilen = m_indices.Count() - m_cursors.Last().m2;
1304
1305    /* Step 1: enumerate all faces. This is done by merging triangles
1306     * that are coplanar and share an edge. */
1307    int *triangle_classes = new int[ilen / 3];
1308    for (int i = 0; i < ilen / 3; i++)
1309        triangle_classes[i] = -1;
1310
1311    for (int i = 0; i < ilen / 3; i++)
1312    {
1313
1314    }
1315
1316    /* Fun shit: reduce all triangles */
1317    int *vertices = new int[vlen];
1318    memset(vertices, 0, vlen * sizeof(int));
1319    for (int i = 0; i < ilen; i++)
1320        vertices[m_indices[i]]++;
1321
1322    for (int i = 0; i < ilen / 3; i++)
1323    {
1324    #if 0
1325        if (vertices[m_indices[i * 3]] > 1)
1326            continue;
1327        if (vertices[m_indices[i * 3 + 1]] > 1)
1328            continue;
1329        if (vertices[m_indices[i * 3 + 2]] > 1)
1330            continue;
1331    #endif
1332
1333        vec3 bary = 1.f / 3.f * (m_vert[m_indices[i * 3]].m1 +
1334                                 m_vert[m_indices[i * 3 + 1]].m1 +
1335                                 m_vert[m_indices[i * 3 + 2]].m1);
1336        for (int k = 0; k < 3; k++)
1337        {
1338            vec3 &p = m_vert[m_indices[i * 3 + k]].m1;
1339            p -= normalize(p - bary) * f;
1340        }
1341    }
1342}
1343
1344} /* namespace lol */
1345
Note: See TracBrowser for help on using the repository browser.