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