geometrydatafactory.cpp 17.8 KB
Newer Older
1
2
3
4
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
6
7
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
11
12
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
25
26
// 
// ================================================================================================

#include "geometrydatafactory.h"

27
#include "cgt/assert.h"
28

29
30
#include "core/tools/teapot.h"

31
32
namespace campvis {

33
    std::unique_ptr<FaceGeometry> GeometryDataFactory::createQuad(const cgt::vec3& llf, const cgt::vec3& urb, const cgt::vec3& texLlf, const cgt::vec3& texUrb) {
34
        std::vector<cgt::vec3> vertices, texCorods;
35

36
37
38
39
        vertices.push_back(cgt::vec3(llf.x, llf.y, llf.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, llf.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, llf.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, llf.z));
40

41
42
43
44
        texCorods.push_back(cgt::vec3(texLlf.x, texLlf.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texUrb.x, texLlf.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texUrb.x, texUrb.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texLlf.x, texUrb.y, texLlf.z));
45

46
        return std::unique_ptr<FaceGeometry>(new FaceGeometry(vertices, texCorods));
47
48
    }

49
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createGrid(const cgt::vec3& llf, const cgt::vec3& urb, const cgt::vec3& texLlf, const cgt::vec3& texUrb, int xSegments, int ySegments) {
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        cgtAssert(xSegments > 0 && ySegments > 1, "Grid must have at least one segment in each direction");

        int numVertices = (xSegments + 1) * (ySegments + 1);
        std::vector<cgt::vec3> vertices(numVertices);
        std::vector<cgt::vec3> textureCoordinates(numVertices);
        std::vector<cgt::vec3> normals(numVertices);

        // Compute vertices of the grid in x-major order
        for (int y = 0; y <= ySegments; ++y) {
            for (int x = 0; x <= xSegments; ++x) {
                int idx = y * (xSegments + 1) + x;

                float ux = x / static_cast<float>(xSegments);
                float uy = y / static_cast<float>(ySegments);

                vertices[idx] = cgt::vec3(llf.x * (1-ux) + urb.x * ux,
                                          llf.y * (1-uy) + urb.y * uy,
                                          llf.z);
                textureCoordinates[idx] = cgt::vec3(texLlf.x * (1-ux) + texUrb.x * ux,
                                                    texLlf.y * (1-uy) + texUrb.y * uy,
                                                    texLlf.z);
                normals[idx] = cgt::vec3(0, 0, 1);
            }
        }

75
        auto result = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), normals);
76
77
78
79
80
81
82
83
84
85
86
87
88

        // For each horizontal stripe, construct the indeces for triangle strips
        int verticesPerStrip = (xSegments + 1) * 2;
        for (int y = 0; y < ySegments; ++y) {
            std::vector<uint16_t> indices(verticesPerStrip);
            for (uint16_t x = 0; x <= xSegments; ++x) {
                indices[x*2 + 0] = (y + 0) * (xSegments + 1) + x;
                indices[x*2 + 1] = (y + 1) * (xSegments + 1) + x;
            }

            result->addPrimitive(indices);
        }

89
        return std::unique_ptr<MultiIndexedGeometry>(result);
90
91
92
    }


93
    std::unique_ptr<MeshGeometry> GeometryDataFactory::createCube(const cgt::Bounds& bounds, const cgt::Bounds& texBounds) {
94
95
96
97
        const cgt::vec3& llf = bounds.getLLF();
        const cgt::vec3& urb = bounds.getURB();
        const cgt::vec3& tLlf = texBounds.getLLF();
        const cgt::vec3& tUrb = texBounds.getURB();
98
99

        // not the most elegant method, but it works...
100
        std::vector<cgt::vec3> vertices, texCoords;
101
102
103
        std::vector<FaceGeometry> faces;

        // front
104
105
106
107
108
109
110
111
112
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, llf.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, llf.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, llf.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, llf.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 0.f, -1.f))));
113
114
115
116
        vertices.clear();
        texCoords.clear();

        // right
117
118
119
120
121
122
123
124
125
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, llf.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, urb.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, llf.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(1.f, 0.f, 0.f))));
126
127
128
129
        vertices.clear();
        texCoords.clear();

        // top
130
131
132
133
134
135
136
137
138
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, llf.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, llf.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 1.f, 0.f))));
139
140
141
142
        vertices.clear();
        texCoords.clear();

        // left
