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

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

easymesh: fix point light handling.

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