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

Last change on this file since 2116 was 2116, checked in by touky, 8 years ago

Added tsw (ToggleScaleWinding) command in EasyMesh Parser to make old-school celShading contour.

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