source: trunk/orbital/mesh.h @ 1330

Last change on this file since 1330 was 1330, checked in by sam, 9 years ago

orbital: get rid of the normal matrix; we can compute it on the fly later.

  • Property svn:keywords set to Id
File size: 28.3 KB
Line 
1//
2// Orbital
3//
4// Copyright: (c) 2012 Various People
5//
6
7/* TODO for this file:
8 *  - rename "AppendQuadVert" to "AddVertex" or something; it has nothing
9 *    to do with quads.
10 */
11
12#include "CommandParser.h"
13
14#if !defined __MESH_H__
15#define __MESH_H__
16
17class Mesh : public CommandParser
18{
19public:
20    Mesh()
21      : m_color(0), m_color2(0),
22        m_vert_cursor(0), m_quadidx_cursor(0), m_triidx_cursor(0)
23    {}
24
25    virtual void SwitchCommand(char const *&command)
26    {
27        vec4 v4;
28        vec3 v3;
29        float f1, f2, f3, f4, f5, f6, f7, f8;
30
31                const char *&p = command;
32        {
33#define CASE(str) if (CheckCommand(str, p))
34                 CASE("scb") { p = GetArg(p, v4); SetCurColor2(v4); }
35            else CASE("sc")  { p = GetArg(p, v4); SetCurColor(v4); }
36            else CASE("fl")  { Flush(); }
37            else CASE("tx")  { p = GetArg(p, f1); Translate(vec3(f1, 0, 0)); }
38            else CASE("ty")  { p = GetArg(p, f1); Translate(vec3(0, f1, 0)); }
39            else CASE("tz")  { p = GetArg(p, f1); Translate(vec3(0, 0, f1)); }
40            else CASE("t")   { p = GetArg(p, v3); Translate(v3); }
41            else CASE("rx")  { p = GetArg(p, f1); RotateX(f1); }
42            else CASE("ry")  { p = GetArg(p, f1); RotateY(f1); }
43            else CASE("rz")  { p = GetArg(p, f1); RotateZ(f1); }
44            else CASE("tax") { p = GetArg(p, f1, f2, f3); TaperX(f1, f2, f3); }
45            else CASE("tay") { p = GetArg(p, f1, f2, f3); TaperY(f1, f2, f3); }
46            else CASE("taz") { p = GetArg(p, f1, f2, f3); TaperZ(f1, f2, f3); }
47            else CASE("sx")  { p = GetArg(p, f1); Scale(vec3(f1, 1, 1)); }
48            else CASE("sy")  { p = GetArg(p, f1); Scale(vec3(1, f1, 1)); }
49            else CASE("sz")  { p = GetArg(p, f1); Scale(vec3(1, 1, f1)); }
50            else CASE("s")   { p = GetArg(p, v3); Scale(v3); }
51            else CASE("mx")  { MirrorX(); }
52            else CASE("my")  { MirrorY(); }
53            else CASE("mz")  { MirrorZ(); }
54            else CASE("ac")  { p = GetArg(p, f1, f2, f3); p = GetArg(p, f4, f5, f6); AppendCylinder((int)f1, f2, f3, f4, (int)f5, (int)f6); }
55            else CASE("ab")  { p = GetArg(p, v3); AppendBox(v3); }
56            else CASE("ascb") { p = GetArg(p, v3, f1); AppendSmoothChamfBox(v3, f1); }
57            else CASE("afcb") { p = GetArg(p, v3, f1); AppendFlatChamfBox(v3, f1); }
58            else CASE("asph") { p = GetArg(p, f1); p = GetArg(p, v3); AppendSphere((int)f1, v3); }
59            else CASE("as")  { p = GetArg(p, f1, f2, f3, f4, f5); AppendStar((int)f1, f2, f3, (int)f4, (int)f5); }
60            else CASE("aes") { p = GetArg(p, f1, f2, f3, f4); AppendExpandedStar((int)f1, f2, f3, f4); }
61            else CASE("ad")  { p = GetArg(p, f1, f2, f3); AppendDisc((int)f1, f2, (int)f3); }
62            else CASE("at")  { p = GetArg(p, f1, f2); AppendSimpleTriangle(f1, (int)f2); }
63            else CASE("aq")  { p = GetArg(p, f1, f2); AppendSimpleQuad(f1, (int)f2); }
64            else CASE("acg") { p = GetArg(p, f1, f2, f3, f4); p = GetArg(p, f5, f6, f7, f8); AppendCog((int)f1, f2, f3, f4, f5, f6, f7, (int)f8); }
65            else CASE("irb") { MeshConvert(); }
66            else CASE("frb") { /* TODO */ }
67#undef CASE
68        }
69    }
70
71    virtual void Flush()
72    {
73        m_vert_cursor = m_vert.Count();
74        m_quadidx_cursor = m_quadidx.Count();
75        m_triidx_cursor = m_triidx.Count();
76    }
77
78    void MeshConvert()
79    {
80        m_gpu.shader = Shader::Create(
81#if !defined __CELLOS_LV2__ && !defined _XBOX && !defined USE_D3D9
82            "#version 120\n"
83            "attribute vec3 in_Vertex;"
84            "attribute vec3 in_Normal;"
85            "attribute vec4 in_Color;"
86            "uniform mat4 in_ModelView;"
87            "uniform mat4 in_Proj;"
88            "uniform mat3 in_NormalMat;"
89            "varying vec4 pass_Color;"
90            ""
91            "void main(void)"
92            "{"
93                 /* Global shit */
94            "    float alpha_mul = 1.0f;"
95
96                 /* Ambient: global constant */
97            "    float ambient_mul = 0.5f;"
98
99                 /* Diffuse: the level should decide of these values */
100            "    vec3 diffuse_dir = normalize(vec3(-0.7, -0.7, -0.4));"
101            "    vec4 frontColor = vec4(1.0, 1.0, 1.0, 1.0);"
102            "    vec4 backColor = vec4(0.3, 0.2, 0.0, 1.0);"
103
104            "    vec3 world_normal = normalize(in_NormalMat * in_Normal);"
105            "    float d = dot(world_normal, diffuse_dir);"
106            "    vec2 diffuse_mul = max(vec2(-d, d), 0.0);"
107            "    diffuse_mul[0] = min(diffuse_mul[0] + ambient_mul, 1.0);"
108
109                 /* Specular: global settings */
110            "    vec4 spec_col = vec4(0.8, 0.75, 0.4, 1.0);"
111            "    vec3 spec_dir = normalize(vec3(-0.3, -0.3, -1.8));"
112            "    float spec_exp = 60.f;"
113
114            "    float spec_mul = max(-dot(world_normal, spec_dir), 0.0);"
115            "    spec_mul = clamp(pow(spec_mul, spec_exp), 0.0, 1.0);"
116
117
118            "    vec4 tmpColor = frontColor * in_Color;"
119            "    pass_Color = clamp(diffuse_mul[0] * tmpColor"
120            "                        + diffuse_mul[1] * backColor"
121            "                        + spec_mul * spec_col, 0.0, 1.0);"
122            "    pass_Color.a *= alpha_mul;"
123
124            "    vec4 viewPosition = in_ModelView * vec4(in_Vertex, 1.0);"
125            "    gl_Position = in_Proj * viewPosition;"
126            "}",
127
128            "#version 120\n"
129            "varying vec4 pass_Color;"
130            ""
131            "void main(void) {"
132            "    gl_FragColor = pass_Color;"
133            "}"
134#else
135            "void main(float3 in_Vertex : POSITION,"
136            "          float3 in_Normal : NORMAL,"
137            "          float4 in_Color : COLOR,"
138            "          uniform float4x4 in_ModelView,"
139            "          uniform float4x4 in_Proj,"
140            "          uniform float3x3 in_NormalMat,"
141            "          out float4 out_Position : POSITION,"
142            "          out float4 pass_Color : COLOR)"
143            "{"
144            "    float alpha_mul = 1.0f;"
145            "    float ambient_mul = 0.5f;"
146            "    float3 diffuse_dir = normalize(float3(-0.7, -0.7, -0.4));"
147            "    float4 frontColor = float4(1.0, 1.0, 1.0, 1.0);"
148            "    float4 backColor = float4(0.3, 0.2, 0.0, 1.0);"
149            "    float3 world_normal = normalize(mul(in_NormalMat, in_Normal));"
150            "    float d = dot(world_normal, diffuse_dir);"
151            "    float2 diffuse_mul = max(float2(-d, d), 0.0);"
152            "    diffuse_mul[0] = min(diffuse_mul[0] + ambient_mul, 1.0);"
153            "    float4 spec_col = float4(0.8, 0.85, 0.4, 1.0);"
154            "    float3 spec_dir = normalize(float3(-0.7, -0.7, 0.4));"
155            "    float spec_exp = 60.0f;"
156            "    float spec_mul = max(-dot(world_normal, spec_dir), 0.0);"
157            "    spec_mul = saturate(pow(spec_mul, spec_exp));"
158            "    float4 tmpColor = frontColor * in_Color;"
159            "    pass_Color = saturate(diffuse_mul[0] * tmpColor"
160            "                           + diffuse_mul[1] * backColor"
161            "                           + spec_mul * spec_col);"
162            "    pass_Color.a *= alpha_mul;"
163            "    float4 viewPosition = mul(in_ModelView, float4(in_Vertex, 1.0));"
164            "    out_Position = mul(in_Proj, viewPosition);"
165            "}",
166
167            "void main(float4 pass_Color : COLOR,"
168            "          out float4 out_FragColor : COLOR) {"
169            "    out_FragColor = pass_Color;"
170            "}"
171#endif
172        );
173        m_gpu.modelview = m_gpu.shader->GetUniformLocation("in_ModelView");
174        m_gpu.proj = m_gpu.shader->GetUniformLocation("in_Proj");
175        m_gpu.normalmat = m_gpu.shader->GetUniformLocation("in_NormalMat");
176        m_gpu.coord = m_gpu.shader->GetAttribLocation("in_Vertex",
177                                              VertexUsage::Position, 0);
178        m_gpu.norm = m_gpu.shader->GetAttribLocation("in_Normal",
179                                             VertexUsage::Normal, 0);
180        m_gpu.color = m_gpu.shader->GetAttribLocation("in_Color",
181                                              VertexUsage::Color, 0);
182
183        m_gpu.vdecl = new VertexDeclaration(
184            VertexStream<vec3,vec3,u8vec4>(VertexUsage::Position,
185                                           VertexUsage::Normal,
186                                           VertexUsage::Color));
187
188        Array<vec3,vec3,u8vec4> vertexlist;
189        for (int i = 0; i < m_vert.Count(); i++)
190            vertexlist.Push(m_vert[i].m1,
191                            m_vert[i].m2,
192                            (u8vec4)(m_vert[i].m3 * 255.f));
193
194        Array<uint16_t> indexlist;
195        for (int i = 0; i < m_triidx.Count(); i += 3)
196        {
197            indexlist << m_triidx[i + 0];
198            indexlist << m_triidx[i + 1];
199            indexlist << m_triidx[i + 2];
200        }
201        for (int i = 0; i < m_quadidx.Count(); i += 4)
202        {
203            indexlist << m_quadidx[i + 0];
204            indexlist << m_quadidx[i + 1];
205            indexlist << m_quadidx[i + 2];
206
207            indexlist << m_quadidx[i + 0];
208            indexlist << m_quadidx[i + 2];
209            indexlist << m_quadidx[i + 3];
210        }
211
212        m_gpu.vbo = new VertexBuffer(vertexlist.Bytes());
213        void *mesh = m_gpu.vbo->Lock(0, 0);
214        memcpy(mesh, &vertexlist[0], vertexlist.Bytes());
215        m_gpu.vbo->Unlock();
216
217        m_gpu.ibo = new IndexBuffer(indexlist.Bytes());
218        void *indices = m_gpu.ibo->Lock(0, 0);
219        memcpy(indices, &indexlist[0], indexlist.Bytes());
220        m_gpu.ibo->Unlock();
221
222        m_gpu.vertexcount = vertexlist.Count();
223        m_gpu.indexcount = indexlist.Count();
224    }
225
226    void Render(mat4 const &modelview, mat4 const &proj)
227    {
228        mat3 normalmat = transpose(inverse(mat3(modelview)));
229
230        m_gpu.shader->Bind();
231        m_gpu.shader->SetUniform(m_gpu.modelview, modelview);
232        m_gpu.shader->SetUniform(m_gpu.proj, proj);
233        m_gpu.shader->SetUniform(m_gpu.normalmat, normalmat);
234        m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord, m_gpu.norm, m_gpu.color);
235        m_gpu.vdecl->Bind();
236        m_gpu.ibo->Bind();
237        m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles,
238                                         0, 0, m_gpu.vertexcount,
239                                         0, m_gpu.indexcount / 3);
240        m_gpu.ibo->Unbind();
241        m_gpu.vdecl->Unbind();
242    }
243
244    void SetCurColor(vec4 const &color) { m_color = color; }
245    void SetCurColor2(vec4 const &color) { m_color2 = color; }
246
247    void AppendQuadVert(vec3 const &coord)
248    {
249        m_vert.Push(coord, vec3(0.f, 1.f, 0.f), m_color);
250    }
251
252    void AppendDuplicateQuadVert(int i)
253    {
254        m_vert.Push(m_vert[i].m1, vec3(0.f, 1.f, 0.f), m_vert[i].m3);
255    }
256
257    void AppendQuad(int i1, int i2, int i3, int i4, int base)
258    {
259        m_quadidx << base + i1;
260        m_quadidx << base + i2;
261        m_quadidx << base + i3;
262        m_quadidx << base + i4;
263    }
264
265    void AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
266    {
267        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i1);
268        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i2);
269        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i3);
270        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i4);
271    }
272
273    void AppendTriangle(int i1, int i2, int i3, int base)
274    {
275        m_triidx << base + i1;
276        m_triidx << base + i2;
277        m_triidx << base + i3;
278    }
279
280    void AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
281    {
282        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i1);
283        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i2);
284        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i3);
285    }
286
287    void ComputeQuadNormals(int start, int vcount)
288    {
289        for (int i = 0; i < vcount; i += 4)
290        {
291            vec3 v0 = m_vert[m_quadidx[start + i + 2]].m1
292                    - m_vert[m_quadidx[start + i + 0]].m1;
293            vec3 v1 = m_vert[m_quadidx[start + i + 1]].m1
294                    - m_vert[m_quadidx[start + i + 0]].m1;
295            vec3 n = normalize(cross(v1, v0));
296
297            for (int j = 0; j < 4; j++)
298                m_vert[m_quadidx[start + i + j]].m2 = n;
299        }
300    }
301
302    void ComputeTriNormals(int start, int vcount)
303    {
304        for (int i = 0; i < vcount; i += 3)
305        {
306            vec3 v0 = m_vert[m_triidx[start + i + 2]].m1
307                    - m_vert[m_triidx[start + i + 0]].m1;
308            vec3 v1 = m_vert[m_triidx[start + i + 1]].m1
309                    - m_vert[m_triidx[start + i + 0]].m1;
310            vec3 n = normalize(cross(v1, v0));
311
312            for (int j = 0; j < 3; j++)
313                m_vert[m_triidx[start + i + j]].m2 = n;
314        }
315    }
316
317    void SetVertColor(vec4 const &color)
318    {
319        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
320            m_vert[i].m3 = color;
321    }
322
323    void SetCurVertNormal(vec3 const &normal)
324    {
325        m_vert[m_vert.Count() - 1].m2 = normal;
326    }
327
328    void SetCurVertColor(vec4 const &color)
329    {
330        m_vert[m_vert.Count() - 1].m3 = color;
331    }
332
333    void Translate(vec3 const &v)
334    {
335        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
336            m_vert[i].m1 += v;
337    }
338
339    void RotateX(float t) { Rotate(t, vec3(1, 0, 0)); }
340    void RotateY(float t) { Rotate(t, vec3(0, 1, 0)); }
341    void RotateZ(float t) { Rotate(t, vec3(0, 0, 1)); }
342
343    void Rotate(float t, vec3 const &axis)
344    {
345        mat3 m = mat3::rotate(t, axis);
346        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
347        {
348            m_vert[i].m1 = m * m_vert[i].m1;
349            m_vert[i].m2 = m * m_vert[i].m2;
350        }
351    }
352
353    void TaperX(float y, float z, float xoff)
354    {
355        /* FIXME: this code breaks normals! */
356        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
357        {
358            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.x + xoff);
359            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.x + xoff);
360        }
361    }
362
363    void TaperY(float x, float z, float yoff)
364    {
365        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
366        {
367            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.y + yoff);
368            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.y + yoff);
369        }
370    }
371
372    void TaperZ(float x, float y, float zoff)
373    {
374        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
375        {
376            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.z + zoff);
377            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.z + zoff);
378        }
379    }
380
381    void Scale(vec3 const &s)
382    {
383        vec3 const invs = vec3(1) / s;
384
385        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
386        {
387            m_vert[i].m1 *= s;
388            m_vert[i].m2 = normalize(m_vert[i].m2 * invs);
389        }
390
391        /* Flip winding if the scaling involves mirroring */
392        if (s.x * s.y * s.z < 0)
393        {
394            for (int i = m_quadidx_cursor; i < m_quadidx.Count(); i += 2)
395            {
396                uint16_t tmp = m_quadidx[i + 0];
397                m_quadidx[i + 0] = m_quadidx[i + 1];
398                m_quadidx[i + 1] = tmp;
399            }
400
401            for (int i = m_triidx_cursor; i < m_triidx.Count(); i += 3)
402            {
403                uint16_t tmp = m_triidx[i + 0];
404                m_triidx[i + 0] = m_triidx[i + 1];
405                m_triidx[i + 1] = tmp;
406            }
407        }
408    }
409
410    void MirrorX() { Duplicate(); Scale(vec3(-1, 1, 1)); }
411    void MirrorY() { Duplicate(); Scale(vec3(1, -1, 1)); }
412    void MirrorZ() { Duplicate(); Scale(vec3(1, 1, -1)); }
413
414    void Duplicate()
415    {
416        int vlen = m_vert.Count() - m_vert_cursor;
417        int qlen = m_quadidx.Count() - m_quadidx_cursor;
418        int tlen = m_triidx.Count() - m_triidx_cursor;
419
420        for (int i = 0; i < vlen; i++)
421            m_vert << m_vert[m_vert_cursor++];
422
423        for (int i = 0; i < qlen; i++)
424            m_quadidx << m_quadidx[m_quadidx_cursor++] + vlen;
425
426        for (int i = 0; i < tlen; i++)
427            m_triidx << m_triidx[m_triidx_cursor++] + vlen;
428    }
429
430    void AppendCylinder(int nsides, float h, float r1, float r2,
431                        int dualside, int smooth)
432    {
433        int vbase = m_vert.Count();
434
435        mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
436        vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n;
437
438        /* Construct normal */
439        n = p2;
440        n.y = r1 * (r1 - r2) / h;
441        if (!smooth)
442            n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n;
443        n = normalize(n);
444
445        /* FIXME: normals should be flipped in two-sided mode, but that
446         * means duplicating the vertices again... */
447        for (int i = 0; i < nsides; i++)
448        {
449            AppendQuadVert(p1); SetCurVertNormal(n);
450            AppendQuadVert(p2); SetCurVertNormal(n);
451            SetCurVertColor(m_color2);
452
453            if (smooth)
454            {
455                int j = (i + 1) % nsides;
456                AppendQuad(j * 2, j * 2 + 1, i * 2 + 1, i * 2, vbase);
457                if (dualside)
458                    AppendQuad(i * 2, i * 2 + 1, j * 2 + 1, j * 2, vbase);
459            }
460
461            p1 = rotmat * p1;
462            p2 = rotmat * p2;
463
464            if (!smooth)
465            {
466                AppendQuadVert(p1); SetCurVertNormal(n);
467                AppendQuadVert(p2); SetCurVertNormal(n);
468                SetCurVertColor(m_color2);
469
470                AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase);
471                if (dualside)
472                    AppendQuad(i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, vbase);
473            }
474
475            n = rotmat * n;
476        }
477    }
478
479    void AppendSphere(int ndivisions, vec3 const &size)
480    {
481        ndivisions *= 2;
482
483        int ibase = m_quadidx.Count();
484        int vbase = m_vert.Count();
485
486        vec3 d = size * 0.5f;
487        float const pi = std::acos(-1.0f);
488
489        Array<vec2> table;
490        for (int i = 0; i <= ndivisions; i++)
491            table.Push(vec2(std::sin(pi * 2 / ndivisions * i) + 1e-5f,
492                            std::cos(pi * 2 / ndivisions * i) + 1e-5f));
493
494        for (int j = 0; j <= ndivisions / 2; j++)
495            for (int i = 0; i < ndivisions; i++)
496            {
497                int j2 = j + 1;
498                int i2 = (i + 1) % ndivisions;
499
500                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j].xxy);
501                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j].xxy);
502                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j2].xxy);
503                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j2].xxy);
504            }
505
506        for (int i = vbase; i < m_vert.Count(); i += 4)
507            AppendQuad(0, 1, 2, 3, i);
508
509        ComputeQuadNormals(ibase, m_quadidx.Count() - ibase);
510    }
511
512    void AppendBox(vec3 const &size, float chamf = 0.f)
513    {
514        AppendBox(size, chamf, false);
515    }
516
517    void AppendSmoothChamfBox(vec3 const &size, float chamf)
518    {
519        AppendBox(size, chamf, true);
520    }
521
522    void AppendFlatChamfBox(vec3 const &size, float chamf)
523    {
524        AppendBox(size, chamf, false);
525    }
526
527    void AppendBox(vec3 const &size, float chamf, bool smooth)
528    {
529        int vbase = m_vert.Count();
530        int qibase = m_quadidx.Count();
531        int tibase = m_triidx.Count();
532
533        vec3 d = size * 0.5f;
534
535        AppendQuadVert(vec3(-d.x, -d.y, -d.z - chamf));
536        AppendQuadVert(vec3(-d.x, +d.y, -d.z - chamf));
537        AppendQuadVert(vec3(+d.x, +d.y, -d.z - chamf));
538        AppendQuadVert(vec3(+d.x, -d.y, -d.z - chamf));
539
540        AppendQuadVert(vec3(-d.x - chamf, -d.y, +d.z));
541        AppendQuadVert(vec3(-d.x - chamf, +d.y, +d.z));
542        AppendQuadVert(vec3(-d.x - chamf, +d.y, -d.z));
543        AppendQuadVert(vec3(-d.x - chamf, -d.y, -d.z));
544
545        AppendQuadVert(vec3(+d.x, -d.y, +d.z + chamf));
546        AppendQuadVert(vec3(+d.x, +d.y, +d.z + chamf));
547        AppendQuadVert(vec3(-d.x, +d.y, +d.z + chamf));
548        AppendQuadVert(vec3(-d.x, -d.y, +d.z + chamf));
549
550        AppendQuadVert(vec3(+d.x + chamf, -d.y, -d.z));
551        AppendQuadVert(vec3(+d.x + chamf, +d.y, -d.z));
552        AppendQuadVert(vec3(+d.x + chamf, +d.y, +d.z));
553        AppendQuadVert(vec3(+d.x + chamf, -d.y, +d.z));
554
555        AppendQuadVert(vec3(-d.x, -d.y - chamf, +d.z));
556        AppendQuadVert(vec3(-d.x, -d.y - chamf, -d.z));
557        AppendQuadVert(vec3(+d.x, -d.y - chamf, -d.z));
558        AppendQuadVert(vec3(+d.x, -d.y - chamf, +d.z));
559
560        AppendQuadVert(vec3(-d.x, +d.y + chamf, -d.z));
561        AppendQuadVert(vec3(-d.x, +d.y + chamf, +d.z));
562        AppendQuadVert(vec3(+d.x, +d.y + chamf, +d.z));
563        AppendQuadVert(vec3(+d.x, +d.y + chamf, -d.z));
564
565        /* The 6 quads on each side of the box */
566        for (int i = 0; i < 24; i += 4)
567            AppendQuad(i, i + 1, i + 2, i + 3, vbase);
568
569        ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
570        qibase = m_quadidx.Count();
571
572        /* The 8 quads at each edge of the box */
573        if (chamf)
574        {
575            static int const quadlist[48] =
576            {
577                0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
578                2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
579                1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
580            };
581
582            for (int i = 0; i < 48; i += 4)
583            {
584                if (smooth)
585                    AppendQuad(quadlist[i], quadlist[i + 1],
586                               quadlist[i + 2], quadlist[i + 3], vbase);
587                else
588                    AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
589                                     quadlist[i + 2], quadlist[i + 3], vbase);
590            }
591        }
592
593        /* The 8 triangles at each corner of the box */
594        if (chamf)
595        {
596            static int const trilist[24] =
597            {
598                3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
599                2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
600            };
601
602            for (int i = 0; i < 24; i += 3)
603            {
604                if (smooth)
605                    AppendTriangle(trilist[i], trilist[i + 1],
606                                   trilist[i + 2], vbase);
607                else
608                    AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
609                                                 trilist[i + 2], vbase);
610            }
611        }
612
613        if (!smooth)
614        {
615            ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
616            ComputeTriNormals(tibase, m_triidx.Count() - tibase);
617        }
618    }
619
620    void AppendStar(int nbranches, float r1, float r2,
621                    int fade = 0, int fade2 = 0)
622    {
623        int vbase = m_vert.Count();
624
625        AppendQuadVert(vec3(0.f, 0.f, 0.f));
626
627        mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
628        vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
629
630        p2 = rotmat * p2;
631        rotmat = rotmat * rotmat;
632
633        for (int i = 0; i < nbranches; i++)
634        {
635            AppendQuadVert(p1);
636            if (fade2)
637                SetCurVertColor(m_color2);
638
639            AppendQuadVert(p2);
640            if (fade)
641                SetCurVertColor(m_color2);
642
643            AppendQuad(0, (2 * i + 3) % (2 * nbranches),
644                       2 * i + 2, 2 * i + 1, vbase);
645
646            p1 = rotmat * p1;
647            p2 = rotmat * p2;
648        }
649    }
650
651    void AppendExpandedStar(int nbranches, float r1, float r2, float extrar)
652    {
653        int vbase = m_vert.Count();
654
655        AppendQuadVert(vec3(0.f, 0.f, 0.f));
656
657        mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
658        vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f),
659             p3(r1 + extrar, 0.f, 0.f), p4(r2 + extrar, 0.f, 0.f);;
660
661        p2 = rotmat * p2;
662        p4 = rotmat * p4;
663        rotmat = rotmat * rotmat;
664
665        for (int i = 0; i < nbranches; i++)
666        {
667            AppendQuadVert(p1);
668            AppendQuadVert(p2);
669            AppendQuadVert(p3); SetCurVertColor(m_color2);
670            AppendQuadVert(p4); SetCurVertColor(m_color2);
671
672            int j = (i + 1) % nbranches;
673            AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase);
674            AppendQuad(4 * i + 1, 4 * i + 3, 4 * i + 4, 4 * i + 2, vbase);
675            AppendQuad(4 * j + 1, 4 * i + 2, 4 * i + 4, 4 * j + 3, vbase);
676
677            p1 = rotmat * p1;
678            p2 = rotmat * p2;
679            p3 = rotmat * p3;
680            p4 = rotmat * p4;
681        }
682    }
683
684    void AppendDisc(int nsides, float r, int fade = 0)
685    {
686        int vbase = m_vert.Count();
687
688        AppendQuadVert(vec3(0.f, 0.f, 0.f));
689
690        mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
691        vec3 p1(r, 0.f, 0.f);
692
693        for (int i = 0; i < nsides; i++)
694        {
695            AppendQuadVert(p1);
696            if (fade)
697                SetCurVertColor(m_color2);
698            AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase);
699            p1 = rotmat * p1;
700        }
701    }
702
703    void AppendSimpleTriangle(float size, int fade = 0)
704    {
705        mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f);
706        vec3 p(0.f, 0.f, size);
707
708        AppendQuadVert(p);
709        p = m * p;
710        AppendQuadVert(p);
711        if (fade)
712            SetCurVertColor(m_color2);
713        p = m * p;
714        AppendQuadVert(p);
715        if (fade)
716            SetCurVertColor(m_color2);
717
718        AppendTriangle(0, 1, 2, m_vert.Count() - 3);
719    }
720
721    void AppendSimpleQuad(float size, int fade = 0)
722    {
723        AppendSimpleQuad(vec2(size * .5f), vec2(size * -.5f), 0.f, fade);
724    }
725
726    void AppendSimpleQuad(vec2 p1, vec2 p2, float z = 0.f, int fade = 0)
727    {
728        AppendQuadVert(vec3(p2.x, z, -p1.y));
729        AppendQuadVert(vec3(p2.x, z, -p2.y));
730        AppendQuadVert(vec3(p1.x, z, -p2.y));
731        if (fade)
732            SetCurVertColor(m_color2);
733        AppendQuadVert(vec3(p1.x, z, -p1.y));
734        if (fade)
735            SetCurVertColor(m_color2);
736
737        AppendQuad(0, 3, 2, 1, m_vert.Count() - 4);
738        ComputeQuadNormals(m_quadidx.Count() - 4, 4);
739    }
740
741    void AppendCog(int nbsides, float h, float r1, float r2,
742                   float r12, float r22, float sidemul, int offset)
743    {
744        int qibase = m_quadidx.Count();
745        int vbase = m_vert.Count();
746
747        AppendQuadVert(vec3(0.f, h * .5f, 0.f));
748        AppendQuadVert(vec3(0.f, h * -.5f, 0.f));
749        SetCurVertColor(m_color2);
750
751        mat3 rotmat = mat3::rotate(180.0f / nbsides, 0.f, 1.f, 0.f);
752        mat3 smat1 = mat3::rotate(sidemul * 180.0f / nbsides, 0.f, 1.f, 0.f);
753        mat3 smat2 = mat3::rotate(sidemul * -360.0f / nbsides, 0.f, 1.f, 0.f);
754
755        vec3 p[8];
756
757        p[0] = vec3(r1, h * .5f, 0.f);
758        p[1] = rotmat * p[0];
759        p[2] = smat1 * (rotmat * vec3(r1 + r12, h * .5f, 0.f));
760        p[3] = smat2 * (rotmat * p[2]);
761
762        p[4] = vec3(r2, h * -.5f, 0.f);
763        p[5] = rotmat * p[4];
764        p[6] = smat1 * (rotmat * vec3(r2 + r22, h * -.5f, 0.f));
765        p[7] = smat2 * (rotmat * p[6]);
766
767        if (offset & 1)
768            for (int n = 0; n < 8; n++)
769                p[n] = rotmat * p[n];
770
771        rotmat = rotmat * rotmat;
772
773        for (int i = 0; i < nbsides; i++)
774        {
775            /* Each vertex will share three faces, so three different
776             * normals, therefore we add each vertex three times. */
777            for (int n = 0; n < 24; n++)
778            {
779                AppendQuadVert(p[n / 3]);
780                if (n / 3 >= 4)
781                    SetCurVertColor(m_color2);
782            }
783
784            int j = 24 * i, k = 24 * ((i + 1) % nbsides);
785
786            /* The top and bottom faces */
787            AppendQuad(0, j + 2, j + 5, k + 2, vbase);
788            AppendQuad(1, k + 14, j + 17, j + 14, vbase);
789            AppendQuad(j + 5, j + 8, j + 11, k + 2, vbase);
790            AppendQuad(k + 14, j + 23, j + 20, j + 17, vbase);
791
792            /* The side quads */
793            AppendQuad(j + 6, j + 3, j + 15, j + 18, vbase);
794            AppendQuad(j + 9, j + 7, j + 19, j + 21, vbase);
795            AppendQuad(j + 12, j + 10, j + 22, j + 24, vbase);
796            AppendQuad(k + 4, j + 13, j + 25, k + 16, vbase);
797
798            for (int n = 0; n < 8; n++)
799                p[n] = rotmat * p[n];
800        }
801
802        ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
803    }
804
805private:
806    vec4 m_color, m_color2;
807    Array<uint16_t> m_triidx, m_quadidx;
808    Array<vec3, vec3, vec4> m_vert;
809    int m_vert_cursor, m_quadidx_cursor, m_triidx_cursor;
810
811    /* FIXME: put this in a separate class so that we can copy meshes. */
812    struct
813    {
814        Shader *shader;
815        ShaderAttrib coord, norm, color;
816        ShaderUniform modelview, proj, normalmat;
817        VertexDeclaration *vdecl;
818        VertexBuffer *vbo;
819        IndexBuffer *ibo;
820        int vertexcount, indexcount;
821    }
822    m_gpu;
823};
824
825#endif /* __MESH_H__ */
826
Note: See TracBrowser for help on using the repository browser.