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

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

easymesh : CSG operation is now handled with a safe enum.

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