143
144
145
146
147
148
149
150
151
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, llf.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, llf.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, urb.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(-1.f, 0.f, 0.f))));
152
153
154
155
        vertices.clear();
        texCoords.clear();

        // bottom
156
157
158
159
160
161
162
163
164
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, llf.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, llf.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, urb.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, urb.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, -1.f, 0.f))));
165
166
167
168
        vertices.clear();
        texCoords.clear();

        // back
169
170
171
172
173
174
175
176
177
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, urb.z));
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(llf.x, llf.y, urb.z));
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, urb.z));
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 0.f, 1.f))));
178
179
180
        vertices.clear();
        texCoords.clear();

181
        return std::unique_ptr<MeshGeometry>(new MeshGeometry(faces));
182
183
    }

184
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createTeapot() {
185
        std::vector<cgt::vec3> vertices, normals;
186
187
        vertices.reserve(Teapot::num_teapot_vertices);
        normals.reserve(Teapot::num_teapot_vertices);
188

189
        for (size_t i = 0; i < Teapot::num_teapot_vertices; ++i) {
190
191
            vertices.push_back(cgt::vec3(Teapot::teapot_vertices + 3*i));
            normals.push_back(cgt::vec3(Teapot::teapot_normals + 3*i));
192
193
        }

194
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, std::vector<cgt::vec3>(), std::vector<cgt::vec4>(), normals);
195
196
197

        // convert indices and add primitives 
        int currentOffset = 0;
198
199
200
        while (currentOffset < Teapot::num_teapot_indices) {
            uint16_t count = Teapot::new_teapot_indicies[currentOffset];
            toReturn->addPrimitive(std::vector<uint16_t>(Teapot::new_teapot_indicies + currentOffset + 1, Teapot::new_teapot_indicies + count + currentOffset + 1));
201
202
203
            currentOffset += count + 1;
        }

204
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
205
206
    }

207
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/, const cgt::vec3& exponents /*= cgt::vec3(1.f)*/) {
208
209
210
        cgtAssert(numStacks > 1 && numSlices > 2, "Sphere must have minimum 2 stacks and 3 slices!");
        std::vector<cgt::vec3> vertices;
        std::vector<cgt::vec3> textureCoordinates;
211
212

        // add top vertex
213
214
        vertices.push_back(cgt::vec3(0.f, 0.f, 1.f));
        textureCoordinates.push_back(cgt::vec3(0.f));
215
216
217

        // add middle vertices
        for (int i = 1; i < numStacks; ++i) {
218
            float phi = static_cast<float>(i) * cgt::PIf / static_cast<float>(numStacks);
219
220

            for (int j = 0; j < numSlices; ++j) {
221
                float theta = static_cast<float>(j) * 2.f*cgt::PIf / static_cast<float>(numSlices);
222
223
224
225
226
227
228
229
230
231
232

                // apply exponents for supersphere
                cgt::vec3 theVertex(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
                for (size_t e = 0; e < 3; ++e) {
                    if (theVertex[e] < 0)
                        theVertex[e] = -pow(-theVertex[e], exponents[e]);
                    else
                        theVertex[e] = pow(theVertex[e], exponents[e]);
                }

                vertices.push_back(theVertex);
233
                textureCoordinates.push_back(cgt::vec3(theta / (2.f * cgt::PIf), phi / cgt::PIf, 0.f));
234
235
236
237
            }
        }

        // add bottom vertex
238
239
        vertices.push_back(cgt::vec3(0.f, 0.f, -1.f));
        textureCoordinates.push_back(cgt::vec3(1.f, 0.f, 0.f));
240
241

        // create geometry (in a unit sphere vertices = normals)
242
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), vertices);
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

        // add indices for primitives to geometry:
        {
            // top stack:
            std::vector<uint16_t> indices;
            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(0);
                indices.push_back(j+1);
            }
            indices.push_back(0);
            indices.push_back(1);

            toReturn->addPrimitive(indices);
        }
        {
            // middle stacks:
            std::vector<uint16_t> indices;
            for (uint16_t i = 1; i < numStacks-1; ++i) {
                uint16_t startIndex = 1 + (i-1) * numSlices;

                for (uint16_t j = 0; j < numSlices; ++j) {
                    indices.push_back(startIndex + j);
                    indices.push_back(startIndex + numSlices + j);
                }
                indices.push_back(startIndex);
                indices.push_back(startIndex + numSlices);
            }

            toReturn->addPrimitive(indices);
        }
        {
            // bottom stack:
            std::vector<uint16_t> indices;
            uint16_t endIndex = static_cast<uint16_t>(vertices.size() - 1);

            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(endIndex);
                indices.push_back(endIndex - (j+1));
            }
            indices.push_back(endIndex);
            indices.push_back(endIndex - 1);

            toReturn->addPrimitive(indices);
        }

