Showing the changes to libraries/script-engine/src/ModelScriptingInterface.cpp (1 of 36 files). Show all
Unified · Split
| @@ -0,0 +1,251 @@ | ||
| 1 | +// | |
| 2 | +// ModelScriptingInterface.cpp | |
| 3 | +// libraries/script-engine/src | |
| 4 | +// | |
| 5 | +// Created by Seth Alves on 2017-1-27. | |
| 6 | +// Copyright 2017 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | + | |
| 12 | +#include "ModelScriptingInterface.h" | |
| 13 | +#include <QScriptEngine> | |
| 14 | +#include <QScriptValueIterator> | |
| 15 | +#include <QtScript/QScriptValue> | |
| 16 | +#include <model-networking/SimpleMeshProxy.h> | |
| 17 | +#include "ScriptEngine.h" | |
| 18 | +#include "ScriptEngineLogging.h" | |
| 19 | +#include "OBJWriter.h" | |
| 20 | + | |
| 21 | +ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { | |
| 22 | + _modelScriptEngine = qobject_cast<QScriptEngine*>(parent); | |
| 23 | + | |
| 24 | + qScriptRegisterSequenceMetaType<QList<MeshProxy*>>(_modelScriptEngine); | |
| 25 | + qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue); | |
| 26 | + qScriptRegisterMetaType(_modelScriptEngine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue); | |
| 27 | +} | |
| 28 | + | |
| 29 | +QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { | |
| 30 | + QList<MeshPointer> meshes; | |
| 31 | + foreach (const MeshProxy* meshProxy, in) { | |
| 32 | + meshes.append(meshProxy->getMeshPointer()); | |
| 33 | + } | |
| 34 | + | |
| 35 | + return writeOBJToString(meshes); | |
| 36 | +} | |
| 37 | + | |
| 38 | +QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { | |
| 39 | + // figure out the size of the resulting mesh | |
| 40 | + size_t totalVertexCount { 0 }; | |
| 41 | + size_t totalColorCount { 0 }; | |
| 42 | + size_t totalNormalCount { 0 }; | |
| 43 | + size_t totalIndexCount { 0 }; | |
| 44 | + foreach (const MeshProxy* meshProxy, in) { | |
| 45 | + MeshPointer mesh = meshProxy->getMeshPointer(); | |
| 46 | + totalVertexCount += mesh->getNumVertices(); | |
| 47 | + | |
| 48 | + int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h | |
| 49 | + const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(attributeTypeColor); | |
| 50 | + gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements(); | |
| 51 | + totalColorCount += numColors; | |
| 52 | + | |
| 53 | + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h | |
| 54 | + const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); | |
| 55 | + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); | |
| 56 | + totalNormalCount += numNormals; | |
| 57 | + | |
| 58 | + totalIndexCount += mesh->getNumIndices(); | |
| 59 | + } | |
| 60 | + | |
| 61 | + // alloc the resulting mesh | |
| 62 | + gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3); | |
| 63 | + std::unique_ptr<unsigned char> combinedVertexData{ new unsigned char[combinedVertexSize] }; | |
| 64 | + unsigned char* combinedVertexDataCursor = combinedVertexData.get(); | |
| 65 | + | |
| 66 | + gpu::Resource::Size combinedColorSize = totalColorCount * sizeof(glm::vec3); | |
| 67 | + std::unique_ptr<unsigned char> combinedColorData{ new unsigned char[combinedColorSize] }; | |
| 68 | + unsigned char* combinedColorDataCursor = combinedColorData.get(); | |
| 69 | + | |
| 70 | + gpu::Resource::Size combinedNormalSize = totalNormalCount * sizeof(glm::vec3); | |
| 71 | + std::unique_ptr<unsigned char> combinedNormalData{ new unsigned char[combinedNormalSize] }; | |
| 72 | + unsigned char* combinedNormalDataCursor = combinedNormalData.get(); | |
| 73 | + | |
| 74 | + gpu::Resource::Size combinedIndexSize = totalIndexCount * sizeof(uint32_t); | |
| 75 | + std::unique_ptr<unsigned char> combinedIndexData{ new unsigned char[combinedIndexSize] }; | |
| 76 | + unsigned char* combinedIndexDataCursor = combinedIndexData.get(); | |
| 77 | + | |
| 78 | + uint32_t indexStartOffset { 0 }; | |
| 79 | + | |
| 80 | + foreach (const MeshProxy* meshProxy, in) { | |
| 81 | + MeshPointer mesh = meshProxy->getMeshPointer(); | |
| 82 | + mesh->forEach( | |
| 83 | + [&](glm::vec3 position){ | |
| 84 | + memcpy(combinedVertexDataCursor, &position, sizeof(position)); | |
| 85 | + combinedVertexDataCursor += sizeof(position); | |
| 86 | + }, | |
| 87 | + [&](glm::vec3 color){ | |
| 88 | + memcpy(combinedColorDataCursor, &color, sizeof(color)); | |
| 89 | + combinedColorDataCursor += sizeof(color); | |
| 90 | + }, | |
| 91 | + [&](glm::vec3 normal){ | |
| 92 | + memcpy(combinedNormalDataCursor, &normal, sizeof(normal)); | |
| 93 | + combinedNormalDataCursor += sizeof(normal); | |
| 94 | + }, | |
| 95 | + [&](uint32_t index){ | |
| 96 | + index += indexStartOffset; | |
| 97 | + memcpy(combinedIndexDataCursor, &index, sizeof(index)); | |
| 98 | + combinedIndexDataCursor += sizeof(index); | |
| 99 | + }); | |
| 100 | + | |
| 101 | + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); | |
| 102 | + indexStartOffset += numVertices; | |
| 103 | + } | |
| 104 | + | |
| 105 | + graphics::MeshPointer result(new graphics::Mesh()); | |
| 106 | + | |
| 107 | + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); | |
| 108 | + gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData.get()); | |
| 109 | + gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer); | |
| 110 | + gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement); | |
| 111 | + result->setVertexBuffer(combinedVertexBufferView); | |
| 112 | + | |
| 113 | + int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h | |
| 114 | + gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); | |
| 115 | + gpu::Buffer* combinedColorsBuffer = new gpu::Buffer(combinedColorSize, combinedColorData.get()); | |
| 116 | + gpu::BufferPointer combinedColorsBufferPointer(combinedColorsBuffer); | |
| 117 | + gpu::BufferView combinedColorsBufferView(combinedColorsBufferPointer, colorElement); | |
| 118 | + result->addAttribute(attributeTypeColor, combinedColorsBufferView); | |
| 119 | + | |
| 120 | + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h | |
| 121 | + gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); | |
| 122 | + gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData.get()); | |
| 123 | + gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer); | |
| 124 | + gpu::BufferView combinedNormalsBufferView(combinedNormalsBufferPointer, normalElement); | |
| 125 | + result->addAttribute(attributeTypeNormal, combinedNormalsBufferView); | |
| 126 | + | |
| 127 | + gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); | |
| 128 | + gpu::Buffer* combinedIndexesBuffer = new gpu::Buffer(combinedIndexSize, combinedIndexData.get()); | |
| 129 | + gpu::BufferPointer combinedIndexesBufferPointer(combinedIndexesBuffer); | |
| 130 | + gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement); | |
| 131 | + result->setIndexBuffer(combinedIndexesBufferView); | |
| 132 | + | |
| 133 | + std::vector<graphics::Mesh::Part> parts; | |
| 134 | + parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex | |
| 135 | + (graphics::Index)result->getNumIndices(), // numIndices | |
| 136 | + (graphics::Index)0, // baseVertex | |
| 137 | + graphics::Mesh::TRIANGLES)); // topology | |
| 138 | + result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), | |
| 139 | + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); | |
| 140 | + | |
| 141 | + | |
| 142 | + MeshProxy* resultProxy = new SimpleMeshProxy(result); | |
| 143 | + return meshToScriptValue(_modelScriptEngine, resultProxy); | |
| 144 | +} | |
| 145 | + | |
| 146 | +QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { | |
| 147 | + if (!meshProxy) { | |
| 148 | + return QScriptValue(false); | |
| 149 | + } | |
| 150 | + MeshPointer mesh = meshProxy->getMeshPointer(); | |
| 151 | + if (!mesh) { | |
| 152 | + return QScriptValue(false); | |
| 153 | + } | |
| 154 | + | |
| 155 | + const auto inverseTransposeTransform = glm::inverse(glm::transpose(transform)); | |
| 156 | + graphics::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, | |
| 157 | + [&](glm::vec3 color){ return color; }, | |
| 158 | + [&](glm::vec3 normal){ return glm::vec3(inverseTransposeTransform * glm::vec4(normal, 0.0f)); }, | |
| 159 | + [&](uint32_t index){ return index; }); | |
| 160 | + MeshProxy* resultProxy = new SimpleMeshProxy(result); | |
| 161 | + return meshToScriptValue(_modelScriptEngine, resultProxy); | |
| 162 | +} | |
| 163 | + | |
| 164 | +QScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) { | |
| 165 | + if (!meshProxy) { | |
| 166 | + return QScriptValue(false); | |
| 167 | + } | |
| 168 | + MeshPointer mesh = meshProxy->getMeshPointer(); | |
| 169 | + if (!mesh) { | |
| 170 | + return QScriptValue(false); | |
| 171 | + } | |
| 172 | + | |
| 173 | + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); | |
| 174 | + | |
| 175 | + return numVertices; | |
| 176 | +} | |
| 177 | + | |
| 178 | +QScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) { | |
| 179 | + if (!meshProxy) { | |
| 180 | + return QScriptValue(false); | |
| 181 | + } | |
| 182 | + MeshPointer mesh = meshProxy->getMeshPointer(); | |
| 183 | + if (!mesh) { | |
| 184 | + return QScriptValue(false); | |
| 185 | + } | |
| 186 | + | |
| 187 | + const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); | |
| 188 | + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); | |
| 189 | + | |
| 190 | + if (vertexIndex < 0 || vertexIndex >= numVertices) { | |
| 191 | + return QScriptValue(false); | |
| 192 | + } | |
| 193 | + | |
| 194 | + glm::vec3 pos = vertexBufferView.get<glm::vec3>(vertexIndex); | |
| 195 | + return vec3toScriptValue(_modelScriptEngine, pos); | |
| 196 | +} | |
| 197 | + | |
| 198 | + | |
| 199 | +QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices, | |
| 200 | + const QVector<glm::vec3>& normals, | |
| 201 | + const QVector<MeshFace>& faces) { | |
| 202 | + graphics::MeshPointer mesh(new graphics::Mesh()); | |
| 203 | + | |
| 204 | + // vertices | |
| 205 | + auto vertexBuffer = std::make_shared<gpu::Buffer>(vertices.size() * sizeof(glm::vec3), (gpu::Byte*)vertices.data()); | |
| 206 | + auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); | |
| 207 | + gpu::BufferView vertexBufferView(vertexBufferPtr, 0, vertexBufferPtr->getSize(), | |
| 208 | + sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); | |
| 209 | + mesh->setVertexBuffer(vertexBufferView); | |
| 210 | + | |
| 211 | + if (vertices.size() == normals.size()) { | |
| 212 | + // normals | |
| 213 | + auto normalBuffer = std::make_shared<gpu::Buffer>(normals.size() * sizeof(glm::vec3), (gpu::Byte*)normals.data()); | |
| 214 | + auto normalBufferPtr = gpu::BufferPointer(normalBuffer); | |
| 215 | + gpu::BufferView normalBufferView(normalBufferPtr, 0, normalBufferPtr->getSize(), | |
| 216 | + sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); | |
| 217 | + mesh->addAttribute(gpu::Stream::NORMAL, normalBufferView); | |
| 218 | + } else { | |
| 219 | + qCDebug(scriptengine) << "ModelScriptingInterface::newMesh normals must be same length as vertices"; | |
| 220 | + } | |
| 221 | + | |
| 222 | + // indices (faces) | |
| 223 | + int VERTICES_PER_TRIANGLE = 3; | |
| 224 | + int indexBufferSize = faces.size() * sizeof(uint32_t) * VERTICES_PER_TRIANGLE; | |
| 225 | + unsigned char* indexData = new unsigned char[indexBufferSize]; | |
| 226 | + unsigned char* indexDataCursor = indexData; | |
| 227 | + foreach(const MeshFace& meshFace, faces) { | |
| 228 | + for (int i = 0; i < VERTICES_PER_TRIANGLE; i++) { | |
| 229 | + memcpy(indexDataCursor, &meshFace.vertexIndices[i], sizeof(uint32_t)); | |
| 230 | + indexDataCursor += sizeof(uint32_t); | |
| 231 | + } | |
| 232 | + } | |
| 233 | + auto indexBuffer = std::make_shared<gpu::Buffer>(indexBufferSize, (gpu::Byte*)indexData); | |
| 234 | + auto indexBufferPtr = gpu::BufferPointer(indexBuffer); | |
| 235 | + gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)); | |
| 236 | + mesh->setIndexBuffer(indexBufferView); | |
| 237 | + | |
| 238 | + // parts | |
| 239 | + std::vector<graphics::Mesh::Part> parts; | |
| 240 | + parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex | |
| 241 | + (graphics::Index)faces.size() * 3, // numIndices | |
| 242 | + (graphics::Index)0, // baseVertex | |
| 243 | + graphics::Mesh::TRIANGLES)); // topology | |
| 244 | + mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), | |
| 245 | + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + MeshProxy* meshProxy = new SimpleMeshProxy(mesh); | |
| 250 | + return meshToScriptValue(_modelScriptEngine, meshProxy); | |
| 251 | +} | |