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

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

Added VertexDictionnary object to manage vertices with same coord && connected vertices.
Added UVs system with and UVs generation test (not very conclusive)

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