288
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
289
290
    }

291
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createArrow(uint16_t numSlices, float tipLen, float cylRadius, float tipRadius) {
292
293
294
295
296
297
        cgtAssert(numSlices > 2, "Arrow shaft must have minimum 3 slices!");
        cgtAssert(tipRadius > cylRadius, "Tip radius must exceed cyclinder radius (for correct normals)!");
        cgtAssert(tipLen > 0, "Tip length must be between 0 and 1!");
        cgtAssert(tipLen < 1, "Tip length must be between 0 and 1!");
        std::vector<cgt::vec3> vertices;
        std::vector<cgt::vec3> normals;
298

299
        // add bottom vertex
300
301
        vertices.push_back(cgt::vec3(0.f, 0.f, 0.f));
        normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
302

303
304
        // add shaft floor vertices
        for (int i = 0; i < numSlices; ++i) {
305
306
307
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
308
309
        }
        for (int i = 0; i < numSlices; ++i) {
310
311
312
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
            normals.push_back(cgt::vec3(cos(theta), sin(theta), 0.f));
313
        }
314

315
316
        // add shaft top vertices
        for (int i = 0; i < numSlices; ++i) {
317
318
319
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(cos(theta), sin(theta), 0.f));
320
321
        }
        for (int i = 0; i < numSlices; ++i) {
322
323
324
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
325
        }
326

327
328
        // add arrow tip outer cone vertices
        for (int i = 0; i < numSlices; ++i) {
329
330
331
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
332
333
334
        }
        float phi = atan2f(tipRadius, tipLen);
        for (int i = 0; i < numSlices; ++i) {
335
336
337
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(cos(theta) * cos(phi), sin(theta) * cos(phi), sin(phi)));
338
        }
339

340
        // add top vertex
341
342
        vertices.push_back(cgt::vec3(0.f, 0.f, 1.f));
        normals.push_back(cgt::vec3(0.f, 0.f, 1.f));
343
344

        // create geometry
345
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, std::vector<cgt::vec3>(), std::vector<cgt::vec4>(), normals);
346
347
348
349
350
351
352
353
354
355
356
357
358
359

        // add indices for primitives to geometry:
        {
            // cylinder floor
            std::vector<uint16_t> indices;
            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(0);
                indices.push_back(j+1);
            }
            indices.push_back(0);
            indices.push_back(1);

            toReturn->addPrimitive(indices);
        }
360
        {
361
362
363
364
365
366
367
368
369
370
371
            // cylinder shaft
            std::vector<uint16_t> indices;
            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(j+1+numSlices);
                indices.push_back(j+1+numSlices*2);
            }
            indices.push_back(1+numSlices);
            indices.push_back(1+numSlices*2);

            toReturn->addPrimitive(indices);
        }
372
        {
373
374
375
376
377
378
379
380
381
382
383
            // arrow tip bottom area
            std::vector<uint16_t> indices;
            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(j+1+numSlices*3);
                indices.push_back(j+1+numSlices*4);
            }
            indices.push_back(1+numSlices*3);
            indices.push_back(1+numSlices*4);

            toReturn->addPrimitive(indices);
        }
384
        {
385
            // arrow tip cone
386
            uint16_t m = static_cast<uint16_t>(vertices.size() - 1);
387
388
389
            std::vector<uint16_t> indices;
            for (uint16_t j = 0; j < numSlices; ++j) {
                indices.push_back(j+1+numSlices*5);
390
                indices.push_back(m);
391
392
393
394
395
396
397
            }
            indices.push_back(1+numSlices*5);
            indices.push_back(m);

            toReturn->addPrimitive(indices);
        }

398
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
399
    }
400

401
}