1162 lines
36 KiB
C++
1162 lines
36 KiB
C++
//
|
|
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
|
|
//
|
|
#include "scene/dvu_load_gltf.h"
|
|
#include "camera/dvu_default_camera.h"
|
|
#include "scene/dvc_scene.h"
|
|
#include "scene/dvc_scene_node.h"
|
|
#include "scene/component/dvc_mesh_component.h"
|
|
#include "scene/component/dvc_camera_component.h"
|
|
#include "scene/component/dvc_light_component.h"
|
|
#include "device/dvc_device.h"
|
|
#include "device/dvc_buffer_accessor.h"
|
|
#include "asset/dvc_mesh.h"
|
|
#include "asset/dvc_image.h"
|
|
#include "asset/dvc_texture.h"
|
|
#include "asset/dvc_material.h"
|
|
|
|
#include "math/dvc_vector3.h"
|
|
#include "math/dvc_vector4.h"
|
|
|
|
#include "buffer/dvu_dump_buffer.h"
|
|
|
|
#include "standard/dvu_standard_material.h"
|
|
|
|
#include <tiny_gltf.h>
|
|
|
|
#include <string>
|
|
#include <filesystem>
|
|
|
|
DV_UTILS_BEGIN_NAMESPACE
|
|
|
|
//from TINYGLTF_COMPONENT_TYPE_*** to CT_***
|
|
davinci::ComponentType _getComponentTypeFromGltf(int gltfComponentType)
|
|
{
|
|
switch (gltfComponentType)
|
|
{
|
|
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
|
return davinci::CT_Int8;
|
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
|
return davinci::CT_Uint8;
|
|
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
|
return davinci::CT_Int16;
|
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
|
return davinci::CT_Uint16;
|
|
case TINYGLTF_COMPONENT_TYPE_INT:
|
|
return davinci::CT_Int32;
|
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
|
return davinci::CT_Uint32;
|
|
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
|
return davinci::CT_Float32;
|
|
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
|
return davinci::CT_Float64;
|
|
default:
|
|
return davinci::CT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
//from TINYGLTF_TYPE_*** to DT_***
|
|
davinci::DataType _getDataTypeFromGltf(int gltfDataType)
|
|
{
|
|
switch (gltfDataType)
|
|
{
|
|
case TINYGLTF_TYPE_SCALAR:
|
|
return davinci::DT_Scalar;
|
|
case TINYGLTF_TYPE_VEC2:
|
|
return davinci::DT_Vec2;
|
|
case TINYGLTF_TYPE_VEC3:
|
|
return davinci::DT_Vec3;
|
|
case TINYGLTF_TYPE_VEC4:
|
|
return davinci::DT_Vec4;
|
|
case TINYGLTF_TYPE_MAT2:
|
|
return davinci::DT_Matrix2;
|
|
case TINYGLTF_TYPE_MAT3:
|
|
return davinci::DT_Matrix3;
|
|
case TINYGLTF_TYPE_MAT4:
|
|
return davinci::DT_Matrix4;
|
|
default:
|
|
return davinci::DT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
//from TINYGLTF_MODE_*** to PT_***
|
|
davinci::PrimitiveType _getPrimitiveTypeFromGltf(int gltfModelType)
|
|
{
|
|
switch (gltfModelType)
|
|
{
|
|
case TINYGLTF_MODE_POINTS:
|
|
return davinci::PT_POINT_LIST;
|
|
case TINYGLTF_MODE_LINE:
|
|
return davinci::PT_LINE_LIST;
|
|
case TINYGLTF_MODE_LINE_LOOP:
|
|
return davinci::PT_LINE_LOOP;
|
|
case TINYGLTF_MODE_LINE_STRIP:
|
|
return davinci::PT_LINE_STRIP;
|
|
case TINYGLTF_MODE_TRIANGLES:
|
|
return davinci::PT_TRIANGLE_LIST;
|
|
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
|
return davinci::PT_TRIANGLE_STRIP;
|
|
case TINYGLTF_MODE_TRIANGLE_FAN:
|
|
return davinci::PT_TRIANGLE_FAN;
|
|
default:
|
|
return davinci::PT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
davinci::PixelFormat _getPixelFormatFromGltf(int32_t gltfComponent, int32_t gltfPixelType)
|
|
{
|
|
if (gltfPixelType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
|
|
{
|
|
if (gltfComponent == 1) return davinci::PF_UINT8_ALPHA;
|
|
else if (gltfComponent == 3) return davinci::PF_UINT8_RGB;
|
|
else if (gltfComponent == 4) return davinci::PF_UINT8_RGBA;
|
|
else return davinci::PF_UNKNOWN;
|
|
}
|
|
else if (gltfPixelType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
|
|
{
|
|
if (gltfComponent == 1) return davinci::PF_UINT16_ALPHA;
|
|
else if (gltfComponent == 3) return davinci::PF_UINT16_RGB;
|
|
else if (gltfComponent == 4) return davinci::PF_UINT16_RGBA;
|
|
else return davinci::PF_UNKNOWN;
|
|
}
|
|
else return davinci::PF_UNKNOWN;
|
|
}
|
|
|
|
//from "POSITION/NORMAL/..." to VET_***
|
|
davinci::VertexElementType _getElementTypeFromGltf(const std::string& gltfElementType)
|
|
{
|
|
#define IS_MATCH_RANGE_TYPE(Prefix, PrefixLength, FirstValue, LastValue) \
|
|
else if (gltfElementType.length() == PrefixLength + 1 && gltfElementType.rfind(Prefix, 0) == 0) \
|
|
{ \
|
|
int32_t index = gltfElementType[PrefixLength] - '0'; \
|
|
if (index<0 || index>(LastValue - FirstValue)) \
|
|
{ \
|
|
return davinci::VET_UNKNOWN; \
|
|
} \
|
|
return static_cast<davinci::VertexElementType>(static_cast<int32_t>(FirstValue) + index); \
|
|
}
|
|
|
|
if (gltfElementType == "POSITION")
|
|
{
|
|
return davinci::VET_POSITION_MODEL;
|
|
}
|
|
else if(gltfElementType == "NORMAL")
|
|
{
|
|
return davinci::VET_NORMAL;
|
|
}
|
|
else if (gltfElementType == "TANGENT")
|
|
{
|
|
return davinci::VET_TANGENT;
|
|
}
|
|
else if (gltfElementType == "BINORMAL")
|
|
{
|
|
return davinci::VET_BINORMAL;
|
|
}
|
|
IS_MATCH_RANGE_TYPE("COLOR_", 6, davinci::VET_COLOR_0, davinci::VET_COLOR_LAST)
|
|
IS_MATCH_RANGE_TYPE("TEXCOORD_", 9, davinci::VET_TEXCOORD_0, davinci::VET_TEXCOORD_LAST)
|
|
IS_MATCH_RANGE_TYPE("JOINTS_", 7, davinci::VET_JOINTS_0, davinci::VET_JOINTS_LAST)
|
|
IS_MATCH_RANGE_TYPE("WEIGHTS_", 8, davinci::VET_WEIGHTS_0, davinci::VET_WEIGHTS_LAST)
|
|
|
|
return davinci::VET_UNKNOWN;
|
|
}
|
|
|
|
davinci::DeviceBufferAccessorPtr _createFloat32BufferAccessorFromNormalizedIntegerType(
|
|
davinci::Device& device, davinci::Scene& scene,
|
|
davinci::DeviceBufferAccessorPtr inpuptBufferAccesser)
|
|
{
|
|
size_t elementCounts = inpuptBufferAccesser->getCount();
|
|
davinci::ComponentType inputComponentType = inpuptBufferAccesser->getComponentType();
|
|
if (inputComponentType != davinci::ComponentType::CT_Uint8 &&
|
|
inputComponentType != davinci::ComponentType::CT_Uint16 &&
|
|
inputComponentType != davinci::ComponentType::CT_Uint32)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
davinci::DataType dataType = inpuptBufferAccesser->getDataType();
|
|
size_t bufferSize = elementCounts * davinci::MathUtil::ComponentSize(davinci::ComponentType::CT_Float32) * davinci::MathUtil::DataTypeSize(dataType);
|
|
davinci::DeviceBufferPtr newBuffer = device.newDeviceBuffer(bufferSize);
|
|
|
|
if (dataType == davinci::DataType::DT_Scalar)
|
|
{
|
|
inpuptBufferAccesser->walk([newBuffer, inputComponentType](const uint8_t* ptr, size_t index)
|
|
{
|
|
float32_t* target = (float32_t*)(newBuffer->ptr(index * sizeof(float32_t)));
|
|
if (inputComponentType == davinci::ComponentType::CT_Uint8)
|
|
{
|
|
target[0] = ((const uint8_t*)ptr)[0] / (float32_t)0xFF;
|
|
}
|
|
else if (inputComponentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
target[0] = ((const uint16_t*)ptr)[0] / (float32_t)0xFFFF;
|
|
}
|
|
else
|
|
{
|
|
target[0] = ((const uint32_t*)ptr)[0] / (float32_t)0xFFFFFFFF;
|
|
}
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
else if (dataType == davinci::DataType::DT_Vec2)
|
|
{
|
|
inpuptBufferAccesser->walk(
|
|
[newBuffer, inputComponentType](const uint8_t* ptr, size_t index)
|
|
{
|
|
float32_t* target = (float32_t*)(newBuffer->ptr(index * sizeof(float32_t) * 2));
|
|
if (inputComponentType == davinci::ComponentType::CT_Uint8)
|
|
{
|
|
target[0] = ((const uint8_t*)ptr)[0] / (float32_t)0xFF;
|
|
target[1] = ((const uint8_t*)ptr)[1] / (float32_t)0xFF;
|
|
}
|
|
else if (inputComponentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
target[0] = ((const uint16_t*)ptr)[0] / (float32_t)0xFFFF;
|
|
target[1] = ((const uint16_t*)ptr)[1] / (float32_t)0xFFFF;
|
|
}
|
|
else
|
|
{
|
|
target[0] = ((const uint32_t*)ptr)[0] / (float32_t)0xFFFFFFFF;
|
|
target[1] = ((const uint32_t*)ptr)[1] / (float32_t)0xFFFFFFFF;
|
|
}
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
else if (dataType == davinci::DataType::DT_Vec3)
|
|
{
|
|
inpuptBufferAccesser->walk(
|
|
[newBuffer, inputComponentType](const uint8_t* ptr, size_t index)
|
|
{
|
|
float32_t* target = (float32_t*)(newBuffer->ptr(index * sizeof(float32_t) * 3));
|
|
if (inputComponentType == davinci::ComponentType::CT_Uint8)
|
|
{
|
|
target[0] = ((const uint8_t*)ptr)[0] / (float32_t)0xFF;
|
|
target[1] = ((const uint8_t*)ptr)[1] / (float32_t)0xFF;
|
|
target[2] = ((const uint8_t*)ptr)[2] / (float32_t)0xFF;
|
|
}
|
|
else if (inputComponentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
target[0] = ((const uint16_t*)ptr)[0] / (float32_t)0xFFFF;
|
|
target[1] = ((const uint16_t*)ptr)[1] / (float32_t)0xFFFF;
|
|
target[2] = ((const uint16_t*)ptr)[2] / (float32_t)0xFFFF;
|
|
}
|
|
else
|
|
{
|
|
target[0] = ((const uint32_t*)ptr)[0] / (float32_t)0xFFFFFFFF;
|
|
target[1] = ((const uint32_t*)ptr)[1] / (float32_t)0xFFFFFFFF;
|
|
target[2] = ((const uint32_t*)ptr)[2] / (float32_t)0xFFFFFFFF;
|
|
}
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
else if (dataType == davinci::DataType::DT_Vec4)
|
|
{
|
|
inpuptBufferAccesser->walk(
|
|
[newBuffer, inputComponentType](const uint8_t* ptr, size_t index)
|
|
{
|
|
float32_t* target = (float32_t*)(newBuffer->ptr(index * sizeof(float32_t) * 4));
|
|
if (inputComponentType == davinci::ComponentType::CT_Uint8)
|
|
{
|
|
target[0] = ((const uint8_t*)ptr)[0] / (float32_t)0xFF;
|
|
target[1] = ((const uint8_t*)ptr)[1] / (float32_t)0xFF;
|
|
target[2] = ((const uint8_t*)ptr)[2] / (float32_t)0xFF;
|
|
target[3] = ((const uint8_t*)ptr)[3] / (float32_t)0xFF;
|
|
}
|
|
else if (inputComponentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
target[0] = ((const uint16_t*)ptr)[0] / (float32_t)0xFFFF;
|
|
target[1] = ((const uint16_t*)ptr)[1] / (float32_t)0xFFFF;
|
|
target[2] = ((const uint16_t*)ptr)[2] / (float32_t)0xFFFF;
|
|
target[3] = ((const uint16_t*)ptr)[3] / (float32_t)0xFFFF;
|
|
}
|
|
else
|
|
{
|
|
target[0] = ((const uint32_t*)ptr)[0] / (float32_t)0xFFFFFFFF;
|
|
target[1] = ((const uint32_t*)ptr)[1] / (float32_t)0xFFFFFFFF;
|
|
target[2] = ((const uint32_t*)ptr)[2] / (float32_t)0xFFFFFFFF;
|
|
target[3] = ((const uint32_t*)ptr)[3] / (float32_t)0xFFFFFFFF;
|
|
}
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
davinci::DeviceBufferViewPtr newBufferViewer = device.newDeviceBufferView(newBuffer, 0, bufferSize, 0);
|
|
return device.newDeviceBufferAccessor(newBufferViewer, 0, elementCounts, davinci::ComponentType::CT_Float32, dataType);
|
|
}
|
|
|
|
davinci::DeviceBufferAccessorPtr _createSupportedPrimitiveAttributeBufferAccessor(
|
|
davinci::Device& device, davinci::Scene& scene,
|
|
davinci::VertexElementType vetType, davinci::DeviceBufferAccessorPtr inpuptBufferAccesser)
|
|
{
|
|
if (!inpuptBufferAccesser) return nullptr;
|
|
davinci::ComponentType componentType = inpuptBufferAccesser->getComponentType();
|
|
davinci::DataType dataType = inpuptBufferAccesser->getDataType();
|
|
|
|
switch (vetType)
|
|
{
|
|
case davinci::VET_POSITION_MODEL:
|
|
case davinci::VET_NORMAL:
|
|
case davinci::VET_BINORMAL:
|
|
if (componentType == davinci::ComponentType::CT_Float32 && dataType == davinci::DataType::DT_Vec3)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
break;
|
|
|
|
case davinci::VET_TANGENT:
|
|
if (componentType == davinci::ComponentType::CT_Float32 && dataType == davinci::DataType::DT_Vec4)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
break;
|
|
|
|
case davinci::VET_TEXCOORD_0:
|
|
case davinci::VET_TEXCOORD_1:
|
|
case davinci::VET_TEXCOORD_2:
|
|
case davinci::VET_TEXCOORD_3:
|
|
case davinci::VET_TEXCOORD_4:
|
|
case davinci::VET_TEXCOORD_5:
|
|
case davinci::VET_TEXCOORD_6:
|
|
case davinci::VET_TEXCOORD_7:
|
|
if (dataType == davinci::DataType::DT_Vec2)
|
|
{
|
|
if (componentType == davinci::ComponentType::CT_Float32)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
else if (componentType == davinci::ComponentType::CT_Uint8 || componentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
return _createFloat32BufferAccessorFromNormalizedIntegerType(device, scene, inpuptBufferAccesser);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case davinci::VET_COLOR_0:
|
|
case davinci::VET_COLOR_1:
|
|
case davinci::VET_COLOR_2:
|
|
case davinci::VET_COLOR_3:
|
|
case davinci::VET_COLOR_4:
|
|
case davinci::VET_COLOR_5:
|
|
case davinci::VET_COLOR_6:
|
|
case davinci::VET_COLOR_7:
|
|
if (dataType == davinci::DataType::DT_Vec3 || dataType == davinci::DataType::DT_Vec4)
|
|
{
|
|
if (componentType == davinci::ComponentType::CT_Float32)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
else if (componentType == davinci::ComponentType::CT_Uint8 || componentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
return _createFloat32BufferAccessorFromNormalizedIntegerType(device, scene, inpuptBufferAccesser);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case davinci::VET_JOINTS_0:
|
|
case davinci::VET_JOINTS_1:
|
|
case davinci::VET_JOINTS_2:
|
|
case davinci::VET_JOINTS_3:
|
|
case davinci::VET_JOINTS_4:
|
|
case davinci::VET_JOINTS_5:
|
|
case davinci::VET_JOINTS_6:
|
|
case davinci::VET_JOINTS_7:
|
|
if (dataType == davinci::DataType::DT_Vec4)
|
|
{
|
|
if (componentType == davinci::ComponentType::CT_Uint8 || componentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case davinci::VET_WEIGHTS_0:
|
|
case davinci::VET_WEIGHTS_1:
|
|
case davinci::VET_WEIGHTS_2:
|
|
case davinci::VET_WEIGHTS_3:
|
|
case davinci::VET_WEIGHTS_4:
|
|
case davinci::VET_WEIGHTS_5:
|
|
case davinci::VET_WEIGHTS_6:
|
|
case davinci::VET_WEIGHTS_7:
|
|
if (dataType == davinci::DataType::DT_Vec4)
|
|
{
|
|
if (componentType == davinci::ComponentType::CT_Float32)
|
|
{
|
|
return inpuptBufferAccesser;
|
|
}
|
|
else if (componentType == davinci::ComponentType::CT_Uint8 || componentType == davinci::ComponentType::CT_Uint16)
|
|
{
|
|
return _createFloat32BufferAccessorFromNormalizedIntegerType(device, scene, inpuptBufferAccesser);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool _isSupportedIndicesType(const davinci::DeviceBufferAccessorConstPtr accesserBuffer)
|
|
{
|
|
if (!accesserBuffer) return false;
|
|
davinci::ComponentType componentType = accesserBuffer->getComponentType();
|
|
davinci::DataType dataType = accesserBuffer->getDataType();
|
|
|
|
return componentType == davinci::ComponentType::CT_Uint16 && dataType == davinci::DataType::DT_Scalar;
|
|
}
|
|
|
|
bool _loadDeviceBuffer(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i = 0; i < gltfModel.buffers.size(); i++)
|
|
{
|
|
tinygltf::Buffer& gltfBuffer = gltfModel.buffers[i];
|
|
|
|
davinci::DeviceBufferPtr deviceBufferPtr = device.newDeviceBuffer(gltfBuffer.data.size());
|
|
|
|
//fill data
|
|
memcpy(deviceBufferPtr->ptr(0), gltfBuffer.data.data(), gltfBuffer.data.size());
|
|
|
|
//set davinci id
|
|
gltfBuffer.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)deviceBufferPtr->getID())));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool _loadBufferView(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i = 0; i < gltfModel.bufferViews.size(); i++)
|
|
{
|
|
tinygltf::BufferView& gltfBufferView = gltfModel.bufferViews[i];
|
|
tinygltf::Buffer& gltfBuffer = gltfModel.buffers[gltfBufferView.buffer];
|
|
int32_t bufferID = gltfBuffer.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
|
|
davinci::DeviceBufferConstPtr deviceBufferPtr = device.getDeviceBuffer(bufferID);
|
|
if (deviceBufferPtr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
davinci::DeviceBufferViewPtr bufferViewPtr = device.newDeviceBufferView(
|
|
deviceBufferPtr, gltfBufferView.byteOffset, gltfBufferView.byteLength, gltfBufferView.byteStride);
|
|
gltfBufferView.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)bufferViewPtr->getID())));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool _loadBufferAccessor(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i = 0; i < gltfModel.accessors.size(); i++)
|
|
{
|
|
tinygltf::Accessor& gltfAccessor = gltfModel.accessors[i];
|
|
tinygltf::BufferView& gltfBufferView = gltfModel.bufferViews[gltfAccessor.bufferView];
|
|
int32_t bufferViewID = gltfBufferView.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
|
|
davinci::DeviceBufferViewPtr deviceBufferView = device.getDeviceBufferView(bufferViewID);
|
|
if (deviceBufferView==nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
davinci::ComponentType componentType = _getComponentTypeFromGltf(gltfAccessor.componentType);
|
|
if (componentType == davinci::CT_UNKNOWN)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
davinci::DataType dataType = _getDataTypeFromGltf(gltfAccessor.type);
|
|
if (dataType == davinci::DT_UNKNOWN)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
davinci::DeviceBufferAccessorPtr bufferAccessor = device.newDeviceBufferAccessor(
|
|
deviceBufferView, gltfAccessor.byteOffset, gltfAccessor.count, componentType, dataType);
|
|
gltfAccessor.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)bufferAccessor->getID())));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool _loadMesh(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i=0; i<gltfModel.meshes.size(); i++)
|
|
{
|
|
tinygltf::Mesh& gltfMesh = gltfModel.meshes[i];
|
|
|
|
davinci::MeshPtr mesh = device.newMeshAsset(gltfMesh.name);
|
|
gltfMesh.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)mesh->getID())));
|
|
|
|
for (size_t j=0; j<gltfMesh.primitives.size(); j++)
|
|
{
|
|
const tinygltf::Primitive& gltfPrimitive = gltfMesh.primitives[j];
|
|
|
|
davinci::Mesh::PrimitivePtr primitive = mesh->newPrimitive();
|
|
primitive->type = _getPrimitiveTypeFromGltf(gltfPrimitive.mode);
|
|
|
|
//apply attributes
|
|
std::map<std::string, int>::const_iterator it(gltfPrimitive.attributes.begin());
|
|
std::map<std::string, int>::const_iterator itEnd(gltfPrimitive.attributes.end());
|
|
for (; it != itEnd; it++)
|
|
{
|
|
davinci::VertexElementType vetype = _getElementTypeFromGltf(it->first);
|
|
int32_t gltfAccessIndex = it->second;
|
|
if (gltfAccessIndex < 0 || gltfAccessIndex >= gltfModel.accessors.size())
|
|
{
|
|
return false;
|
|
}
|
|
tinygltf::Accessor& gltfAccessor = gltfModel.accessors[gltfAccessIndex];
|
|
int32_t accessorID = gltfAccessor.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
|
|
davinci::DeviceBufferAccessorPtr deviceBufferAccessor = device.getDeviceBufferAccessor(accessorID);
|
|
if (deviceBufferAccessor ==nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//convert to supported primitive buffer(float32)
|
|
deviceBufferAccessor = _createSupportedPrimitiveAttributeBufferAccessor(device, scene, vetype, deviceBufferAccessor);
|
|
if (deviceBufferAccessor == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
primitive->attributes.insert(std::make_pair(vetype, deviceBufferAccessor));
|
|
}
|
|
|
|
//apply indices
|
|
if (gltfPrimitive.indices < 0 || gltfPrimitive.indices >= gltfModel.accessors.size())
|
|
{
|
|
return false;
|
|
}
|
|
tinygltf::Accessor& gltfIndicesAccessor = gltfModel.accessors[gltfPrimitive.indices];
|
|
int32_t accessorID = gltfIndicesAccessor.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
davinci::DeviceBufferAccessorPtr indicesBufferAccessor = device.getDeviceBufferAccessor(accessorID);
|
|
if (indicesBufferAccessor == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
bool isSupportedType = _isSupportedIndicesType(indicesBufferAccessor);
|
|
if (!isSupportedType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
primitive->indices = indicesBufferAccessor;
|
|
|
|
//apply material
|
|
if (gltfPrimitive.material >= 0 && gltfPrimitive.material < gltfModel.materials.size())
|
|
{
|
|
tinygltf::Material& gltfMaterial = gltfModel.materials[gltfPrimitive.material];
|
|
int32_t materialID = gltfMaterial.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
davinci::MaterialPtr materialPtr = device.getMaterial(materialID);
|
|
if (materialPtr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
primitive->material = materialPtr;
|
|
}
|
|
else
|
|
{
|
|
davinci::MaterialPtr materialPtr = create_standard_material(&device, "classic:phong");
|
|
materialPtr->setParam("u_materialColor", davinci::fVector4::WHITE);
|
|
materialPtr->setParam("u_specularShininess", 32.f);
|
|
materialPtr->setupMaterial();
|
|
|
|
primitive->material = materialPtr;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool _loadTexture(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i = 0; i < gltfModel.images.size(); i++)
|
|
{
|
|
tinygltf::Image& gltfImage = gltfModel.images[i];
|
|
|
|
davinci::ImagePtr imagePtr = device.newImageAsset();
|
|
imagePtr->initWithPixelData(device, gltfImage.width, gltfImage.height,
|
|
_getPixelFormatFromGltf(gltfImage.component, gltfImage.pixel_type), gltfImage.image.data(), gltfImage.image.size());
|
|
|
|
gltfImage.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)imagePtr->getID())));
|
|
}
|
|
|
|
for (size_t i = 0; i < gltfModel.textures.size(); i++)
|
|
{
|
|
tinygltf::Texture& gltfTexture = gltfModel.textures[i];
|
|
if (gltfTexture.source < 0 || gltfTexture.source >= (int)gltfModel.images.size())
|
|
{
|
|
continue;
|
|
}
|
|
tinygltf::Image& gltfImage = gltfModel.images[gltfTexture.source];
|
|
if (gltfImage.width <= 0 || gltfImage.height <= 0 || gltfImage.component <= 0 || gltfImage.component > 4)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int32_t imageID = gltfImage.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
davinci::ImagePtr imagePtr = device.getImage(imageID);
|
|
|
|
davinci::TexturePtr texturePtr = device.newTextureAsset();
|
|
texturePtr->setImage(imagePtr);
|
|
|
|
gltfTexture.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)texturePtr->getID())));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
davinci::TexturePtr _getTexturePtr(tinygltf::Model& gltfModel, davinci::Device& device, int gltfTextureIndex)
|
|
{
|
|
if (gltfTextureIndex < 0 || gltfTextureIndex >= gltfModel.textures.size()) return nullptr;
|
|
tinygltf::Texture& gltfTexture = gltfModel.textures[gltfTextureIndex];
|
|
|
|
int32_t textureID = gltfTexture.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
return device.getTexture(textureID);
|
|
}
|
|
|
|
davinci::fVector4 _getVector4FromDoubleArray(const std::vector<double>& doubleArray)
|
|
{
|
|
if (doubleArray.size() != 4) return davinci::fVector4::ONE;
|
|
return davinci::fVector4((float32_t)doubleArray[0], (float32_t)doubleArray[1], (float32_t)doubleArray[2], (float32_t)doubleArray[3]);
|
|
}
|
|
|
|
davinci::fMatrix3 _getTextureTransform(const tinygltf::ExtensionMap& gltfTextureInfoExternsionMap)
|
|
{
|
|
davinci::fMatrix3 textureTransform = davinci::fMatrix3::IDENTITY;
|
|
|
|
auto transformExternsions = gltfTextureInfoExternsionMap.find("KHR_texture_transform");
|
|
if (transformExternsions != gltfTextureInfoExternsionMap.end())
|
|
{
|
|
davinci::fVector2 scale = davinci::fVector2::ONE;
|
|
const tinygltf::Value& scaleArray = transformExternsions->second.Get("scale");
|
|
if (scaleArray.IsArray() && scaleArray.ArrayLen()>=2 &&
|
|
scaleArray.Get(0).IsNumber() && scaleArray.Get(1).IsNumber())
|
|
{
|
|
scale = davinci::fVector2(
|
|
(float32_t)(scaleArray.Get(0).GetNumberAsDouble()),
|
|
(float32_t)(scaleArray.Get(1).GetNumberAsDouble())
|
|
);
|
|
}
|
|
|
|
float32_t rotate = 0.f;
|
|
const tinygltf::Value& rotationValue = transformExternsions->second.Get("rotation");
|
|
if (rotationValue.IsNumber())
|
|
{
|
|
rotate = (float32_t)rotationValue.GetNumberAsDouble();
|
|
}
|
|
|
|
davinci::fVector2 offset = davinci::fVector2::ZERO;
|
|
const tinygltf::Value& offsetArray = transformExternsions->second.Get("offset");
|
|
if (offsetArray.IsArray() && offsetArray.ArrayLen()>=2 &&
|
|
offsetArray.Get(0).IsNumber() && offsetArray.Get(1).IsNumber())
|
|
{
|
|
offset = davinci::fVector2(
|
|
(float32_t)(offsetArray.Get(0).GetNumberAsDouble()),
|
|
(float32_t)(offsetArray.Get(1).GetNumberAsDouble())
|
|
);
|
|
}
|
|
|
|
textureTransform = davinci::fMatrix3::makeTrans(offset) *
|
|
davinci::fMatrix3::makeRotate(rotate) * davinci::fMatrix3::makeScale(scale);
|
|
}
|
|
|
|
return textureTransform;
|
|
}
|
|
|
|
bool _loadMaterial(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
for (size_t i = 0; i < gltfModel.materials.size(); i++)
|
|
{
|
|
tinygltf::Material& gltfMaterial = gltfModel.materials[i];
|
|
|
|
//create new material
|
|
davinci::MaterialPtr materialPtr = create_standard_material(&device, "pbr:gltf");
|
|
|
|
//apply matellic roughness info
|
|
const tinygltf::PbrMetallicRoughness& gltfPBRMetllicRoughness = gltfMaterial.pbrMetallicRoughness;
|
|
|
|
//base color texture
|
|
const tinygltf::TextureInfo& gltfBaseColorTextureInfo = gltfPBRMetllicRoughness.baseColorTexture;
|
|
davinci::TextureInfo baseColorTextureInfo = davinci::TextureInfo{
|
|
_getTexturePtr(gltfModel, device, gltfBaseColorTextureInfo.index),
|
|
gltfBaseColorTextureInfo.texCoord,
|
|
_getTextureTransform(gltfBaseColorTextureInfo.extensions)
|
|
};
|
|
materialPtr->setParam("u_baseColorTextureInfo", baseColorTextureInfo);
|
|
|
|
//matallic & roughness texture
|
|
const tinygltf::TextureInfo& gltfMetalicRoughnessTextureInfo = gltfPBRMetllicRoughness.metallicRoughnessTexture;
|
|
davinci::TextureInfo metalicRoughnessTextureInfo = davinci::TextureInfo{
|
|
_getTexturePtr(gltfModel, device, gltfMetalicRoughnessTextureInfo.index),
|
|
gltfMetalicRoughnessTextureInfo.texCoord,
|
|
_getTextureTransform(gltfMetalicRoughnessTextureInfo.extensions),
|
|
};
|
|
materialPtr->setParam("u_metalicRoughnessTextureInfo", baseColorTextureInfo);
|
|
materialPtr->setParam("u_metalicFactor", static_cast<float32_t>(gltfPBRMetllicRoughness.metallicFactor));
|
|
materialPtr->setParam("u_roughnessFactor", static_cast<float32_t>(gltfPBRMetllicRoughness.roughnessFactor));
|
|
|
|
//normal texture
|
|
const tinygltf::NormalTextureInfo& gltfNormalTextureInfo = gltfMaterial.normalTexture;
|
|
davinci::TextureInfo normalTextureInfo = davinci::TextureInfo{
|
|
_getTexturePtr(gltfModel, device, gltfNormalTextureInfo.index),
|
|
gltfNormalTextureInfo.texCoord,
|
|
_getTextureTransform(gltfNormalTextureInfo.extensions),
|
|
};
|
|
materialPtr->setParam("u_normalTextureInfo", normalTextureInfo);
|
|
materialPtr->setParam("u_normalTextureScale", static_cast<float32_t>(gltfMaterial.normalTexture.scale));
|
|
|
|
//load shader
|
|
if (!(materialPtr->setupMaterial()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
gltfMaterial.extensions.insert(std::make_pair("DAVINCI_ID", tinygltf::Value((int32_t)materialPtr->getID())));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool _loadLightExternsion(const tinygltf::Model& gltfModel, std::vector<davinci::LightComponent::LightDefine>& lightDefineArray)
|
|
{
|
|
lightDefineArray.clear();
|
|
|
|
//read lights define from externsions
|
|
tinygltf::Value lightsArray;
|
|
auto lightExternsions = gltfModel.extensions.find("KHR_lights_punctual");
|
|
if (lightExternsions == gltfModel.extensions.end())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
lightsArray = lightExternsions->second.Get("lights");
|
|
if (!lightsArray.IsArray())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t lightCounts = lightsArray.ArrayLen();
|
|
for (size_t i = 0; i < lightCounts; i++)
|
|
{
|
|
auto lightObj = lightsArray.Get(i);
|
|
|
|
davinci::LightComponent::LightDefine lightDefine;
|
|
|
|
auto lightType = lightObj.Get("type");
|
|
if (!lightType.IsString()) {
|
|
lightDefineArray.clear();
|
|
return false;
|
|
}
|
|
|
|
std::string lightTypeString = lightType.Get<std::string>();
|
|
if (lightTypeString == "point") {
|
|
lightDefine.type = davinci::LightComponent::LT_Point;
|
|
}
|
|
else if (lightTypeString == "directional") {
|
|
lightDefine.type = davinci::LightComponent::LT_Directional;
|
|
}
|
|
else if (lightTypeString == "spot") {
|
|
lightDefine.type = davinci::LightComponent::LT_Spot;
|
|
}
|
|
else {
|
|
//unknown type?
|
|
lightDefineArray.clear();
|
|
return false;
|
|
}
|
|
|
|
//TODO: read other defines...
|
|
lightDefine.color = davinci::fVector3(1.0, 1.0, 1.0);
|
|
lightDefine.intensity = 1.0f;
|
|
lightDefine.range = -1.0f;
|
|
|
|
lightDefineArray.push_back(lightDefine);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool _loadSceneNodes(tinygltf::Model& gltfModel, davinci::Device& device, davinci::Scene& scene, const std::vector<davinci::LightComponent::LightDefine>& lightsArray)
|
|
{
|
|
std::vector<std::pair<bool, davinci::SceneNodePtr>> sceneNodeArray;
|
|
|
|
//read scene nodes
|
|
for (size_t i = 0; i < gltfModel.nodes.size(); i++)
|
|
{
|
|
const tinygltf::Node& gltfNode = gltfModel.nodes[i];
|
|
|
|
davinci::SceneNodePtr sceneNode = scene.newSceneNode(gltfNode.name);
|
|
davinci::fMatrix4 transform = davinci::fMatrix4::IDENTITY;
|
|
|
|
if (!gltfNode.scale.empty())
|
|
{
|
|
transform =
|
|
davinci::fMatrix4::makeScale(gltfNode.scale[0], gltfNode.scale[1], gltfNode.scale[2]) * transform;
|
|
}
|
|
if (!gltfNode.rotation.empty())
|
|
{
|
|
davinci::fVector4 quaternion(gltfNode.rotation[0], gltfNode.rotation[1], gltfNode.rotation[2], gltfNode.rotation[3]);
|
|
transform = davinci::fMatrix4::makeRotate(quaternion) * transform;
|
|
}
|
|
if (!gltfNode.translation.empty())
|
|
{
|
|
transform = davinci::fMatrix4::makeTrans(gltfNode.translation[0], gltfNode.translation[1], gltfNode.translation[2]) * transform;
|
|
}
|
|
if(!gltfNode.matrix.empty())
|
|
{
|
|
davinci::fMatrix4 matrix(
|
|
gltfNode.matrix[0], gltfNode.matrix[1], gltfNode.matrix[2], gltfNode.matrix[3],
|
|
gltfNode.matrix[4], gltfNode.matrix[5], gltfNode.matrix[6], gltfNode.matrix[7],
|
|
gltfNode.matrix[8], gltfNode.matrix[9], gltfNode.matrix[10], gltfNode.matrix[11],
|
|
gltfNode.matrix[12], gltfNode.matrix[13], gltfNode.matrix[14], gltfNode.matrix[15]);
|
|
transform = matrix.transpose() * transform;
|
|
}
|
|
sceneNode->setTransform(transform);
|
|
|
|
//add mesh component
|
|
if (gltfNode.mesh != -1)
|
|
{
|
|
tinygltf::Mesh& gltfMesh = gltfModel.meshes[gltfNode.mesh];
|
|
int32_t meshID = gltfMesh.extensions["DAVINCI_ID"].GetNumberAsInt();
|
|
|
|
davinci::MeshConstPtr meshPtr = device.getMesh(meshID);
|
|
if (meshPtr)
|
|
{
|
|
davinci::MeshComponentPtr meshComponet = std::make_shared<davinci::MeshComponent>(sceneNode);
|
|
|
|
meshComponet->setMesh(meshPtr);
|
|
|
|
sceneNode->addComponent(std::dynamic_pointer_cast<davinci::SceneComponent>(meshComponet));
|
|
}
|
|
}
|
|
//add camera component
|
|
if (gltfNode.camera != -1)
|
|
{
|
|
const tinygltf::Camera& gltfCamera = gltfModel.cameras[gltfNode.camera];
|
|
if (gltfCamera.type == "perspective")
|
|
{
|
|
davinci::CameraComponentPtr cameraComponent = std::make_shared<davinci::CameraComponent>(sceneNode);
|
|
|
|
davinci::CameraComponent::CameraDefine cameraDefine;
|
|
cameraDefine.aspect = gltfCamera.perspective.aspectRatio;
|
|
cameraDefine.fov = gltfCamera.perspective.yfov;
|
|
cameraDefine.nearClip = gltfCamera.perspective.znear;
|
|
cameraDefine.farClip = gltfCamera.perspective.zfar;
|
|
cameraComponent->setCameraDefine(cameraDefine);
|
|
|
|
sceneNode->addComponent(std::dynamic_pointer_cast<davinci::SceneComponent>(cameraComponent));
|
|
}
|
|
}
|
|
|
|
//add light component(KHR_lights_punctual)
|
|
do
|
|
{
|
|
auto node_light_it = gltfNode.extensions.find("KHR_lights_punctual");
|
|
if (node_light_it == gltfNode.extensions.end()) {
|
|
break;
|
|
}
|
|
|
|
auto lightValue = node_light_it->second.Get("light");
|
|
if (!lightValue.IsNumber()) {
|
|
break;
|
|
}
|
|
|
|
int32_t lightIndex = lightValue.GetNumberAsInt();
|
|
if (lightIndex < 0 || lightIndex >= lightsArray.size()) {
|
|
break;
|
|
}
|
|
|
|
davinci::LightComponentPtr lightComponent = std::make_shared<davinci::LightComponent>(sceneNode);
|
|
lightComponent->setLightDefine(lightsArray[lightIndex]);
|
|
sceneNode->addComponent(std::dynamic_pointer_cast<davinci::SceneComponent>(lightComponent));
|
|
|
|
} while (false);
|
|
|
|
sceneNodeArray.push_back(std::make_pair(true, sceneNode));
|
|
}
|
|
|
|
assert(sceneNodeArray.size() == gltfModel.nodes.size());
|
|
|
|
for (size_t i = 0; i < gltfModel.nodes.size(); i++)
|
|
{
|
|
const tinygltf::Node& gltfNode = gltfModel.nodes[i];
|
|
if (gltfNode.children.empty()) continue;
|
|
|
|
//attach children nodes
|
|
for (size_t j = 0; j < gltfNode.children.size(); j++)
|
|
{
|
|
int32_t childrenIndex = gltfNode.children[j];
|
|
if (childrenIndex < 0 || childrenIndex >= gltfModel.nodes.size())
|
|
{
|
|
//error!
|
|
continue;
|
|
}
|
|
if (!(sceneNodeArray[childrenIndex].first)) //already attached?
|
|
{
|
|
//error!
|
|
continue;
|
|
}
|
|
sceneNodeArray[childrenIndex].first = false;
|
|
sceneNodeArray[i].second->addChild(sceneNodeArray[childrenIndex].second);
|
|
}
|
|
}
|
|
|
|
//add root node
|
|
for (size_t i = 0; i < gltfModel.scenes.size(); i++)
|
|
{
|
|
const tinygltf::Scene& gltfScene = gltfModel.scenes[i];
|
|
for (size_t j = 0; j < gltfScene.nodes.size(); j++)
|
|
{
|
|
int sceneNodeIndex = gltfScene.nodes[j];
|
|
if(sceneNodeIndex<0 || sceneNodeIndex>= gltfModel.nodes.size())
|
|
{
|
|
//error!
|
|
continue;
|
|
}
|
|
if (!(sceneNodeArray[sceneNodeIndex].first)) //already attached?
|
|
{
|
|
//error!
|
|
continue;
|
|
}
|
|
scene.getRootSceneNode()->addChild(sceneNodeArray[sceneNodeIndex].second);
|
|
}
|
|
}
|
|
|
|
//clear temp scene node
|
|
sceneNodeArray.clear();
|
|
return true;
|
|
}
|
|
|
|
bool load_scene_from_gltf(const char* szSceneFiles, davinci::Device& device, davinci::Scene& scene)
|
|
{
|
|
std::filesystem::path sceneFilePath = std::filesystem::path(szSceneFiles);
|
|
|
|
//is file exist?
|
|
if (!std::filesystem::exists(std::string(szSceneFiles)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tinygltf::Model gltfModel;
|
|
|
|
tinygltf::TinyGLTF gltf_ctx;
|
|
gltf_ctx.SetPreserveImageChannels(true);
|
|
|
|
std::string err;
|
|
std::string warn;
|
|
bool ret = false;
|
|
|
|
//get file ext
|
|
std::filesystem::path ext = sceneFilePath.extension();
|
|
|
|
scene.init();
|
|
|
|
//--------------------------
|
|
//load gltf
|
|
if (ext == ".glb")
|
|
{
|
|
//binary file
|
|
ret = gltf_ctx.LoadBinaryFromFile(&gltfModel, &err, &warn, szSceneFiles);
|
|
}
|
|
else
|
|
{
|
|
//text file
|
|
ret = gltf_ctx.LoadASCIIFromFile(&gltfModel, &err, &warn, szSceneFiles);
|
|
}
|
|
|
|
//error
|
|
if (!ret)
|
|
{
|
|
//TODO: log something
|
|
return false;
|
|
}
|
|
|
|
//--------------------------
|
|
//dump to davinci scene
|
|
|
|
//load device buffer
|
|
if (!_loadDeviceBuffer(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load buffer view
|
|
if (!_loadBufferView(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load buffer accessor
|
|
if (!_loadBufferAccessor(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load texture
|
|
if (!_loadTexture(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load material
|
|
if (!_loadMaterial(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load mesh
|
|
if (!_loadMesh(gltfModel, device, scene))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load light externsion
|
|
std::vector<davinci::LightComponent::LightDefine> lightDefine;
|
|
if (!_loadLightExternsion(gltfModel, lightDefine))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//load scene nodes
|
|
if (!_loadSceneNodes(gltfModel, device, scene, lightDefine))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//create default camera
|
|
davinci::SceneNodeConstPtr cameraNode = scene.getNodeWithComponent<davinci::CameraComponent>();
|
|
if (cameraNode.get()==nullptr)
|
|
{
|
|
create_default_camera(scene);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool export_mesh_to_obj(const davinci::Device& device, const davinci::Scene& scene)
|
|
{
|
|
#if 0
|
|
int32_t meshCounts = device.getMeshCounts();
|
|
for (int32_t meshIndex = 0; meshIndex < meshCounts; meshIndex++)
|
|
{
|
|
davinci::MeshConstPtr mesh = device.getMesh(meshIndex);
|
|
|
|
const std::string& meshName = mesh->getName();
|
|
if (meshName.empty()) {
|
|
continue;
|
|
}
|
|
|
|
char szTemp[32] = { 0 };
|
|
_snprintf(szTemp, 32, "d:\\%s.obj", meshName.c_str());
|
|
|
|
FILE* fp = fopen(szTemp, "w");
|
|
fprintf(fp, "o %s\n", meshName.c_str());
|
|
|
|
int32_t primitiveCounts = mesh->getPrimitiveCounts();
|
|
for (int32_t primitiveIndex = 0; primitiveIndex < primitiveCounts; primitiveIndex++)
|
|
{
|
|
davinci::Mesh::PrimitiveConstPtr primitive = mesh->getPrimitive(primitiveIndex);
|
|
|
|
//Output "POSITION"
|
|
davinci::Mesh::PrimitiveAttributes::const_iterator posAttribute = primitive->attributes.find(davinci::VET_POSITION);
|
|
if (posAttribute != primitive->attributes.end())
|
|
{
|
|
davinci::DeviceBufferAccessorConstPtr posBuffer = posAttribute->second;
|
|
posBuffer->walk([=](const uint8_t* ptr, size_t index) {
|
|
const float32_t* pPos = (const float32_t*)ptr;
|
|
|
|
fprintf(fp, "v %f %f %f\n", pPos[0], pPos[1], pPos[2]);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
//Output "NORMAL"
|
|
davinci::Mesh::PrimitiveAttributes::const_iterator normalAttribute = primitive->attributes.find(davinci::VET_NORMAL);
|
|
bool bHasNormal = (normalAttribute != primitive->attributes.end());
|
|
if (bHasNormal)
|
|
{
|
|
davinci::DeviceBufferAccessorConstPtr normalBuffer = normalAttribute->second;
|
|
normalBuffer->walk([=](const uint8_t* ptr, size_t index) {
|
|
const float32_t* pNormal = (const float32_t*)ptr;
|
|
|
|
fprintf(fp, "vn %f %f %f\n", pNormal[0], pNormal[1], pNormal[2]);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
//Output "TEXCOORD_0"
|
|
davinci::Mesh::PrimitiveAttributes::const_iterator tex0Attribute = primitive->attributes.find(davinci::VET_TEXCOORD_0);
|
|
bool bHasTex0 = (tex0Attribute != primitive->attributes.end());
|
|
if (bHasTex0)
|
|
{
|
|
davinci::DeviceBufferAccessorConstPtr tex0Buffer = tex0Attribute->second;
|
|
tex0Buffer->walk([=](const uint8_t* ptr, size_t index) {
|
|
const float32_t* pTex0 = (const float32_t*)ptr;
|
|
|
|
fprintf(fp, "vt %f %f\n", pTex0[0], pTex0[1]);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
//fprintf(fp, "TYPE:%d\n", primitive->type);
|
|
|
|
davinci::DeviceBufferAccessorConstPtr indexBufferAccessor = primitive->indices;
|
|
indexBufferAccessor->walk3([=](const uint8_t* ptr0, const uint8_t* ptr1, const uint8_t* ptr2, size_t index) {
|
|
|
|
uint32_t indice0 = *((uint16_t*)ptr0) + 1;
|
|
uint32_t indice1 = *((uint16_t*)ptr1) + 1;
|
|
uint32_t indice2 = *((uint16_t*)ptr2) + 1;
|
|
|
|
if (bHasTex0)
|
|
{
|
|
if (bHasNormal)
|
|
{
|
|
fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
|
|
indice0, indice0, indice0,
|
|
indice1, indice1, indice1,
|
|
indice2, indice2, indice2
|
|
);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, "f %d/%d %d/%d %d/%d\n",
|
|
indice0, indice0,
|
|
indice1, indice1,
|
|
indice2, indice2
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bHasNormal)
|
|
{
|
|
fprintf(fp, "f %d//%d %d//%d %d//%d\n",
|
|
indice0, indice0,
|
|
indice1, indice1,
|
|
indice2, indice2
|
|
);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, "f %d %d %d\n",
|
|
indice0,
|
|
indice1,
|
|
indice2
|
|
);
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
DV_UTILS_END_NAMESPACE
|