overte/tests-manual/gpu/src/TestFbx.cpp

187 lines
6.7 KiB
C++

//
// Created by Bradley Austin Davis on 2016/05/16
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TestFbx.h"
#include <glm/gtc/matrix_transform.hpp>
#include <QtCore/QFile>
#include <FBXSerializer.h>
struct MyVertex {
vec3 position;
vec2 texCoords;
vec3 normal;
uint32_t color;
static gpu::Stream::FormatPointer getVertexFormat() {
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element TEXTURE_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
gpu::Stream::FormatPointer vertexFormat { std::make_shared<gpu::Stream::Format>() };
vertexFormat->setAttribute(gpu::Stream::POSITION, 0, POSITION_ELEMENT, offsetof(MyVertex, position));
vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, TEXTURE_ELEMENT, offsetof(MyVertex, texCoords));
vertexFormat->setAttribute(gpu::Stream::COLOR, 0, COLOR_ELEMENT, offsetof(MyVertex, color));
vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, NORMAL_ELEMENT, offsetof(MyVertex, normal));
return vertexFormat;
}
};
struct Part {
size_t baseVertex;
size_t baseIndex;
size_t materialId;
};
struct DrawElementsIndirectCommand {
uint count { 0 };
uint instanceCount { 1 };
uint firstIndex { 0 };
uint baseVertex { 0 };
uint baseInstance { 0 };
};
class FileDownloader : public QObject {
Q_OBJECT
public:
explicit FileDownloader(QUrl imageUrl, QObject *parent = 0) : QObject(parent) {
connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*)));
QNetworkRequest request(imageUrl);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
m_WebCtrl.get(request);
}
virtual ~FileDownloader() {}
const QByteArray& downloadedData() const {
return m_DownloadedData;
}
signals:
void downloaded();
private slots:
void fileDownloaded(QNetworkReply* pReply) {
m_DownloadedData = pReply->readAll();
pReply->deleteLater();
emit downloaded();
}
private:
QNetworkAccessManager m_WebCtrl;
QByteArray m_DownloadedData;
};
static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/models/tardis/console.fbx");
static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -1.5f, 0)) * glm::scale(mat4(), vec3(0.01f));
//static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/simple/SimpleMilitary/Models/Vehicles/tank_02_c.fbx");
//static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -0.5f, 0)) * glm::scale(mat4(), vec3(0.1f));
TestFbx::TestFbx(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {
FileDownloader* downloader = new FileDownloader(TEST_ASSET, qApp);
QObject::connect(downloader, &FileDownloader::downloaded, [this, downloader] {
parseFbx(downloader->downloadedData());
});
}
bool TestFbx::isReady() const {
return _partCount != 0;
}
void TestFbx::parseFbx(const QByteArray& fbxData) {
QVariantHash mapping;
HFMModel::Pointer hfmModel = FBXSerializer().read(fbxData, mapping);
size_t totalVertexCount = 0;
size_t totalIndexCount = 0;
size_t totalPartCount = 0;
size_t highestIndex = 0;
for (const auto& mesh : hfmModel->meshes) {
size_t vertexCount = mesh.vertices.size();
totalVertexCount += mesh.vertices.size();
highestIndex = std::max(highestIndex, vertexCount);
totalPartCount += mesh.parts.size();
for (const auto& part : mesh.parts) {
totalIndexCount += part.quadTrianglesIndices.size();
totalIndexCount += part.triangleIndices.size();
}
}
size_t baseVertex = 0;
std::vector<MyVertex> vertices;
vertices.reserve(totalVertexCount);
std::vector<uint16_t> indices;
indices.reserve(totalIndexCount);
std::vector<DrawElementsIndirectCommand> parts;
parts.reserve(totalPartCount);
_partCount = totalPartCount;
for (const auto& mesh : hfmModel->meshes) {
baseVertex = vertices.size();
vec3 color;
for (const auto& part : mesh.parts) {
DrawElementsIndirectCommand partIndirect;
partIndirect.baseVertex = (uint)baseVertex;
partIndirect.firstIndex = (uint)indices.size();
partIndirect.baseInstance = (uint)parts.size();
_partTransforms.push_back(mesh.modelTransform);
auto material = hfmModel->materials[part.materialID];
color = material.diffuseColor;
for (auto index : part.quadTrianglesIndices) {
indices.push_back(index);
}
for (auto index : part.triangleIndices) {
indices.push_back(index);
}
size_t triangles = (indices.size() - partIndirect.firstIndex);
Q_ASSERT(0 == (triangles % 3));
//triangles /= 3;
partIndirect.count = (uint)triangles;
parts.push_back(partIndirect);
}
size_t vertexCount = mesh.vertices.size();
for (size_t i = 0; i < vertexCount; ++i) {
MyVertex vertex;
vertex.position = mesh.vertices[(int)i];
vec3 n = mesh.normals[(int)i];
vertex.normal = n;
vertex.texCoords = mesh.texCoords[(int)i];
vertex.color = toCompactColor(vec4(color, 1));
vertices.push_back(vertex);
}
}
_vertexBuffer->append(vertices);
_indexBuffer->append(indices);
_indirectBuffer->append(parts);
}
void TestFbx::renderTest(size_t testId, RenderArgs* args) {
gpu::Batch& batch = *(args->_batch);
//pipeline->pipeline
if (_partCount) {
for (size_t i = 0; i < _partCount; ++i) {
batch.setModelTransform(TEST_ASSET_TRANSFORM * _partTransforms[i]);
batch.setupNamedCalls(__FUNCTION__, [this](gpu::Batch& batch, gpu::Batch::NamedBatchData&) {
RenderArgs args; args._batch = &batch;
_shapePlumber->pickPipeline(&args, render::ShapeKey());
batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(MyVertex));
batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0);
batch.setInputFormat(MyVertex::getVertexFormat());
batch.setIndirectBuffer(_indirectBuffer, 0);
batch.multiDrawIndexedIndirect((uint)_partCount, gpu::TRIANGLES);
});
}
}
}
#include "TestFbx.moc"