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

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

build: fix the WTFPL site URL in all code comments.

File size: 25.6 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
5//            (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
6//            (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
7//   This program is free software; you can redistribute it and/or
8//   modify it under the terms of the Do What The Fuck You Want To
9//   Public License, Version 2, as published by Sam Hocevar. See
10//   http://www.wtfpl.net/ for more details.
11//
12
13//
14// The EasyMesh class
15// ------------------
16//
17
18#if defined HAVE_CONFIG_H
19#   include "config.h"
20#endif
21
22#if defined _XBOX
23#   define _USE_MATH_DEFINES /* for M_PI */
24#   include <xtl.h>
25#   undef near /* Fuck Microsoft */
26#   undef far /* Fuck Microsoft again */
27#elif defined _WIN32
28#   define _USE_MATH_DEFINES /* for M_PI */
29#   define WIN32_LEAN_AND_MEAN
30#   include <windows.h>
31#   undef near /* Fuck Microsoft */
32#   undef far /* Fuck Microsoft again */
33#endif
34
35#include "core.h"
36#include "easymesh/easymesh-compiler.h"
37
38extern char const *lolfx_shiny;
39
40namespace lol
41{
42
43EasyMesh::EasyMesh()
44  : m_color(0), m_color2(0), m_ignore_winding_on_scale(0)
45{
46    m_cursors.Push(0, 0);
47}
48
49bool EasyMesh::Compile(char const *command)
50{
51    EasyMeshCompiler mc(*this);
52    return mc.ParseString(command);
53}
54
55void EasyMesh::OpenBrace()
56{
57    m_cursors.Push(m_vert.Count(), m_indices.Count());
58}
59
60void EasyMesh::CloseBrace()
61{
62    m_cursors.Pop();
63}
64
65void EasyMesh::MeshConvert()
66{
67    m_gpu.shader = Shader::Create(lolfx_shiny);
68
69    m_gpu.modelview = m_gpu.shader->GetUniformLocation("in_ModelView");
70    m_gpu.view = m_gpu.shader->GetUniformLocation("in_View");
71        m_gpu.invview = m_gpu.shader->GetUniformLocation("in_Inv_View");
72    m_gpu.proj = m_gpu.shader->GetUniformLocation("in_Proj");
73    m_gpu.normalmat = m_gpu.shader->GetUniformLocation("in_NormalMat");
74    m_gpu.damage = m_gpu.shader->GetUniformLocation("in_Damage");
75    m_gpu.coord = m_gpu.shader->GetAttribLocation("in_Vertex",
76                                          VertexUsage::Position, 0);
77    m_gpu.norm = m_gpu.shader->GetAttribLocation("in_Normal",
78                                         VertexUsage::Normal, 0);
79    m_gpu.color = m_gpu.shader->GetAttribLocation("in_Color",
80                                          VertexUsage::Color, 0);
81
82    m_gpu.vdecl = new VertexDeclaration(
83        VertexStream<vec3,vec3,u8vec4>(VertexUsage::Position,
84                                       VertexUsage::Normal,
85                                       VertexUsage::Color));
86
87    Array<vec3,vec3,u8vec4> vertexlist;
88    for (int i = 0; i < m_vert.Count(); i++)
89        vertexlist.Push(m_vert[i].m1,
90                        m_vert[i].m2,
91                        (u8vec4)(m_vert[i].m3 * 255.f));
92
93    Array<uint16_t> indexlist;
94    for (int i = 0; i < m_indices.Count(); i += 3)
95    {
96        indexlist << m_indices[i + 0];
97        indexlist << m_indices[i + 1];
98        indexlist << m_indices[i + 2];
99    }
100
101    m_gpu.vbo = new VertexBuffer(vertexlist.Bytes());
102    void *mesh = m_gpu.vbo->Lock(0, 0);
103    memcpy(mesh, &vertexlist[0], vertexlist.Bytes());
104    m_gpu.vbo->Unlock();
105
106    m_gpu.ibo = new IndexBuffer(indexlist.Bytes());
107    void *indices = m_gpu.ibo->Lock(0, 0);
108    memcpy(indices, &indexlist[0], indexlist.Bytes());
109    m_gpu.ibo->Unlock();
110
111    m_gpu.vertexcount = vertexlist.Count();
112    m_gpu.indexcount = indexlist.Count();
113}
114
115void EasyMesh::Render(mat4 const &model, float damage)
116{
117    mat4 modelview = Scene::GetDefault()->GetViewMatrix() * model;
118    mat3 normalmat = transpose(inverse(mat3(modelview)));
119
120    m_gpu.shader->Bind();
121    m_gpu.shader->SetUniform(m_gpu.modelview, modelview);
122    m_gpu.shader->SetUniform(m_gpu.view, Scene::GetDefault()->GetViewMatrix());
123    m_gpu.shader->SetUniform(m_gpu.invview, inverse(Scene::GetDefault()->GetViewMatrix()));
124    m_gpu.shader->SetUniform(m_gpu.proj, Scene::GetDefault()->GetProjMatrix());
125    m_gpu.shader->SetUniform(m_gpu.normalmat, normalmat);
126    m_gpu.shader->SetUniform(m_gpu.damage, damage);
127    m_gpu.vdecl->Bind();
128    m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord, m_gpu.norm, m_gpu.color);
129    m_gpu.ibo->Bind();
130    m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles,
131                                     0, 0, m_gpu.vertexcount,
132                                     0, m_gpu.indexcount);
133    m_gpu.ibo->Unbind();
134    m_gpu.vdecl->Unbind();
135}
136
137void EasyMesh::ToggleScaleWinding()
138{
139    m_ignore_winding_on_scale = !m_ignore_winding_on_scale;
140}
141
142void EasyMesh::SetCurColor(vec4 const &color)
143{
144    m_color = color;
145}
146
147void EasyMesh::SetCurColor2(vec4 const &color)
148{
149    m_color2 = color;
150}
151
152void EasyMesh::AddVertex(vec3 const &coord)
153{
154    m_vert.Push(coord, vec3(0.f, 1.f, 0.f), m_color);
155}
156
157void EasyMesh::AddDuplicateVertex(int i)
158{
159    m_vert.Push(m_vert[i].m1, vec3(0.f, 1.f, 0.f), m_vert[i].m3);
160}
161
162void EasyMesh::AppendQuad(int i1, int i2, int i3, int i4, int base)
163{
164    m_indices << base + i1;
165    m_indices << base + i2;
166    m_indices << base + i3;
167
168    m_indices << base + i4;
169    m_indices << base + i1;
170    m_indices << base + i3;
171}
172
173void EasyMesh::AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
174{
175    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
176    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
177    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
178
179    m_indices << m_vert.Count(); AddDuplicateVertex(base + i4);
180    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
181    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
182}
183
184void EasyMesh::AppendTriangle(int i1, int i2, int i3, int base)
185{
186    m_indices << base + i1;
187    m_indices << base + i2;
188    m_indices << base + i3;
189}
190
191void EasyMesh::AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
192{
193    m_indices << m_vert.Count(); AddDuplicateVertex(base + i1);
194    m_indices << m_vert.Count(); AddDuplicateVertex(base + i2);
195    m_indices << m_vert.Count(); AddDuplicateVertex(base + i3);
196}
197
198void EasyMesh::ComputeNormals(int start, int vcount)
199{
200    for (int i = 0; i < vcount; i += 3)
201    {
202        vec3 v0 = m_vert[m_indices[start + i + 2]].m1
203                - m_vert[m_indices[start + i + 0]].m1;
204        vec3 v1 = m_vert[m_indices[start + i + 1]].m1
205                - m_vert[m_indices[start + i + 0]].m1;
206        vec3 n = normalize(cross(v1, v0));
207
208        for (int j = 0; j < 3; j++)
209            m_vert[m_indices[start + i + j]].m2 = n;
210    }
211}
212
213void EasyMesh::SetVertColor(vec4 const &color)
214{
215    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
216        m_vert[i].m3 = color;
217}
218
219void EasyMesh::SetCurVertNormal(vec3 const &normal)
220{
221    m_vert[m_vert.Count() - 1].m2 = normal;
222}
223
224void EasyMesh::SetCurVertColor(vec4 const &color)
225{
226    m_vert[m_vert.Count() - 1].m3 = color;
227}
228
229void EasyMesh::Translate(vec3 const &v)
230{
231    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
232        m_vert[i].m1 += v;
233}
234
235void EasyMesh::RotateX(float t) { Rotate(t, vec3(1, 0, 0)); }
236void EasyMesh::RotateY(float t) { Rotate(t, vec3(0, 1, 0)); }
237void EasyMesh::RotateZ(float t) { Rotate(t, vec3(0, 0, 1)); }
238
239void EasyMesh::Rotate(float t, vec3 const &axis)
240{
241    mat3 m = mat3::rotate(t, axis);
242    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
243    {
244        m_vert[i].m1 = m * m_vert[i].m1;
245        m_vert[i].m2 = m * m_vert[i].m2;
246    }
247}
248
249void EasyMesh::RadialJitter(float r)
250{
251    Array<int> Welded;
252    Welded.Push(-1);
253    for (int i = m_cursors.Last().m1 + 1; i < m_vert.Count(); i++)
254    {
255        int j, k;
256        for (j = m_cursors.Last().m1, k = 0; j < i; j++, k++)
257        {
258            if(Welded[k] < 0)
259            {
260                vec3 diff = m_vert[i].m1 - m_vert[j].m1;
261
262                if(diff.x > 0.1f || diff.x < -0.1f)
263                    continue;
264
265                if(diff.y > 0.1f || diff.y < -0.1f)
266                    continue;
267
268                if(diff.z > 0.1f || diff.z < -0.1f)
269                    continue;
270
271                break;
272            }
273        }
274
275        if(j == i)
276            Welded.Push(-1);
277        else
278            Welded.Push(j);
279    }
280
281    int i, j;
282    for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++)
283    {
284        if(Welded[j] == -1)
285            m_vert[i].m1 *= 1.0f + RandF(r);
286        else
287            m_vert[i].m1 = m_vert[Welded[j]].m1;
288    }
289
290    ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2);
291}
292
293void EasyMesh::TaperX(float y, float z, float xoff)
294{
295    /* FIXME: this code breaks normals! */
296    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
297    {
298        m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.x + xoff);
299        m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.x + xoff);
300    }
301}
302
303void EasyMesh::TaperY(float x, float z, float yoff)
304{
305    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
306    {
307        m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.y + yoff);
308        m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.y + yoff);
309    }
310}
311
312void EasyMesh::TaperZ(float x, float y, float zoff)
313{
314    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
315    {
316        m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.z + zoff);
317        m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.z + zoff);
318    }
319}
320
321void EasyMesh::Scale(vec3 const &s)
322{
323    vec3 const invs = vec3(1) / s;
324
325    for (int i = m_cursors.Last().m1; i < m_vert.Count(); i++)
326    {
327        m_vert[i].m1 *= s;
328        m_vert[i].m2 = normalize(m_vert[i].m2 * invs);
329    }
330
331    /* Flip winding if the scaling involves mirroring */
332    if (!m_ignore_winding_on_scale && s.x * s.y * s.z < 0)
333    {
334        for (int i = m_cursors.Last().m2; i < m_indices.Count(); i += 3)
335        {
336            uint16_t tmp = m_indices[i + 0];
337            m_indices[i + 0] = m_indices[i + 1];
338            m_indices[i + 1] = tmp;
339        }
340    }
341}
342
343void EasyMesh::MirrorX() { DupAndScale(vec3(-1, 1, 1)); }
344void EasyMesh::MirrorY() { DupAndScale(vec3(1, -1, 1)); }
345void EasyMesh::MirrorZ() { DupAndScale(vec3(1, 1, -1)); }
346
347void EasyMesh::DupAndScale(vec3 const &s)
348{
349    int vlen = m_vert.Count() - m_cursors.Last().m1;
350    int tlen = m_indices.Count() - m_cursors.Last().m2;
351
352    for (int i = 0; i < vlen; i++)
353        m_vert << m_vert[m_cursors.Last().m1++];
354
355    for (int i = 0; i < tlen; i++)
356        m_indices << m_indices[m_cursors.Last().m2++] + vlen;
357
358    Scale(s);
359
360    m_cursors.Last().m1 -= vlen;
361    m_cursors.Last().m2 -= tlen;
362}
363
364void EasyMesh::AppendCylinder(int nsides, float h, float r1, float r2,
365                    int dualside, int smooth)
366{
367    int vbase = m_vert.Count();
368
369    mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
370    vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n;
371
372    /* Construct normal */
373    if (r2 != .0f)
374        n = vec3(r2, h * .5f, 0.f);
375    else
376        n = vec3(r1, h * .5f, 0.f);
377    n.y = r1 * (r1 - r2) / h;
378    if (!smooth)
379        n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n;
380    n = normalize(n);
381
382    /* FIXME: normals should be flipped in two-sided mode, but that
383     * means duplicating the vertices again... */
384    for (int i = 0; i < nsides; i++)
385    {
386        AddVertex(p1); SetCurVertNormal(n);
387        AddVertex(p2); SetCurVertNormal(n);
388        SetCurVertColor(m_color2);
389
390        if (smooth)
391        {
392            int j = (i + 1) % nsides;
393            AppendQuad(j * 2, j * 2 + 1, i * 2 + 1, i * 2, vbase);
394            if (dualside)
395                AppendQuad(i * 2, i * 2 + 1, j * 2 + 1, j * 2, vbase);
396        }
397
398        p1 = rotmat * p1;
399        p2 = rotmat * p2;
400
401        if (!smooth)
402        {
403            AddVertex(p1); SetCurVertNormal(n);
404            AddVertex(p2); SetCurVertNormal(n);
405            SetCurVertColor(m_color2);
406
407            AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase);
408            if (dualside)
409                AppendQuad(i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, vbase);
410        }
411
412        n = rotmat * n;
413    }
414}
415
416void EasyMesh::AppendCapsule(int ndivisions, float h, float r)
417{
418    int ibase = m_indices.Count();
419
420    Array<vec3> vertices;
421
422    /* FIXME: we don't know how to handle even-divided capsules, so we
423     * force the count to be odd. */
424    if (h)
425        ndivisions |= 1;
426
427    /* Fill in the icosahedron vertices, rotating them so that there
428     * is a vertex at [0 1 0] and [0 -1 0] after normalisation. */
429    float phi = 0.5f + 0.5f * sqrt(5.f);
430    mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / M_PI),
431                            vec3(0.f, 0.f, 1.f));
432    for (int i = 0; i < 4; i++)
433    {
434        float x = (i & 1) ? 0.5f : -0.5f;
435        float y = (i & 2) ? phi * 0.5f : phi * -0.5f;
436        vertices << mat * vec3(x, y, 0.f);
437        vertices << mat * vec3(0.f, x, y);
438        vertices << mat * vec3(y, 0.f, x);
439    }
440
441    static int const trilist[] =
442    {
443        0, 1, 2, 2, 4, 6, 3, 8, 1, 9, 4, 8,
444        7, 0, 5, 7, 11, 3, 10, 5, 6, 10, 9, 11,
445
446        0, 3, 1, 7, 3, 0, 1, 4, 2, 8, 4, 1,
447        2, 5, 0, 6, 5, 2, 6, 9, 10, 4, 9, 6,
448        7, 10, 11, 5, 10, 7, 8, 11, 9, 3, 11, 8
449    };
450
451    for (unsigned i = 0; i < sizeof(trilist) / sizeof(*trilist); i += 3)
452    {
453        vec3 const &a = vertices[trilist[i]];
454        vec3 const &b = vertices[trilist[i + 1]];
455        vec3 const &c = vertices[trilist[i + 2]];
456
457        vec3 const vb = 1.f / ndivisions * (b - a);
458        vec3 const vc = 1.f / ndivisions * (c - a);
459
460        int line = ndivisions + 1;
461
462        for (int v = 0, x = 0, y = 0; x < ndivisions + 1; v++)
463        {
464            vec3 p[] = { a + x * vb + y * vc,
465                         p[0] + vb,
466                         p[0] + vc,
467                         p[0] + vb + vc };
468
469            /* FIXME: when we normalise here, we get a volume that is slightly
470             * smaller than the sphere of radius 1, since we are not using
471             * the midradius. */
472            for (int k = 0; k < 4; k++)
473                p[k] = normalize(p[k]) * r;
474
475            /* If this is a capsule, grow in the Z direction */
476            if (h > 0.f)
477            {
478                for (int k = 0; k < 4; k++)
479                    p[k].y += (p[k].y > 0.f) ? 0.5f * h : -0.5f * h;
480            }
481
482            /* Add zero, one or two triangles */
483            if (y < line - 1)
484            {
485                AddVertex(p[0]);
486                AddVertex(p[1]);
487                AddVertex(p[2]);
488                AppendTriangle(0, 2, 1, m_vert.Count() - 3);
489            }
490
491            if (y < line - 2)
492            {
493                AddVertex(p[1]);
494                AddVertex(p[3]);
495                AddVertex(p[2]);
496                AppendTriangle(0, 2, 1, m_vert.Count() - 3);
497            }
498
499            y++;
500            if (y == line)
501            {
502                x++;
503                y = 0;
504                line--;
505            }
506        }
507    }
508
509    ComputeNormals(ibase, m_indices.Count() - ibase);
510}
511
512void EasyMesh::AppendSphere(int ndivisions, vec3 const &size)
513{
514    OpenBrace();
515    AppendCapsule(ndivisions, 0.f, 1.f);
516    Scale(size);
517    CloseBrace();
518}
519
520void EasyMesh::AppendTorus(int ndivisions, float r1, float r2)
521{
522    int ibase = m_indices.Count();
523    int nidiv = ndivisions; /* Cross-section */
524    int njdiv = ndivisions; /* Full circumference */
525
526    for (int j = 0; j < njdiv; j++)
527    for (int i = 0; i < 2 * nidiv; i++)
528    {
529        for (int di = 0; di < 2; di++)
530        for (int dj = 0; dj < 2; dj++)
531        {
532            int i2 = (i + di) % nidiv;
533            int j2 = (j + dj) % njdiv;
534            float x = 0.5f * (r1 + r2) + 0.5 * (r2 - r1) * lol::cos(2.0 * M_PI * i2 / nidiv);
535            float y = 0.5f * (r2 - r1) * lol::sin(2.0 * M_PI * i2 / nidiv);
536            float z = 0.0f;
537
538            float ca = lol::cos(2.0 * M_PI * j2 / njdiv);
539            float sa = lol::sin(2.0 * M_PI * j2 / njdiv);
540            float x2 = x * ca - z * sa;
541            float z2 = z * ca + x * sa;
542
543            AddVertex(vec3(x2, y, z2));
544        }
545
546        AppendTriangle(0, 2, 3, m_vert.Count() - 4);
547        AppendTriangle(0, 3, 1, m_vert.Count() - 4);
548    }
549
550    ComputeNormals(ibase, m_indices.Count() - ibase);
551}
552
553void EasyMesh::AppendBox(vec3 const &size, float chamf)
554{
555    AppendBox(size, chamf, false);
556}
557
558void EasyMesh::AppendSmoothChamfBox(vec3 const &size, float chamf)
559{
560    AppendBox(size, chamf, true);
561}
562
563void EasyMesh::AppendFlatChamfBox(vec3 const &size, float chamf)
564{
565    AppendBox(size, chamf, false);
566}
567
568void EasyMesh::AppendBox(vec3 const &size, float chamf, bool smooth)
569{
570    if (chamf < 0.0f)
571    {
572        AppendBox(size + vec3(chamf * 2.0f), -chamf, smooth);
573        return;
574    }
575
576    int vbase = m_vert.Count();
577    int ibase = m_indices.Count();
578
579    vec3 d = size * 0.5f;
580
581    AddVertex(vec3(-d.x, -d.y, -d.z - chamf));
582    AddVertex(vec3(-d.x, +d.y, -d.z - chamf));
583    AddVertex(vec3(+d.x, +d.y, -d.z - chamf));
584    AddVertex(vec3(+d.x, -d.y, -d.z - chamf));
585
586    AddVertex(vec3(-d.x - chamf, -d.y, +d.z));
587    AddVertex(vec3(-d.x - chamf, +d.y, +d.z));
588    AddVertex(vec3(-d.x - chamf, +d.y, -d.z));
589    AddVertex(vec3(-d.x - chamf, -d.y, -d.z));
590
591    AddVertex(vec3(+d.x, -d.y, +d.z + chamf));
592    AddVertex(vec3(+d.x, +d.y, +d.z + chamf));
593    AddVertex(vec3(-d.x, +d.y, +d.z + chamf));
594    AddVertex(vec3(-d.x, -d.y, +d.z + chamf));
595
596    AddVertex(vec3(+d.x + chamf, -d.y, -d.z));
597    AddVertex(vec3(+d.x + chamf, +d.y, -d.z));
598    AddVertex(vec3(+d.x + chamf, +d.y, +d.z));
599    AddVertex(vec3(+d.x + chamf, -d.y, +d.z));
600
601    AddVertex(vec3(-d.x, -d.y - chamf, +d.z));
602    AddVertex(vec3(-d.x, -d.y - chamf, -d.z));
603    AddVertex(vec3(+d.x, -d.y - chamf, -d.z));
604    AddVertex(vec3(+d.x, -d.y - chamf, +d.z));
605
606    AddVertex(vec3(-d.x, +d.y + chamf, -d.z));
607    AddVertex(vec3(-d.x, +d.y + chamf, +d.z));
608    AddVertex(vec3(+d.x, +d.y + chamf, +d.z));
609    AddVertex(vec3(+d.x, +d.y + chamf, -d.z));
610
611    /* The 6 quads on each side of the box */
612    for (int i = 0; i < 24; i += 4)
613        AppendQuad(i, i + 1, i + 2, i + 3, vbase);
614
615    ComputeNormals(ibase, m_indices.Count() - ibase);
616    ibase = m_indices.Count();
617
618    /* The 8 quads at each edge of the box */
619    if (chamf)
620    {
621        static int const quadlist[48] =
622        {
623            0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
624            2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
625            1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
626        };
627
628        for (int i = 0; i < 48; i += 4)
629        {
630            if (smooth)
631                AppendQuad(quadlist[i], quadlist[i + 1],
632                           quadlist[i + 2], quadlist[i + 3], vbase);
633            else
634                AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
635                                 quadlist[i + 2], quadlist[i + 3], vbase);
636        }
637    }
638
639    /* The 8 triangles at each corner of the box */
640    if (chamf)
641    {
642        static int const trilist[24] =
643        {
644            3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
645            2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
646        };
647
648        for (int i = 0; i < 24; i += 3)
649        {
650            if (smooth)
651                AppendTriangle(trilist[i], trilist[i + 1],
652                               trilist[i + 2], vbase);
653            else
654                AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
655                                             trilist[i + 2], vbase);
656        }
657    }
658
659    if (!smooth)
660        ComputeNormals(ibase, m_indices.Count() - ibase);
661}
662
663void EasyMesh::AppendStar(int nbranches, float r1, float r2,
664                          int fade, int fade2)
665{
666    int vbase = m_vert.Count();
667
668    AddVertex(vec3(0.f, 0.f, 0.f));
669
670    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
671    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
672
673    p2 = rotmat * p2;
674    rotmat = rotmat * rotmat;
675
676    for (int i = 0; i < nbranches; i++)
677    {
678        AddVertex(p1);
679        if (fade2)
680            SetCurVertColor(m_color2);
681
682        AddVertex(p2);
683        if (fade)
684            SetCurVertColor(m_color2);
685
686        AppendQuad(0, 2 * i + 1, 2 * i + 2, (2 * i + 3) % (2 * nbranches),
687                   vbase);
688
689        p1 = rotmat * p1;
690        p2 = rotmat * p2;
691    }
692}
693
694void EasyMesh::AppendExpandedStar(int nbranches, float r1,
695                                  float r2, float extrar)
696{
697    int vbase = m_vert.Count();
698
699    AddVertex(vec3(0.f, 0.f, 0.f));
700
701    mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
702    vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f),
703         p3(r1 + extrar, 0.f, 0.f), p4(r2 + extrar, 0.f, 0.f);;
704
705    p2 = rotmat * p2;
706    p4 = rotmat * p4;
707    rotmat = rotmat * rotmat;
708
709    for (int i = 0; i < nbranches; i++)
710    {
711        AddVertex(p1);
712        AddVertex(p2);
713        AddVertex(p3); SetCurVertColor(m_color2);
714        AddVertex(p4); SetCurVertColor(m_color2);
715
716        int j = (i + 1) % nbranches;
717        AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase);
718        AppendQuad(4 * i + 1, 4 * i + 3, 4 * i + 4, 4 * i + 2, vbase);
719        AppendQuad(4 * j + 1, 4 * i + 2, 4 * i + 4, 4 * j + 3, vbase);
720
721        p1 = rotmat * p1;
722        p2 = rotmat * p2;
723        p3 = rotmat * p3;
724        p4 = rotmat * p4;
725    }
726}
727
728void EasyMesh::AppendDisc(int nsides, float r, int fade)
729{
730    int vbase = m_vert.Count();
731
732    AddVertex(vec3(0.f, 0.f, 0.f));
733
734    mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
735    vec3 p1(r, 0.f, 0.f);
736
737    for (int i = 0; i < nsides; i++)
738    {
739        AddVertex(p1);
740        if (fade)
741            SetCurVertColor(m_color2);
742        AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase);
743        p1 = rotmat * p1;
744    }
745}
746
747void EasyMesh::AppendSimpleTriangle(float size, int fade)
748{
749    mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f);
750    vec3 p(0.f, 0.f, size);
751
752    AddVertex(p);
753    p = m * p;
754    AddVertex(p);
755    if (fade)
756        SetCurVertColor(m_color2);
757    p = m * p;
758    AddVertex(p);
759    if (fade)
760        SetCurVertColor(m_color2);
761
762    AppendTriangle(0, 1, 2, m_vert.Count() - 3);
763}
764
765void EasyMesh::AppendSimpleQuad(float size, int fade)
766{
767    AppendSimpleQuad(vec2(size * .5f), vec2(size * -.5f), 0.f, fade);
768}
769
770void EasyMesh::AppendSimpleQuad(vec2 p1, vec2 p2, float z, int fade)
771{
772    AddVertex(vec3(p2.x, z, -p1.y));
773    AddVertex(vec3(p2.x, z, -p2.y));
774    AddVertex(vec3(p1.x, z, -p2.y));
775    if (fade)
776        SetCurVertColor(m_color2);
777    AddVertex(vec3(p1.x, z, -p1.y));
778    if (fade)
779        SetCurVertColor(m_color2);
780
781    AppendQuad(3, 2, 1, 0, m_vert.Count() - 4);
782    ComputeNormals(m_indices.Count() - 6, 6);
783}
784
785void EasyMesh::AppendCog(int nbsides, float h, float r10, float r20,
786                         float r1, float r2, float r12, float r22,
787                         float sidemul, int offset)
788{
789    int ibase = m_indices.Count();
790    int vbase = m_vert.Count();
791
792    /* FIXME: enforce this some other way */
793    if (r12 < 0)
794        h = -h;
795
796    mat3 rotmat = mat3::rotate(180.0f / nbsides, 0.f, 1.f, 0.f);
797    mat3 smat1 = mat3::rotate(sidemul * 180.0f / nbsides, 0.f, 1.f, 0.f);
798    mat3 smat2 = mat3::rotate(sidemul * -360.0f / nbsides, 0.f, 1.f, 0.f);
799
800    vec3 p[12];
801
802    p[0] = vec3(r10, h * .5f, 0.f);
803    p[1] = rotmat * p[0];
804    p[2] = vec3(r1, h * .5f, 0.f);
805    p[3] = rotmat * p[2];
806    p[4] = smat1 * (rotmat * vec3(r1 + r12, h * .5f, 0.f));
807    p[5] = smat2 * (rotmat * p[4]);
808
809    p[6] = vec3(r20, h * -.5f, 0.f);
810    p[7] = rotmat * p[6];
811    p[8] = vec3(r2, h * -.5f, 0.f);
812    p[9] = rotmat * p[8];
813    p[10] = smat1 * (rotmat * vec3(r2 + r22, h * -.5f, 0.f));
814    p[11] = smat2 * (rotmat * p[10]);
815
816    if (offset & 1)
817        for (int n = 0; n < 12; n++)
818            p[n] = rotmat * p[n];
819
820    rotmat = rotmat * rotmat;
821
822    for (int i = 0; i < nbsides; i++)
823    {
824        /* Each vertex will share three faces, so three different
825         * normals, therefore we add each vertex three times. */
826        for (int n = 0; n < 3 * 12; n++)
827        {
828            AddVertex(p[n / 3]);
829            if (n / 3 >= 6)
830                SetCurVertColor(m_color2);
831        }
832
833        int j = 3 * 12 * i, k = 3 * 12 * ((i + 1) % nbsides);
834
835        /* The top and bottom faces */
836        AppendQuad(j, j + 6, j + 9, j + 3, vbase);
837        AppendQuad(j + 21, j + 27, j + 24, j + 18, vbase);
838        AppendQuad(j + 3, j + 9, k + 6, k, vbase);
839        AppendQuad(k + 18, k + 24, j + 27, j + 21, vbase);
840        AppendQuad(j + 9, j + 12, j + 15, k + 6, vbase);
841        AppendQuad(k + 24, j + 33, j + 30, j + 27, vbase);
842
843        /* The inner side quads */
844        AppendQuad(j + 1, j + 4, j + 22, j + 19, vbase);
845        AppendQuad(j + 5, k + 2, k + 20, j + 23, vbase);
846
847        /* The outer side quads */
848        AppendQuad(j + 10, j + 7, j + 25, j + 28, vbase);
849        AppendQuad(j + 13, j + 11, j + 29, j + 31, vbase);
850        AppendQuad(j + 16, j + 14, j + 32, j + 34, vbase);
851        AppendQuad(k + 8, j + 17, j + 35, k + 26, vbase);
852
853        for (int n = 0; n < 12; n++)
854            p[n] = rotmat * p[n];
855    }
856
857    ComputeNormals(ibase, m_indices.Count() - ibase);
858}
859
860void EasyMesh::Chamfer(float f)
861{
862    int vlen = m_vert.Count() - m_cursors.Last().m1;
863    int ilen = m_indices.Count() - m_cursors.Last().m2;
864
865    /* Step 1: enumerate all faces. This is done by merging triangles
866     * that are coplanar and share an edge. */
867    int *triangle_classes = new int[ilen / 3];
868    for (int i = 0; i < ilen / 3; i++)
869        triangle_classes[i] = -1;
870
871    for (int i = 0; i < ilen / 3; i++)
872    {
873
874    }
875
876    /* Fun shit: reduce all triangles */
877    int *vertices = new int[vlen];
878    memset(vertices, 0, vlen * sizeof(int));
879    for (int i = 0; i < ilen; i++)
880        vertices[m_indices[i]]++;
881
882    for (int i = 0; i < ilen / 3; i++)
883    {
884    #if 0
885        if (vertices[m_indices[i * 3]] > 1)
886            continue;
887        if (vertices[m_indices[i * 3 + 1]] > 1)
888            continue;
889        if (vertices[m_indices[i * 3 + 2]] > 1)
890            continue;
891    #endif
892
893        vec3 bary = 1.f / 3.f * (m_vert[m_indices[i * 3]].m1 +
894                                 m_vert[m_indices[i * 3 + 1]].m1 +
895                                 m_vert[m_indices[i * 3 + 2]].m1);
896        for (int k = 0; k < 3; k++)
897        {
898            vec3 &p = m_vert[m_indices[i * 3 + k]].m1;
899            p -= normalize(p - bary) * f;
900        }
901    }
902}
903
904} /* namespace lol */
905
Note: See TracBrowser for help on using the repository browser.