source: trunk/orbital/mesh.h @ 1286

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

orbital: first try at a particle system.

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