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

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

Added CSG v0.001a : not optimized, too much operation makes it slow. triangle count is not optimized.
Useage : "...[.... csg*]" equals "current mesh -CSG- the mesh in the braces".
Keywords : CsgUnion<csgu>, CsgSubstract<csgs>, CsgAnd<csga>, CsgXor<csgx>
TODO : cleanup useless code.
TODO : Some bugs are still present, some face that disappear should not.
TODO : Correct epsilon useage (see geometry files).
TODO : Coplanar face are not handled -at all-.
TODO : Vertex count goes through the roof in case of a Xor.

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