summaryrefslogtreecommitdiffstats
path: root/src/datavis3d/utils/vertexindexer.cpp
blob: c54cbf8a24a84f8608794e1197b44a140167d8ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "vertexindexer_p.h"

#include <string.h> // for memcmp

#include <QDebug>

QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE

int unique_vertices = 0;

// Returns true if v1 can be considered equal to v2
bool VertexIndexer::is_near(float v1, float v2)
{
    return fabs(v1 - v2) < 0.01f;
}

// Searches through all already-exported vertices
// for a similar one.
// Similar = same position + same UVs + same normal
bool VertexIndexer::getSimilarVertexIndex(QVector3D &in_vertex
                                          , QVector2D &in_uv
                                          , QVector3D &in_normal
                                          , QVector<QVector3D> &out_vertices
                                          , QVector<QVector2D> &out_uvs
                                          , QVector<QVector3D> &out_normals
                                          , unsigned short &result)
{
    // Lame linear search
    for (int i = 0; i < out_vertices.size(); i++) {
        if (is_near(in_vertex.x() , out_vertices[i].x())
                && is_near(in_vertex.y() , out_vertices[i].y())
                && is_near(in_vertex.z() , out_vertices[i].z())
                && is_near(in_uv.x()     , out_uvs     [i].x())
                && is_near(in_uv.y()     , out_uvs     [i].y())
                && is_near(in_normal.x() , out_normals [i].x())
                && is_near(in_normal.y() , out_normals [i].y())
                && is_near(in_normal.z() , out_normals [i].z())) {
            result = i;
            return true;
        }
    }
    // No other vertex could be used instead.
    // Looks like we'll have to add it to the VBO.
    return false;
}

bool VertexIndexer::getSimilarVertexIndex_fast(PackedVertex &packed
                                               , QMap<PackedVertex, unsigned short> &VertexToOutIndex
                                               , unsigned short &result)
{
    QMap<PackedVertex, unsigned short>::iterator it = VertexToOutIndex.find(packed);
    if (it == VertexToOutIndex.end()) {
        return false;
    }
    else {
        result = it.value();
        return true;
    }
}

void VertexIndexer::indexVBO(QVector<QVector3D> &in_vertices
                             , QVector<QVector2D> &in_uvs
                             , QVector<QVector3D> &in_normals
                             , QVector<unsigned short> &out_indices
                             , QVector<QVector3D> &out_vertices
                             , QVector<QVector2D> &out_uvs
                             , QVector<QVector3D> &out_normals)
{
    unique_vertices = 0;
    QMap<PackedVertex, unsigned short> VertexToOutIndex;

    // For each input vertex
    for (int i = 0; i < in_vertices.size(); i++) {
        PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]};

        // Try to find a similar vertex in out_XXXX
        unsigned short index;
        bool found = getSimilarVertexIndex_fast(packed, VertexToOutIndex, index);

        if (found) { // A similar vertex is already in the VBO, use it instead !
            out_indices.append(index);
        }
        else { // If not, it needs to be added in the output data.
            unique_vertices++;
            out_vertices.append(in_vertices[i]);
            out_uvs.append(in_uvs[i]);
            out_normals.append(in_normals[i]);
            unsigned short newindex = (unsigned short)out_vertices.size() - 1;
            out_indices.append(newindex);
            VertexToOutIndex[packed] = newindex;
        }
    }
    qDebug() << "unique vertices" << unique_vertices;
}

void VertexIndexer::indexVBO_TBN(QVector<QVector3D> &in_vertices
                                 , QVector<QVector2D> &in_uvs
                                 , QVector<QVector3D> &in_normals
                                 , QVector<QVector3D> &in_tangents
                                 , QVector<QVector3D> &in_bitangents
                                 , QVector<unsigned short> &out_indices
                                 , QVector<QVector3D> &out_vertices
                                 , QVector<QVector2D> &out_uvs
                                 , QVector<QVector3D> &out_normals
                                 , QVector<QVector3D> &out_tangents
                                 , QVector<QVector3D> &out_bitangents)
{
    unique_vertices = 0;
    // For each input vertex
    for (int i = 0; i < in_vertices.size(); i++) {

        // Try to find a similar vertex in out_XXXX
        unsigned short index;
        bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i]
                                           , out_vertices, out_uvs, out_normals, index);

        if (found) { // A similar vertex is already in the VBO, use it instead !
            out_indices.append(index);

            // Average the tangents and the bitangents
            out_tangents[index] += in_tangents[i];
            out_bitangents[index] += in_bitangents[i];
        }
        else { // If not, it needs to be added in the output data.
            unique_vertices++;
            out_vertices.append(in_vertices[i]);
            out_uvs.append(in_uvs[i]);
            out_normals.append(in_normals[i]);
            out_tangents.append(in_tangents[i]);
            out_bitangents.append(in_bitangents[i]);
            out_indices.append((unsigned short)out_vertices.size() - 1);
        }
    }
    qDebug() << "unique vertices" << unique_vertices;
}

QTCOMMERCIALDATAVIS3D_END_NAMESPACE