source: trunk/orbital/mesh.h @ 1332

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

orbital: do not let the world objects know anything about the projection
or view matrix unless strictly necessary.

  • Property svn:keywords set to Id
File size: 28.4 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 &model)
227    {
228        mat4 modelview = Scene::GetDefault()->GetViewMatrix() * model;
229        mat3 normalmat = transpose(inverse(mat3(modelview)));
230
231        m_gpu.shader->Bind();
232        m_gpu.shader->SetUniform(m_gpu.modelview, modelview);
233        m_gpu.shader->SetUniform(m_gpu.proj, Scene::GetDefault()->GetProjMatrix());
234        m_gpu.shader->SetUniform(m_gpu.normalmat, normalmat);
235        m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord, m_gpu.norm, m_gpu.color);
236        m_gpu.vdecl->Bind();
237        m_gpu.ibo->Bind();
238        m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles,
239                                         0, 0, m_gpu.vertexcount,
240                                         0, m_gpu.indexcount / 3);
241        m_gpu.ibo->Unbind();
242        m_gpu.vdecl->Unbind();
243    }
244
245    void SetCurColor(vec4 const &color) { m_color = color; }
246    void SetCurColor2(vec4 const &color) { m_color2 = color; }
247
248    void AppendQuadVert(vec3 const &coord)
249    {
250        m_vert.Push(coord, vec3(0.f, 1.f, 0.f), m_color);
251    }
252
253    void AppendDuplicateQuadVert(int i)
254    {
255        m_vert.Push(m_vert[i].m1, vec3(0.f, 1.f, 0.f), m_vert[i].m3);
256    }
257
258    void AppendQuad(int i1, int i2, int i3, int i4, int base)
259    {
260        m_quadidx << base + i1;
261        m_quadidx << base + i2;
262        m_quadidx << base + i3;
263        m_quadidx << base + i4;
264    }
265
266    void AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
267    {
268        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i1);
269        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i2);
270        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i3);
271        m_quadidx << m_vert.Count(); AppendDuplicateQuadVert(base + i4);
272    }
273
274    void AppendTriangle(int i1, int i2, int i3, int base)
275    {
276        m_triidx << base + i1;
277        m_triidx << base + i2;
278        m_triidx << base + i3;
279    }
280
281    void AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
282    {
283        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i1);
284        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i2);
285        m_triidx << m_vert.Count(); AppendDuplicateQuadVert(base + i3);
286    }
287
288    void ComputeQuadNormals(int start, int vcount)
289    {
290        for (int i = 0; i < vcount; i += 4)
291        {
292            vec3 v0 = m_vert[m_quadidx[start + i + 2]].m1
293                    - m_vert[m_quadidx[start + i + 0]].m1;
294            vec3 v1 = m_vert[m_quadidx[start + i + 1]].m1
295                    - m_vert[m_quadidx[start + i + 0]].m1;
296            vec3 n = normalize(cross(v1, v0));
297
298            for (int j = 0; j < 4; j++)
299                m_vert[m_quadidx[start + i + j]].m2 = n;
300        }
301    }
302
303    void ComputeTriNormals(int start, int vcount)
304    {
305        for (int i = 0; i < vcount; i += 3)
306        {
307            vec3 v0 = m_vert[m_triidx[start + i + 2]].m1
308                    - m_vert[m_triidx[start + i + 0]].m1;
309            vec3 v1 = m_vert[m_triidx[start + i + 1]].m1
310                    - m_vert[m_triidx[start + i + 0]].m1;
311            vec3 n = normalize(cross(v1, v0));
312
313            for (int j = 0; j < 3; j++)
314                m_vert[m_triidx[start + i + j]].m2 = n;
315        }
316    }
317
318    void SetVertColor(vec4 const &color)
319    {
320        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
321            m_vert[i].m3 = color;
322    }
323
324    void SetCurVertNormal(vec3 const &normal)
325    {
326        m_vert[m_vert.Count() - 1].m2 = normal;
327    }
328
329    void SetCurVertColor(vec4 const &color)
330    {
331        m_vert[m_vert.Count() - 1].m3 = color;
332    }
333
334    void Translate(vec3 const &v)
335    {
336        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
337            m_vert[i].m1 += v;
338    }
339
340    void RotateX(float t) { Rotate(t, vec3(1, 0, 0)); }
341    void RotateY(float t) { Rotate(t, vec3(0, 1, 0)); }
342    void RotateZ(float t) { Rotate(t, vec3(0, 0, 1)); }
343
344    void Rotate(float t, vec3 const &axis)
345    {
346        mat3 m = mat3::rotate(t, axis);
347        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
348        {
349            m_vert[i].m1 = m * m_vert[i].m1;
350            m_vert[i].m2 = m * m_vert[i].m2;
351        }
352    }
353
354    void TaperX(float y, float z, float xoff)
355    {
356        /* FIXME: this code breaks normals! */
357        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
358        {
359            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.x + xoff);
360            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.x + xoff);
361        }
362    }
363
364    void TaperY(float x, float z, float yoff)
365    {
366        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
367        {
368            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.y + yoff);
369            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.y + yoff);
370        }
371    }
372
373    void TaperZ(float x, float y, float zoff)
374    {
375        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
376        {
377            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.z + zoff);
378            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.z + zoff);
379        }
380    }
381
382    void Scale(vec3 const &s)
383    {
384        vec3 const invs = vec3(1) / s;
385
386        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
387        {
388            m_vert[i].m1 *= s;
389            m_vert[i].m2 = normalize(m_vert[i].m2 * invs);
390        }
391
392        /* Flip winding if the scaling involves mirroring */
393        if (s.x * s.y * s.z < 0)
394        {
395            for (int i = m_quadidx_cursor; i < m_quadidx.Count(); i += 2)
396            {
397                uint16_t tmp = m_quadidx[i + 0];
398                m_quadidx[i + 0] = m_quadidx[i + 1];
399                m_quadidx[i + 1] = tmp;
400            }
401
402            for (int i = m_triidx_cursor; i < m_triidx.Count(); i += 3)
403            {
404                uint16_t tmp = m_triidx[i + 0];
405                m_triidx[i + 0] = m_triidx[i + 1];
406                m_triidx[i + 1] = tmp;
407            }
408        }
409    }
410
411    void MirrorX() { Duplicate(); Scale(vec3(-1, 1, 1)); }
412    void MirrorY() { Duplicate(); Scale(vec3(1, -1, 1)); }
413    void MirrorZ() { Duplicate(); Scale(vec3(1, 1, -1)); }
414
415    void Duplicate()
416    {
417        int vlen = m_vert.Count() - m_vert_cursor;
418        int qlen = m_quadidx.Count() - m_quadidx_cursor;
419        int tlen = m_triidx.Count() - m_triidx_cursor;
420
421        for (int i = 0; i < vlen; i++)
422            m_vert << m_vert[m_vert_cursor++];
423
424        for (int i = 0; i < qlen; i++)
425            m_quadidx << m_quadidx[m_quadidx_cursor++] + vlen;
426
427        for (int i = 0; i < tlen; i++)
428            m_triidx << m_triidx[m_triidx_cursor++] + vlen;
429    }
430
431    void AppendCylinder(int nsides, float h, float r1, float r2,
432                        int dualside, int smooth)
433    {
434        int vbase = m_vert.Count();
435
436        mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
437        vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n;
438
439        /* Construct normal */
440        n = p2;
441        n.y = r1 * (r1 - r2) / h;
442        if (!smooth)
443            n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n;
444        n = normalize(n);
445
446        /* FIXME: normals should be flipped in two-sided mode, but that
447         * means duplicating the vertices again... */
448        for (int i = 0; i < nsides; i++)
449        {
450            AppendQuadVert(p1); SetCurVertNormal(n);
451            AppendQuadVert(p2); SetCurVertNormal(n);
452            SetCurVertColor(m_color2);
453
454            if (smooth)
455            {
456                int j = (i + 1) % nsides;
457                AppendQuad(j * 2, j * 2 + 1, i * 2 + 1, i * 2, vbase);
458                if (dualside)
459                    AppendQuad(i * 2, i * 2 + 1, j * 2 + 1, j * 2, vbase);
460            }
461
462            p1 = rotmat * p1;
463            p2 = rotmat * p2;
464
465            if (!smooth)
466            {
467                AppendQuadVert(p1); SetCurVertNormal(n);
468                AppendQuadVert(p2); SetCurVertNormal(n);
469                SetCurVertColor(m_color2);
470
471                AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase);
472                if (dualside)
473                    AppendQuad(i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, vbase);
474            }
475
476            n = rotmat * n;
477        }
478    }
479
480    void AppendSphere(int ndivisions, vec3 const &size)
481    {
482        ndivisions *= 2;
483
484        int ibase = m_quadidx.Count();
485        int vbase = m_vert.Count();
486
487        vec3 d = size * 0.5f;
488        float const pi = std::acos(-1.0f);
489
490        Array<vec2> table;
491        for (int i = 0; i <= ndivisions; i++)
492            table.Push(vec2(std::sin(pi * 2 / ndivisions * i) + 1e-5f,
493                            std::cos(pi * 2 / ndivisions * i) + 1e-5f));
494
495        for (int j = 0; j <= ndivisions / 2; j++)
496            for (int i = 0; i < ndivisions; i++)
497            {
498                int j2 = j + 1;
499                int i2 = (i + 1) % ndivisions;
500
501                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j].xxy);
502                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j].xxy);
503                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j2].xxy);
504                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j2].xxy);
505            }
506
507        for (int i = vbase; i < m_vert.Count(); i += 4)
508            AppendQuad(0, 1, 2, 3, i);
509
510        ComputeQuadNormals(ibase, m_quadidx.Count() - ibase);
511    }
512
513    void AppendBox(vec3 const &size, float chamf = 0.f)
514    {
515        AppendBox(size, chamf, false);
516    }
517
518    void AppendSmoothChamfBox(vec3 const &size, float chamf)
519    {
520        AppendBox(size, chamf, true);
521    }
522
523    void AppendFlatChamfBox(vec3 const &size, float chamf)
524    {
525        AppendBox(size, chamf, false);
526    }
527
528    void AppendBox(vec3 const &size, float chamf, bool smooth)
529    {
530        int vbase = m_vert.Count();
531        int qibase = m_quadidx.Count();
532        int tibase = m_triidx.Count();
533
534        vec3 d = size * 0.5f;
535
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        AppendQuadVert(vec3(+d.x, -d.y, -d.z - chamf));
540
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        AppendQuadVert(vec3(-d.x - chamf, -d.y, -d.z));
545
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        AppendQuadVert(vec3(-d.x, -d.y, +d.z + chamf));
550
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        AppendQuadVert(vec3(+d.x + chamf, -d.y, +d.z));
555
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        AppendQuadVert(vec3(+d.x, -d.y - chamf, +d.z));
560
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        AppendQuadVert(vec3(+d.x, +d.y + chamf, -d.z));
565
566        /* The 6 quads on each side of the box */
567        for (int i = 0; i < 24; i += 4)
568            AppendQuad(i, i + 1, i + 2, i + 3, vbase);
569
570        ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
571        qibase = m_quadidx.Count();
572
573        /* The 8 quads at each edge of the box */
574        if (chamf)
575        {
576            static int const quadlist[48] =
577            {
578                0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
579                2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
580                1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
581            };
582
583            for (int i = 0; i < 48; i += 4)
584            {
585                if (smooth)
586                    AppendQuad(quadlist[i], quadlist[i + 1],
587                               quadlist[i + 2], quadlist[i + 3], vbase);
588                else
589                    AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
590                                     quadlist[i + 2], quadlist[i + 3], vbase);
591            }
592        }
593
594        /* The 8 triangles at each corner of the box */
595        if (chamf)
596        {
597            static int const trilist[24] =
598            {
599                3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
600                2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
601            };
602
603            for (int i = 0; i < 24; i += 3)
604            {
605                if (smooth)
606                    AppendTriangle(trilist[i], trilist[i + 1],
607                                   trilist[i + 2], vbase);
608                else
609                    AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
610                                                 trilist[i + 2], vbase);
611            }
612        }
613
614        if (!smooth)
615        {
616            ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
617            ComputeTriNormals(tibase, m_triidx.Count() - tibase);
618        }
619    }
620
621    void AppendStar(int nbranches, float r1, float r2,
622                    int fade = 0, int fade2 = 0)
623    {
624        int vbase = m_vert.Count();
625
626        AppendQuadVert(vec3(0.f, 0.f, 0.f));
627
628        mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
629        vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
630
631        p2 = rotmat * p2;
632        rotmat = rotmat * rotmat;
633
634        for (int i = 0; i < nbranches; i++)
635        {
636            AppendQuadVert(p1);
637            if (fade2)
638                SetCurVertColor(m_color2);
639
640            AppendQuadVert(p2);
641            if (fade)
642                SetCurVertColor(m_color2);
643
644            AppendQuad(0, (2 * i + 3) % (2 * nbranches),
645                       2 * i + 2, 2 * i + 1, vbase);
646
647            p1 = rotmat * p1;
648            p2 = rotmat * p2;
649        }
650    }
651
652    void AppendExpandedStar(int nbranches, float r1, float r2, float extrar)
653    {
654        int vbase = m_vert.Count();
655
656        AppendQuadVert(vec3(0.f, 0.f, 0.f));
657
658        mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f);
659        vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f),
660             p3(r1 + extrar, 0.f, 0.f), p4(r2 + extrar, 0.f, 0.f);;
661
662        p2 = rotmat * p2;
663        p4 = rotmat * p4;
664        rotmat = rotmat * rotmat;
665
666        for (int i = 0; i < nbranches; i++)
667        {
668            AppendQuadVert(p1);
669            AppendQuadVert(p2);
670            AppendQuadVert(p3); SetCurVertColor(m_color2);
671            AppendQuadVert(p4); SetCurVertColor(m_color2);
672
673            int j = (i + 1) % nbranches;
674            AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase);
675            AppendQuad(4 * i + 1, 4 * i + 3, 4 * i + 4, 4 * i + 2, vbase);
676            AppendQuad(4 * j + 1, 4 * i + 2, 4 * i + 4, 4 * j + 3, vbase);
677
678            p1 = rotmat * p1;
679            p2 = rotmat * p2;
680            p3 = rotmat * p3;
681            p4 = rotmat * p4;
682        }
683    }
684
685    void AppendDisc(int nsides, float r, int fade = 0)
686    {
687        int vbase = m_vert.Count();
688
689        AppendQuadVert(vec3(0.f, 0.f, 0.f));
690
691        mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f);
692        vec3 p1(r, 0.f, 0.f);
693
694        for (int i = 0; i < nsides; i++)
695        {
696            AppendQuadVert(p1);
697            if (fade)
698                SetCurVertColor(m_color2);
699            AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase);
700            p1 = rotmat * p1;
701        }
702    }
703
704    void AppendSimpleTriangle(float size, int fade = 0)
705    {
706        mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f);
707        vec3 p(0.f, 0.f, size);
708
709        AppendQuadVert(p);
710        p = m * p;
711        AppendQuadVert(p);
712        if (fade)
713            SetCurVertColor(m_color2);
714        p = m * p;
715        AppendQuadVert(p);
716        if (fade)
717            SetCurVertColor(m_color2);
718
719        AppendTriangle(0, 1, 2, m_vert.Count() - 3);
720    }
721
722    void AppendSimpleQuad(float size, int fade = 0)
723    {
724        AppendSimpleQuad(vec2(size * .5f), vec2(size * -.5f), 0.f, fade);
725    }
726
727    void AppendSimpleQuad(vec2 p1, vec2 p2, float z = 0.f, int fade = 0)
728    {
729        AppendQuadVert(vec3(p2.x, z, -p1.y));
730        AppendQuadVert(vec3(p2.x, z, -p2.y));
731        AppendQuadVert(vec3(p1.x, z, -p2.y));
732        if (fade)
733            SetCurVertColor(m_color2);
734        AppendQuadVert(vec3(p1.x, z, -p1.y));
735        if (fade)
736            SetCurVertColor(m_color2);
737
738        AppendQuad(0, 3, 2, 1, m_vert.Count() - 4);
739        ComputeQuadNormals(m_quadidx.Count() - 4, 4);
740    }
741
742    void AppendCog(int nbsides, float h, float r1, float r2,
743                   float r12, float r22, float sidemul, int offset)
744    {
745        int qibase = m_quadidx.Count();
746        int vbase = m_vert.Count();
747
748        AppendQuadVert(vec3(0.f, h * .5f, 0.f));
749        AppendQuadVert(vec3(0.f, h * -.5f, 0.f));
750        SetCurVertColor(m_color2);
751
752        mat3 rotmat = mat3::rotate(180.0f / nbsides, 0.f, 1.f, 0.f);
753        mat3 smat1 = mat3::rotate(sidemul * 180.0f / nbsides, 0.f, 1.f, 0.f);
754        mat3 smat2 = mat3::rotate(sidemul * -360.0f / nbsides, 0.f, 1.f, 0.f);
755
756        vec3 p[8];
757
758        p[0] = vec3(r1, h * .5f, 0.f);
759        p[1] = rotmat * p[0];
760        p[2] = smat1 * (rotmat * vec3(r1 + r12, h * .5f, 0.f));
761        p[3] = smat2 * (rotmat * p[2]);
762
763        p[4] = vec3(r2, h * -.5f, 0.f);
764        p[5] = rotmat * p[4];
765        p[6] = smat1 * (rotmat * vec3(r2 + r22, h * -.5f, 0.f));
766        p[7] = smat2 * (rotmat * p[6]);
767
768        if (offset & 1)
769            for (int n = 0; n < 8; n++)
770                p[n] = rotmat * p[n];
771
772        rotmat = rotmat * rotmat;
773
774        for (int i = 0; i < nbsides; i++)
775        {
776            /* Each vertex will share three faces, so three different
777             * normals, therefore we add each vertex three times. */
778            for (int n = 0; n < 24; n++)
779            {
780                AppendQuadVert(p[n / 3]);
781                if (n / 3 >= 4)
782                    SetCurVertColor(m_color2);
783            }
784
785            int j = 24 * i, k = 24 * ((i + 1) % nbsides);
786
787            /* The top and bottom faces */
788            AppendQuad(0, j + 2, j + 5, k + 2, vbase);
789            AppendQuad(1, k + 14, j + 17, j + 14, vbase);
790            AppendQuad(j + 5, j + 8, j + 11, k + 2, vbase);
791            AppendQuad(k + 14, j + 23, j + 20, j + 17, vbase);
792
793            /* The side quads */
794            AppendQuad(j + 6, j + 3, j + 15, j + 18, vbase);
795            AppendQuad(j + 9, j + 7, j + 19, j + 21, vbase);
796            AppendQuad(j + 12, j + 10, j + 22, j + 24, vbase);
797            AppendQuad(k + 4, j + 13, j + 25, k + 16, vbase);
798
799            for (int n = 0; n < 8; n++)
800                p[n] = rotmat * p[n];
801        }
802
803        ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
804    }
805
806private:
807    vec4 m_color, m_color2;
808    Array<uint16_t> m_triidx, m_quadidx;
809    Array<vec3, vec3, vec4> m_vert;
810    int m_vert_cursor, m_quadidx_cursor, m_triidx_cursor;
811
812    /* FIXME: put this in a separate class so that we can copy meshes. */
813    struct
814    {
815        Shader *shader;
816        ShaderAttrib coord, norm, color;
817        ShaderUniform modelview, proj, normalmat;
818        VertexDeclaration *vdecl;
819        VertexBuffer *vbo;
820        IndexBuffer *ibo;
821        int vertexcount, indexcount;
822    }
823    m_gpu;
824};
825
826#endif /* __MESH_H__ */
827
Note: See TracBrowser for help on using the repository browser.