source: trunk/orbital/mesh.h @ 1268

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

orbital: implement chamfer boxes and stars in the mesh builder.

  • Property svn:keywords set to Id
File size: 19.0 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 Flush()
24    {
25        m_vert_cursor = m_vert.Count();
26        m_quadidx_cursor = m_quadidx.Count();
27        m_triidx_cursor = m_triidx.Count();
28    }
29
30    void MeshConvert()
31    {
32        m_gpu.shader = Shader::Create(
33#if !defined __CELLOS_LV2__ && !defined _XBOX && !defined USE_D3D9
34            "#version 120\n"
35            "attribute vec3 in_Vertex;"
36            "attribute vec3 in_Normal;"
37            "attribute vec4 in_Color;"
38            "uniform mat4 in_ModelView;"
39            "uniform mat4 in_Proj;"
40            "uniform mat3 in_NormalMat;"
41            "varying vec4 pass_Color;"
42            ""
43            "void main(void)"
44            "{"
45                 /* Diffuse information -- the level decides this */
46
47                 /* Global shit */
48            "    float alpha_mul = 1.0f;"
49
50                 /* Ambient: global constant */
51            "    float ambient_mul = 0.5f;"
52
53                 /* Diffuse: the level should decide of these values */
54            "    vec3 diffuse_dir = normalize(vec3(-0.7, -0.7, -0.4));"
55            "    vec4 frontColor = vec4(1.0, 1.0, 1.0, 1.0);"
56            "    vec4 backColor = vec4(0.3, 0.2, 0.0, 1.0);"
57
58            "    vec3 world_normal = normalize(in_NormalMat * in_Normal);"
59            "    float d = dot(world_normal, diffuse_dir);"
60            "    vec2 diffuse_mul = max(vec2(-d, d), 0.0);"
61            "    diffuse_mul[0] = min(diffuse_mul[0] + ambient_mul, 1.0);"
62
63                 /* Specular: global settings */
64            "    vec4 spec_col = vec4(0.8, 0.85, 0.4, 1.0);"
65            "    vec3 spec_dir = normalize(vec3(-0.7, -0.7, 0.4));"
66            "    float spec_exp = 60.0f;"
67
68            "    float spec_mul = max(-dot(world_normal, spec_dir), 0.0);"
69            "    spec_mul = clamp(pow(spec_mul, spec_exp), 0.0, 1.0);"
70
71
72            "    vec4 TmpColor = frontColor * in_Color;"
73                 /* NOTE: use saturate() in HLSL */
74            "    pass_Color = clamp(diffuse_mul[0] * TmpColor"
75            "                        + diffuse_mul[1] * backColor"
76            "                        + spec_mul * spec_col, 0.0, 1.0);"
77            "    pass_Color.a *= alpha_mul;"
78
79            "    vec4 viewPosition = in_ModelView * vec4(in_Vertex, 1.0);"
80            "    gl_Position = in_Proj * viewPosition;"
81            "}",
82
83            "#version 120\n"
84            "varying vec4 pass_Color;"
85            ""
86            "void main(void) {"
87            "    gl_FragColor = pass_Color;"
88            "}"
89#else
90            "void main(float3 in_Vertex : POSITION,"
91            "          float3 in_Normal : NORMAL,"
92            "          float4 in_Color : COLOR,"
93            "          uniform float4x4 in_ModelView,"
94            "          uniform float4x4 in_Proj,"
95            "          uniform float3x3 in_NormalMat,"
96            "          out float4 out_Position : POSITION,"
97            "          out float4 pass_Color : COLOR) {"
98            "    float4 Light = float4(10.0, 1.0, 1.0, 1.0);"
99            "    float3 Kd = float3(1.0, 0.8, 0.8);"
100            "    float3 Ld = float3(1.0, 0.8, 0.8);"
101            ""
102            "    float3 tnorm = normalize(mul(in_NormalMat, in_Normal));"
103            "    float4 Eye = mul(in_ModelView, float4(in_Vertex, 1.0));"
104            "    float3 s = normalize((Light - Eye).xyz);"
105            ""
106            "    pass_Color = float4(Ld * Kd * max(dot(s, tnorm), 0.0), 1.0);"
107            "    out_Position = mul(in_Proj, Eye);"
108            "}",
109
110            "void main(float4 pass_Color : COLOR,"
111            "          out float4 out_FragColor : COLOR) {"
112            "    out_FragColor = pass_Color;"
113            "}"
114#endif
115        );
116        m_gpu.modelview = m_gpu.shader->GetUniformLocation("in_ModelView");
117        m_gpu.proj = m_gpu.shader->GetUniformLocation("in_Proj");
118        m_gpu.normalmat = m_gpu.shader->GetUniformLocation("in_NormalMat");
119        m_gpu.coord = m_gpu.shader->GetAttribLocation("in_Vertex",
120                                              VertexUsage::Position, 0);
121        m_gpu.norm = m_gpu.shader->GetAttribLocation("in_Normal",
122                                             VertexUsage::Normal, 0);
123        m_gpu.color = m_gpu.shader->GetAttribLocation("in_Color",
124                                              VertexUsage::Color, 0);
125
126        m_gpu.vdecl = new VertexDeclaration(
127            VertexStream<vec3,vec3,u8vec4>(VertexUsage::Position,
128                                           VertexUsage::Normal,
129                                           VertexUsage::Color));
130
131        Array<vec3,vec3,u8vec4> vertexlist;
132        for (int i = 0; i < m_vert.Count(); i++)
133            vertexlist.Append(m_vert[i].m1,
134                              m_vert[i].m2,
135                              (u8vec4)(m_vert[i].m3 * 255.f));
136
137        Array<uint16_t> indexlist;
138        for (int i = 0; i < m_triidx.Count(); i += 3)
139        {
140            indexlist += m_triidx[i + 0];
141            indexlist += m_triidx[i + 1];
142            indexlist += m_triidx[i + 2];
143        }
144        for (int i = 0; i < m_quadidx.Count(); i += 4)
145        {
146            indexlist += m_quadidx[i + 0];
147            indexlist += m_quadidx[i + 1];
148            indexlist += m_quadidx[i + 2];
149
150            indexlist += m_quadidx[i + 0];
151            indexlist += m_quadidx[i + 2];
152            indexlist += m_quadidx[i + 3];
153        }
154
155        m_gpu.vbo = new VertexBuffer(vertexlist.Bytes());
156        void *mesh = m_gpu.vbo->Lock(0, 0);
157        memcpy(mesh, &vertexlist[0], vertexlist.Bytes());
158        m_gpu.vbo->Unlock();
159
160        m_gpu.ibo = new IndexBuffer(indexlist.Bytes());
161        void *indices = m_gpu.ibo->Lock(0, 0);
162        memcpy(indices, &indexlist[0], indexlist.Bytes());
163        m_gpu.ibo->Unlock();
164
165        m_gpu.vertexcount = vertexlist.Count();
166        m_gpu.indexcount = indexlist.Count();
167    }
168
169    void Render(mat4 const &modelview, mat4 const &proj, mat3 const &normalmat)
170    {
171        m_gpu.shader->Bind();
172        m_gpu.shader->SetUniform(m_gpu.modelview, modelview);
173        m_gpu.shader->SetUniform(m_gpu.proj, proj);
174        m_gpu.shader->SetUniform(m_gpu.normalmat, normalmat);
175        m_gpu.vdecl->SetStream(m_gpu.vbo, m_gpu.coord, m_gpu.norm, m_gpu.color);
176        m_gpu.vdecl->Bind();
177        m_gpu.ibo->Bind();
178        m_gpu.vdecl->DrawIndexedElements(MeshPrimitive::Triangles,
179                                         0, 0, m_gpu.vertexcount,
180                                         0, m_gpu.indexcount / 3);
181        m_gpu.ibo->Unbind();
182        m_gpu.vdecl->Unbind();
183    }
184
185    void SetCurColor(vec4 const &color) { m_color = color; }
186    void SetCurColor2(vec4 const &color) { m_color2 = color; }
187
188    void AppendQuadVert(vec3 const &coord)
189    {
190        m_vert.Append(coord, vec3(0.f, 1.f, 0.f), m_color);
191    }
192
193    void AppendDuplicateQuadVert(int i)
194    {
195        m_vert.Append(m_vert[i].m1, vec3(0.f, 1.f, 0.f), m_vert[i].m3);
196    }
197
198    void AppendQuad(int i1, int i2, int i3, int i4, int base)
199    {
200        m_quadidx += base + i1;
201        m_quadidx += base + i2;
202        m_quadidx += base + i3;
203        m_quadidx += base + i4;
204    }
205
206    void AppendQuadDuplicateVerts(int i1, int i2, int i3, int i4, int base)
207    {
208        m_quadidx += m_vert.Count(); AppendDuplicateQuadVert(base + i1);
209        m_quadidx += m_vert.Count(); AppendDuplicateQuadVert(base + i2);
210        m_quadidx += m_vert.Count(); AppendDuplicateQuadVert(base + i3);
211        m_quadidx += m_vert.Count(); AppendDuplicateQuadVert(base + i4);
212    }
213
214    void AppendTriangle(int i1, int i2, int i3, int base)
215    {
216        m_triidx += base + i1;
217        m_triidx += base + i2;
218        m_triidx += base + i3;
219    }
220
221    void AppendTriangleDuplicateVerts(int i1, int i2, int i3, int base)
222    {
223        m_triidx += m_vert.Count(); AppendDuplicateQuadVert(base + i1);
224        m_triidx += m_vert.Count(); AppendDuplicateQuadVert(base + i2);
225        m_triidx += m_vert.Count(); AppendDuplicateQuadVert(base + i3);
226    }
227
228    void ComputeQuadNormals(int start, int vcount)
229    {
230        for (int i = 0; i < vcount; i += 4)
231        {
232            vec3 v0 = m_vert[m_quadidx[start + i + 2]].m1
233                    - m_vert[m_quadidx[start + i + 0]].m1;
234            vec3 v1 = m_vert[m_quadidx[start + i + 1]].m1
235                    - m_vert[m_quadidx[start + i + 0]].m1;
236            vec3 n = normalize(cross(v1, v0));
237
238            for (int j = 0; j < 4; j++)
239                m_vert[m_quadidx[start + i + j]].m2 = n;
240        }
241    }
242
243    void ComputeTriNormals(int start, int vcount)
244    {
245        for (int i = 0; i < vcount; i += 3)
246        {
247            vec3 v0 = m_vert[m_triidx[start + i + 2]].m1
248                    - m_vert[m_triidx[start + i + 0]].m1;
249            vec3 v1 = m_vert[m_triidx[start + i + 1]].m1
250                    - m_vert[m_triidx[start + i + 0]].m1;
251            vec3 n = normalize(cross(v1, v0));
252
253            for (int j = 0; j < 3; j++)
254                m_vert[m_triidx[start + i + j]].m2 = n;
255        }
256    }
257
258    void SetVertColor(vec4 const &color)
259    {
260        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
261            m_vert[i].m3 = color;
262    }
263
264    void SetCurVertNormal(vec3 const &normal)
265    {
266        m_vert[m_vert.Count() - 1].m2 = normal;
267    }
268
269    void SetCurVertColor(vec4 const &color)
270    {
271        m_vert[m_vert.Count() - 1].m3 = color;
272    }
273
274    void Translate(vec3 const &v)
275    {
276        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
277            m_vert[i].m1 += v;
278    }
279
280    void RotateZ(float t)
281    {
282        /* FIXME: use mat3 instead of mat4 when it's working */
283        mat4 m = mat4::rotate(t, 0, 0, 1);
284        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
285            m_vert[i].m1 = (m * vec4(m_vert[i].m1, 1.f)).xyz;
286    }
287
288    void RotateY(float t)
289    {
290        mat4 m = mat4::rotate(t, 0, 1, 0);
291        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
292            m_vert[i].m1 = (m * vec4(m_vert[i].m1, 1.f)).xyz;
293    }
294
295    void RotateX(float t)
296    {
297        mat4 m = mat4::rotate(t, 1, 0, 0);
298        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
299            m_vert[i].m1 = (m * vec4(m_vert[i].m1, 1.f)).xyz;
300    }
301
302    void TaperX(float y, float z, float xoff)
303    {
304        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
305        {
306            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.x + xoff);
307            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.x + xoff);
308        }
309    }
310
311    void TaperY(float x, float z, float yoff)
312    {
313        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
314        {
315            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.y + yoff);
316            m_vert[i].m1.z *= 1.f + (z * m_vert[i].m1.y + yoff);
317        }
318    }
319
320    void TaperZ(float x, float y, float zoff)
321    {
322        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
323        {
324            m_vert[i].m1.x *= 1.f + (x * m_vert[i].m1.z + zoff);
325            m_vert[i].m1.y *= 1.f + (y * m_vert[i].m1.z + zoff);
326        }
327    }
328
329    void Scale(vec3 const &s)
330    {
331        for (int i = m_vert_cursor; i < m_vert.Count(); i++)
332        {
333            m_vert[i].m1 *= s;
334            m_vert[i].m2 *= s;
335        }
336
337        // BH : TODO : not sure about this one
338        // Sam: not too sure either!
339        if (s.x * s.y * s.z < 0)
340        {
341            for (int i = m_quadidx_cursor; i < m_quadidx.Count(); i += 2)
342            {
343                uint16_t tmp = m_quadidx[i + 0];
344                m_quadidx[i + 0] = m_quadidx[i + 1];
345                m_quadidx[i + 1] = tmp;
346            }
347
348            for (int i = m_triidx_cursor; i < m_triidx.Count(); i += 3)
349            {
350                uint16_t tmp = m_triidx[i + 0];
351                m_triidx[i + 0] = m_triidx[i + 1];
352                m_triidx[i + 1] = tmp;
353            }
354        }
355    }
356
357    void MirrorX() { Duplicate(); Scale(vec3(-1, 1, 1)); }
358    void MirrorY() { Duplicate(); Scale(vec3(1, -1, 1)); }
359    void MirrorZ() { Duplicate(); Scale(vec3(1, 1, -1)); }
360
361    void Duplicate()
362    {
363        int vlen = m_vert.Count() - m_vert_cursor;
364        int qlen = m_quadidx.Count() - m_quadidx_cursor;
365        int tlen = m_triidx.Count() - m_triidx_cursor;
366
367        for (int i = 0; i < vlen; i++)
368            m_vert += m_vert[m_vert_cursor++];
369
370        for (int i = 0; i < qlen; i++)
371            m_quadidx += m_quadidx[m_quadidx_cursor++] + vlen;
372
373        for (int i = 0; i < tlen; i++)
374            m_triidx += m_triidx[m_triidx_cursor++] + vlen;
375    }
376
377    void AppendCylinder() {} /* TODO */
378
379    void AppendSphere(vec3 const &size, int divisions)
380    {
381        int ibase = m_quadidx.Count();
382        int vbase = m_vert.Count();
383
384        vec3 d = size * 0.5f;
385        float const pi = acos(-1.0f);
386
387        Array<vec2> table;
388        for (int i = 0; i <= divisions; i++)
389            table.Append(vec2(sin(pi * 2 / divisions * i) + 1e-5f,
390                              cos(pi * 2 / divisions * i) + 1e-5f));
391
392        for (int j = 0; j <= divisions / 2; j++)
393            for (int i = 0; i < divisions; i++)
394            {
395                int j2 = j + 1;
396                int i2 = (i + 1) % divisions;
397
398                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j].xxy);
399                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j].xxy);
400                AppendQuadVert(d * vec3(table[i2], 1.0f) * table[j2].xxy);
401                AppendQuadVert(d * vec3(table[i], 1.0f) * table[j2].xxy);
402            }
403
404        for (int i = vbase; i < m_vert.Count(); i += 4)
405            AppendQuad(0, 1, 2, 3, i);
406
407        ComputeQuadNormals(ibase, m_quadidx.Count() - ibase);
408    }
409
410    void AppendBox(vec3 const &size)
411    {
412        AppendBox(size, 0.f, false);
413    }
414
415    void AppendSmoothChamfBox(vec3 const &size, float chamf)
416    {
417        AppendBox(size, chamf, true);
418    }
419
420    void AppendFlatChamfBox(vec3 const &size, float chamf)
421    {
422        AppendBox(size, chamf, false);
423    }
424
425    void AppendBox(vec3 const &size, float chamf, bool smooth)
426    {
427        int vbase = m_vert.Count();
428        int qibase = m_quadidx.Count();
429        int tibase = m_triidx.Count();
430
431        vec3 d = size * 0.5f;
432
433        AppendQuadVert(vec3(-d.x, -d.y, -d.z - chamf));
434        AppendQuadVert(vec3(-d.x, +d.y, -d.z - chamf));
435        AppendQuadVert(vec3(+d.x, +d.y, -d.z - chamf));
436        AppendQuadVert(vec3(+d.x, -d.y, -d.z - chamf));
437
438        AppendQuadVert(vec3(-d.x - chamf, -d.y, +d.z));
439        AppendQuadVert(vec3(-d.x - chamf, +d.y, +d.z));
440        AppendQuadVert(vec3(-d.x - chamf, +d.y, -d.z));
441        AppendQuadVert(vec3(-d.x - chamf, -d.y, -d.z));
442
443        AppendQuadVert(vec3(+d.x, -d.y, +d.z + chamf));
444        AppendQuadVert(vec3(+d.x, +d.y, +d.z + chamf));
445        AppendQuadVert(vec3(-d.x, +d.y, +d.z + chamf));
446        AppendQuadVert(vec3(-d.x, -d.y, +d.z + chamf));
447
448        AppendQuadVert(vec3(+d.x + chamf, -d.y, -d.z));
449        AppendQuadVert(vec3(+d.x + chamf, +d.y, -d.z));
450        AppendQuadVert(vec3(+d.x + chamf, +d.y, +d.z));
451        AppendQuadVert(vec3(+d.x + chamf, -d.y, +d.z));
452
453        AppendQuadVert(vec3(-d.x, -d.y - chamf, +d.z));
454        AppendQuadVert(vec3(-d.x, -d.y - chamf, -d.z));
455        AppendQuadVert(vec3(+d.x, -d.y - chamf, -d.z));
456        AppendQuadVert(vec3(+d.x, -d.y - chamf, +d.z));
457
458        AppendQuadVert(vec3(-d.x, +d.y + chamf, -d.z));
459        AppendQuadVert(vec3(-d.x, +d.y + chamf, +d.z));
460        AppendQuadVert(vec3(+d.x, +d.y + chamf, +d.z));
461        AppendQuadVert(vec3(+d.x, +d.y + chamf, -d.z));
462
463        /* The 6 quads on each side of the box */
464        for (int i = 0; i < 24; i += 4)
465            AppendQuad(i, i + 1, i + 2, i + 3, vbase);
466
467        ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
468        qibase = m_quadidx.Count();
469
470        if (chamf)
471        {
472            /* The 8 quads at each edge of the box */
473            static int const quadlist[48] =
474            {
475                0, 3, 18, 17, 4, 7, 17, 16, 8, 11, 16, 19, 12, 15, 19, 18,
476                2, 1, 20, 23, 6, 5, 21, 20, 10, 9, 22, 21, 14, 13, 23, 22,
477                1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2,
478            };
479
480            for (int i = 0; i < 48; i += 4)
481            {
482                if (smooth)
483                    AppendQuad(quadlist[i], quadlist[i + 1],
484                               quadlist[i + 2], quadlist[i + 3], vbase);
485                else
486                    AppendQuadDuplicateVerts(quadlist[i], quadlist[i + 1],
487                                     quadlist[i + 2], quadlist[i + 3], vbase);
488            }
489
490            /* The 8 triangles at each corner of the box */
491            static int const trilist[24] =
492            {
493                3, 12, 18, 15, 8, 19, 11, 4, 16, 7, 0, 17,
494                2, 23, 13, 14, 22, 9, 10, 21, 5, 6, 20, 1,
495            };
496
497            for (int i = 0; i < 24; i += 3)
498            {
499                if (smooth)
500                    AppendTriangle(trilist[i], trilist[i + 1],
501                                   trilist[i + 2], vbase);
502                else
503                    AppendTriangleDuplicateVerts(trilist[i], trilist[i + 1],
504                                                 trilist[i + 2], vbase);
505            }
506        }
507
508        if (!smooth)
509        {
510            ComputeQuadNormals(qibase, m_quadidx.Count() - qibase);
511            ComputeTriNormals(tibase, m_triidx.Count() - tibase);
512        }
513    }
514
515    void AppendStar(int nbranches, float r1, float r2)
516    {
517        AppendStar(nbranches, r1, r2, 0, 0);
518    }
519
520    void AppendStar(int nbranches, float r1, float r2, int fade)
521    {
522        AppendStar(nbranches, r1, r2, fade, 0);
523    }
524
525    void AppendStar(int nbranches, float r1, float r2, int fade, int fade2)
526    {
527        int vbase = m_vert.Count();
528
529        AppendQuadVert(vec3(0.f, 0.f, 0.f));
530
531        /* FIXME: use mat3 instead of mat4 when it's working */
532        mat3 rotmat(mat4::rotate(180.0f / nbranches, 0.f, 1.f, 0.f));
533        vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f);
534
535        p2 = rotmat * p2;
536        rotmat = rotmat * rotmat;
537
538        for (int i = 0; i < nbranches; i++)
539        {
540            AppendQuadVert(p1);
541            if (fade2)
542                SetCurVertColor(m_color2);
543
544            AppendQuadVert(p2);
545            if (fade)
546                SetCurVertColor(m_color2);
547
548            AppendQuad(0, (2 * i + 3) % (2 * nbranches),
549                       2 * i + 2, 2 * i + 1, vbase);
550
551            p1 = rotmat * p1;
552            p2 = rotmat * p2;
553        }
554    }
555
556    void AppendExpandedStar() {} /* TODO */
557    void AppendDisc() {} /* TODO */
558    void AppendSimpleTriangle() {} /* TODO */
559    void AppendSimpleQuad() {} /* TODO */
560    void AppendCog() {} /* TODO */
561
562private:
563    vec4 m_color, m_color2;
564    Array<uint16_t> m_triidx, m_quadidx;
565    Array<vec3, vec3, vec4> m_vert;
566    int m_vert_cursor, m_quadidx_cursor, m_triidx_cursor;
567
568    struct
569    {
570        Shader *shader;
571        ShaderAttrib coord, norm, color;
572        ShaderUniform modelview, proj, normalmat;
573        VertexDeclaration *vdecl;
574        VertexBuffer *vbo;
575        IndexBuffer *ibo;
576        int vertexcount, indexcount;
577    }
578    m_gpu;
579};
580
581#endif /* __MESH_H__ */
582
Note: See TracBrowser for help on using the repository browser.