1/*
2 * Copyright (C) 2016 Google, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <cassert>
18#include <cmath>
19#include <cstring>
20#include <array>
21#include <unordered_map>
22
23#include "Helpers.h"
24#include "Meshes.h"
25
26namespace {
27
28class Mesh {
29public:
30    struct Position {
31        float x;
32        float y;
33        float z;
34    };
35
36    struct Normal {
37        float x;
38        float y;
39        float z;
40    };
41
42    struct Face {
43        int v0;
44        int v1;
45        int v2;
46    };
47
48    static uint32_t vertex_stride()
49    {
50        // Position + Normal
51        const int comp_count = 6;
52
53        return sizeof(float) * comp_count;
54    }
55
56    static VkVertexInputBindingDescription vertex_input_binding()
57    {
58        VkVertexInputBindingDescription vi_binding = {};
59        vi_binding.binding = 0;
60        vi_binding.stride = vertex_stride();
61        vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
62
63        return vi_binding;
64    }
65
66    static std::vector<VkVertexInputAttributeDescription> vertex_input_attributes()
67    {
68        std::vector<VkVertexInputAttributeDescription> vi_attrs(2);
69        // Position
70        vi_attrs[0].location = 0;
71        vi_attrs[0].binding = 0;
72        vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
73        vi_attrs[0].offset = 0;
74        // Normal
75        vi_attrs[1].location = 1;
76        vi_attrs[1].binding = 0;
77        vi_attrs[1].format = VK_FORMAT_R32G32B32_SFLOAT;
78        vi_attrs[1].offset = sizeof(float) * 3;
79
80        return vi_attrs;
81    }
82
83    static VkIndexType index_type()
84    {
85        return VK_INDEX_TYPE_UINT32;
86    }
87
88    static VkPipelineInputAssemblyStateCreateInfo input_assembly_state()
89    {
90        VkPipelineInputAssemblyStateCreateInfo ia_info = {};
91        ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
92        ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
93        ia_info.primitiveRestartEnable = false;
94        return ia_info;
95    }
96
97    void build(const std::vector<std::array<float, 6>> &vertices, const std::vector<std::array<int, 3>> &faces)
98    {
99        positions_.reserve(vertices.size());
100        normals_.reserve(vertices.size());
101        for (const auto &v : vertices) {
102            positions_.emplace_back(Position{ v[0], v[1], v[2] });
103            normals_.emplace_back(Normal{ v[3], v[4], v[5] });
104        }
105
106        faces_.reserve(faces.size());
107        for (const auto &f : faces)
108            faces_.emplace_back(Face{ f[0], f[1], f[2] });
109    }
110
111    uint32_t vertex_count() const
112    {
113        return static_cast<uint32_t>(positions_.size());
114    }
115
116    VkDeviceSize vertex_buffer_size() const
117    {
118        return vertex_stride() * vertex_count();
119    }
120
121    void vertex_buffer_write(void *data) const
122    {
123        float *dst = reinterpret_cast<float *>(data);
124        for (size_t i = 0; i < positions_.size(); i++) {
125            const Position &pos = positions_[i];
126            const Normal &normal = normals_[i];
127            dst[0] = pos.x;
128            dst[1] = pos.y;
129            dst[2] = pos.z;
130            dst[3] = normal.x;
131            dst[4] = normal.y;
132            dst[5] = normal.z;
133            dst += 6;
134        }
135    }
136
137    uint32_t index_count() const
138    {
139        return static_cast<uint32_t>(faces_.size()) * 3;
140    }
141
142    VkDeviceSize index_buffer_size() const
143    {
144        return sizeof(uint32_t) * index_count();
145    }
146
147    void index_buffer_write(void *data) const
148    {
149        uint32_t *dst = reinterpret_cast<uint32_t *>(data);
150        for (const auto &face : faces_) {
151            dst[0] = face.v0;
152            dst[1] = face.v1;
153            dst[2] = face.v2;
154            dst += 3;
155        }
156    }
157
158    std::vector<Position> positions_;
159    std::vector<Normal> normals_;
160    std::vector<Face> faces_;
161};
162
163class BuildPyramid {
164public:
165    BuildPyramid(Mesh &mesh)
166    {
167        const std::vector<std::array<float, 6>> vertices = {
168            //      position                normal
169            {  0.0f,  0.0f,  1.0f,    0.0f,  0.0f,  1.0f },
170            { -1.0f, -1.0f, -1.0f,   -1.0f, -1.0f, -1.0f },
171            {  1.0f, -1.0f, -1.0f,    1.0f, -1.0f, -1.0f },
172            {  1.0f,  1.0f, -1.0f,    1.0f,  1.0f, -1.0f },
173            { -1.0f,  1.0f, -1.0f,   -1.0f,  1.0f, -1.0f },
174        };
175
176        const std::vector<std::array<int, 3>> faces = {
177            { 0, 1, 2 },
178            { 0, 2, 3 },
179            { 0, 3, 4 },
180            { 0, 4, 1 },
181            { 1, 4, 3 },
182            { 1, 3, 2 },
183        };
184
185        mesh.build(vertices, faces);
186    }
187};
188
189class BuildIcosphere {
190public:
191    BuildIcosphere(Mesh &mesh) : mesh_(mesh), radius_(1.0f)
192    {
193        const int tessellate_level = 2;
194
195        build_icosahedron();
196        for (int i = 0; i < tessellate_level; i++)
197            tessellate();
198    }
199
200private:
201    void build_icosahedron()
202    {
203        // https://en.wikipedia.org/wiki/Regular_icosahedron
204        const float l1 = std::sqrt(2.0f / (5.0f + std::sqrt(5.0f))) * radius_;
205        const float l2 = std::sqrt(2.0f / (5.0f - std::sqrt(5.0f))) * radius_;
206        // vertices are from three golden rectangles
207        const std::vector<std::array<float, 6>> icosahedron_vertices = {
208            //   position           normal
209            { -l1, -l2, 0.0f,   -l1, -l2, 0.0f, },
210            {  l1, -l2, 0.0f,    l1, -l2, 0.0f, },
211            {  l1,  l2, 0.0f,    l1,  l2, 0.0f, },
212            { -l1,  l2, 0.0f,   -l1,  l2, 0.0f, },
213
214            { -l2, 0.0f, -l1,   -l2, 0.0f, -l1, },
215            {  l2, 0.0f, -l1,    l2, 0.0f, -l1, },
216            {  l2, 0.0f,  l1,    l2, 0.0f,  l1, },
217            { -l2, 0.0f,  l1,   -l2, 0.0f,  l1, },
218
219            { 0.0f, -l1, -l2,   0.0f, -l1, -l2, },
220            { 0.0f,  l1, -l2,   0.0f,  l1, -l2, },
221            { 0.0f,  l1,  l2,   0.0f,  l1,  l2, },
222            { 0.0f, -l1,  l2,   0.0f, -l1,  l2, },
223        };
224        const std::vector<std::array<int, 3>> icosahedron_faces = {
225            // triangles sharing vertex 0
226            {  0,  1, 11 },
227            {  0, 11,  7 },
228            {  0,  7,  4 },
229            {  0,  4,  8 },
230            {  0,  8,  1 },
231            // adjacent triangles
232            { 11,  1,  6 },
233            {  7, 11, 10 },
234            {  4,  7,  3 },
235            {  8,  4,  9 },
236            {  1,  8,  5 },
237            // triangles sharing vertex 2
238            {  2,  3, 10 },
239            {  2, 10,  6 },
240            {  2,  6,  5 },
241            {  2,  5,  9 },
242            {  2,  9,  3 },
243            // adjacent triangles
244            { 10,  3,  7 },
245            {  6, 10, 11 },
246            {  5,  6,  1 },
247            {  9,  5,  8 },
248            {  3,  9,  4 },
249        };
250
251        mesh_.build(icosahedron_vertices, icosahedron_faces);
252    }
253
254    void tessellate()
255    {
256        size_t middle_point_count = mesh_.faces_.size() * 3 / 2;
257        size_t final_face_count = mesh_.faces_.size() * 4;
258
259        std::vector<Mesh::Face> faces;
260        faces.reserve(final_face_count);
261
262        middle_points_.clear();
263        middle_points_.reserve(middle_point_count);
264
265        mesh_.positions_.reserve(mesh_.vertex_count() + middle_point_count);
266        mesh_.normals_.reserve(mesh_.vertex_count() + middle_point_count);
267
268        for (const auto &f : mesh_.faces_) {
269            int v0 = f.v0;
270            int v1 = f.v1;
271            int v2 = f.v2;
272
273            int v01 = add_middle_point(v0, v1);
274            int v12 = add_middle_point(v1, v2);
275            int v20 = add_middle_point(v2, v0);
276
277            faces.emplace_back(Mesh::Face{ v0, v01, v20 });
278            faces.emplace_back(Mesh::Face{ v1, v12, v01 });
279            faces.emplace_back(Mesh::Face{ v2, v20, v12 });
280            faces.emplace_back(Mesh::Face{ v01, v12, v20 });
281        }
282
283        mesh_.faces_.swap(faces);
284    }
285
286    int add_middle_point(int a, int b)
287    {
288        uint64_t key = (a < b) ? ((uint64_t) a << 32 | b) : ((uint64_t) b << 32 | a);
289        auto it = middle_points_.find(key);
290        if (it != middle_points_.end())
291            return it->second;
292
293        const Mesh::Position &pos_a = mesh_.positions_[a];
294        const Mesh::Position &pos_b = mesh_.positions_[b];
295        Mesh::Position pos_mid = {
296            (pos_a.x + pos_b.x) / 2.0f,
297            (pos_a.y + pos_b.y) / 2.0f,
298            (pos_a.z + pos_b.z) / 2.0f,
299        };
300        float scale = radius_ / std::sqrt(pos_mid.x * pos_mid.x +
301                                          pos_mid.y * pos_mid.y +
302                                          pos_mid.z * pos_mid.z);
303        pos_mid.x *= scale;
304        pos_mid.y *= scale;
305        pos_mid.z *= scale;
306
307        Mesh::Normal normal_mid = { pos_mid.x, pos_mid.y, pos_mid.z };
308        normal_mid.x /= radius_;
309        normal_mid.y /= radius_;
310        normal_mid.z /= radius_;
311
312        mesh_.positions_.emplace_back(pos_mid);
313        mesh_.normals_.emplace_back(normal_mid);
314
315        int mid = mesh_.vertex_count() - 1;
316        middle_points_.emplace(std::make_pair(key, mid));
317
318        return mid;
319    }
320
321    Mesh &mesh_;
322    const float radius_;
323    std::unordered_map<uint64_t, uint32_t> middle_points_;
324};
325
326class BuildTeapot {
327public:
328    BuildTeapot(Mesh &mesh)
329    {
330#include "Meshes.teapot.h"
331        const int position_count = sizeof(teapot_positions) / sizeof(teapot_positions[0]);
332        const int index_count = sizeof(teapot_indices) / sizeof(teapot_indices[0]);
333        assert(position_count % 3 == 0 && index_count % 3 == 0);
334
335        Mesh::Position translate;
336        float scale;
337        get_transform(teapot_positions, position_count, translate, scale);
338
339        for (int i = 0; i < position_count; i += 3) {
340            mesh.positions_.emplace_back(Mesh::Position{
341                (teapot_positions[i + 0] + translate.x) * scale,
342                (teapot_positions[i + 1] + translate.y) * scale,
343                (teapot_positions[i + 2] + translate.z) * scale,
344            });
345
346            mesh.normals_.emplace_back(Mesh::Normal{
347                teapot_normals[i + 0],
348                teapot_normals[i + 1],
349                teapot_normals[i + 2],
350            });
351        }
352
353        for (int i = 0; i < index_count; i += 3) {
354            mesh.faces_.emplace_back(Mesh::Face{
355                teapot_indices[i + 0],
356                teapot_indices[i + 1],
357                teapot_indices[i + 2]
358            });
359        }
360    }
361
362    void get_transform(const float *positions, int position_count,
363                       Mesh::Position &translate, float &scale)
364    {
365        float min[3] = {
366            positions[0],
367            positions[1],
368            positions[2],
369        };
370        float max[3] = {
371            positions[0],
372            positions[1],
373            positions[2],
374        };
375        for (int i = 3; i < position_count; i += 3) {
376            for (int j = 0; j < 3; j++) {
377                if (min[j] > positions[i + j])
378                    min[j] = positions[i + j];
379                if (max[j] < positions[i + j])
380                    max[j] = positions[i + j];
381            }
382        }
383
384        translate.x = -(min[0] + max[0]) / 2.0f;
385        translate.y = -(min[1] + max[1]) / 2.0f;
386        translate.z = -(min[2] + max[2]) / 2.0f;
387
388        float extents[3] = {
389            max[0] + translate.x,
390            max[1] + translate.y,
391            max[2] + translate.z,
392        };
393
394        float max_extent = extents[0];
395        if (max_extent < extents[1])
396            max_extent = extents[1];
397        if (max_extent < extents[2])
398            max_extent = extents[2];
399
400        scale = 1.0f / max_extent;
401    }
402};
403
404void build_meshes(std::array<Mesh, Meshes::MESH_COUNT> &meshes)
405{
406    BuildPyramid build_pyramid(meshes[Meshes::MESH_PYRAMID]);
407    BuildIcosphere build_icosphere(meshes[Meshes::MESH_ICOSPHERE]);
408    BuildTeapot build_teapot(meshes[Meshes::MESH_TEAPOT]);
409}
410
411} // namespace
412
413Meshes::Meshes(VkDevice dev, const std::vector<VkMemoryPropertyFlags> &mem_flags)
414    : dev_(dev),
415      vertex_input_binding_(Mesh::vertex_input_binding()),
416      vertex_input_attrs_(Mesh::vertex_input_attributes()),
417      vertex_input_state_(),
418      input_assembly_state_(Mesh::input_assembly_state()),
419      index_type_(Mesh::index_type())
420{
421    vertex_input_state_.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
422    vertex_input_state_.vertexBindingDescriptionCount = 1;
423    vertex_input_state_.pVertexBindingDescriptions = &vertex_input_binding_;
424    vertex_input_state_.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attrs_.size());
425    vertex_input_state_.pVertexAttributeDescriptions = vertex_input_attrs_.data();
426
427    std::array<Mesh, MESH_COUNT> meshes;
428    build_meshes(meshes);
429
430    draw_commands_.reserve(meshes.size());
431    uint32_t first_index = 0;
432    int32_t vertex_offset = 0;
433    VkDeviceSize vb_size = 0;
434    VkDeviceSize ib_size = 0;
435    for (const auto &mesh : meshes) {
436        VkDrawIndexedIndirectCommand draw = {};
437        draw.indexCount = mesh.index_count();
438        draw.instanceCount = 1;
439        draw.firstIndex = first_index;
440        draw.vertexOffset = vertex_offset;
441        draw.firstInstance = 0;
442
443        draw_commands_.push_back(draw);
444
445        first_index += mesh.index_count();
446        vertex_offset += mesh.vertex_count();
447        vb_size += mesh.vertex_buffer_size();
448        ib_size += mesh.index_buffer_size();
449    }
450
451    allocate_resources(vb_size, ib_size, mem_flags);
452
453    uint8_t *vb_data, *ib_data;
454    vk::assert_success(vk::MapMemory(dev_, mem_, 0, VK_WHOLE_SIZE,
455                0, reinterpret_cast<void **>(&vb_data)));
456    ib_data = vb_data + ib_mem_offset_;
457
458    for (const auto &mesh : meshes) {
459        mesh.vertex_buffer_write(vb_data);
460        mesh.index_buffer_write(ib_data);
461        vb_data += mesh.vertex_buffer_size();
462        ib_data += mesh.index_buffer_size();
463    }
464
465    vk::UnmapMemory(dev_, mem_);
466}
467
468Meshes::~Meshes()
469{
470    vk::FreeMemory(dev_, mem_, nullptr);
471    vk::DestroyBuffer(dev_, vb_, nullptr);
472    vk::DestroyBuffer(dev_, ib_, nullptr);
473}
474
475void Meshes::cmd_bind_buffers(VkCommandBuffer cmd) const
476{
477    const VkDeviceSize vb_offset = 0;
478    vk::CmdBindVertexBuffers(cmd, 0, 1, &vb_, &vb_offset);
479
480    vk::CmdBindIndexBuffer(cmd, ib_, 0, index_type_);
481}
482
483void Meshes::cmd_draw(VkCommandBuffer cmd, Type type) const
484{
485    const auto &draw = draw_commands_[type];
486    vk::CmdDrawIndexed(cmd, draw.indexCount, draw.instanceCount,
487            draw.firstIndex, draw.vertexOffset, draw.firstInstance);
488}
489
490void Meshes::allocate_resources(VkDeviceSize vb_size, VkDeviceSize ib_size, const std::vector<VkMemoryPropertyFlags> &mem_flags)
491{
492    VkBufferCreateInfo buf_info = {};
493    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
494    buf_info.size = vb_size;
495    buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
496    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
497    vk::CreateBuffer(dev_, &buf_info, nullptr, &vb_);
498
499    buf_info.size = ib_size;
500    buf_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
501    vk::CreateBuffer(dev_, &buf_info, nullptr, &ib_);
502
503    VkMemoryRequirements vb_mem_reqs, ib_mem_reqs;
504    vk::GetBufferMemoryRequirements(dev_, vb_, &vb_mem_reqs);
505    vk::GetBufferMemoryRequirements(dev_, ib_, &ib_mem_reqs);
506
507    // indices follow vertices
508    ib_mem_offset_ = vb_mem_reqs.size +
509        (ib_mem_reqs.alignment - (vb_mem_reqs.size % ib_mem_reqs.alignment));
510
511    VkMemoryAllocateInfo mem_info = {};
512    mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
513    mem_info.allocationSize = ib_mem_offset_ + ib_mem_reqs.size;
514
515    // find any supported and mappable memory type
516    uint32_t mem_types = (vb_mem_reqs.memoryTypeBits & ib_mem_reqs.memoryTypeBits);
517    for (uint32_t idx = 0; idx < mem_flags.size(); idx++) {
518        if ((mem_types & (1 << idx)) &&
519            (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
520            (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
521            // TODO this may not be reachable
522            mem_info.memoryTypeIndex = idx;
523            break;
524        }
525    }
526
527    vk::AllocateMemory(dev_, &mem_info, nullptr, &mem_);
528
529    vk::BindBufferMemory(dev_, vb_, mem_, 0);
530    vk::BindBufferMemory(dev_, ib_, mem_, ib_mem_offset_);
531}
532