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

Last change on this file since 2277 was 2277, checked in by sam, 8 years ago

build: hide LolFx external declarations behind macros.

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