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

Last change on this file since 2318 was 2318, checked in by sam, 7 years ago

build: fix all vector/scalar type mismatches such as "vec2 * double"
instead of "vec2 * float".

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