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 | } | ||