Commit 02d0e6c1 by Kai Westerkamp

generics rework

parent e76fd90e
......@@ -2,20 +2,42 @@
#include "MasterTestProject.h"
#include <locale>
#include <codecvt>
#define TINYGLTF_LOADER_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include "tiny_gltf_loader.h"
#include "Developer/RawMesh/Public/RawMesh.h"
#include "StaticGLTFComponent.h"
/// @cond
// Syntactic sugar to neatly map the TinyGLTF enum to the corresponding data type
// Adapted from http://stackoverflow.com/questions/1735796/is-it-possible-to-choose-a-c-generic-type-parameter-at-runtime
template<int Type> struct GLTFComponentType;
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_BYTE> { typedef int8 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE> { typedef uint8 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_SHORT> { typedef int16 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT> { typedef uint16 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_INT> { typedef int32 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT> { typedef uint32 Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_FLOAT> { typedef float Type; };
template<> struct GLTFComponentType <TINYGLTF_COMPONENT_TYPE_DOUBLE> { typedef double Type; };
template<int Type> struct GLTFType;
template<> struct GLTFType <TINYGLTF_TYPE_VEC2> { typedef FVector2D Type; };
template<> struct GLTFType <TINYGLTF_TYPE_VEC3> { typedef FVector Type; };
template<> struct GLTFType <TINYGLTF_TYPE_VEC4> { typedef FVector4 Type; };
/// @endcond
UStaticGLTFComponent::UStaticGLTFComponent()
{
GLTFPath = TEXT("H:/Repositories/MasterArbeit/glTF-Sample-Models/1.0/Duck/glTF/Duck.gltf");
GLTFPath = TEXT("D:/Dropbox/Studium/MasterArbeit/glTF-Sample-Models/1.0/Duck/glTF/Duck.gltf");
Loader = new tinygltf::TinyGLTFLoader;
Scene = new tinygltf::Scene;
......@@ -54,6 +76,71 @@ void UStaticGLTFComponent::OnRegister()
}
void UStaticGLTFComponent::ImportNodes(std::vector<std::string> nodes, FRawMesh& RawMesh, FMatrix ModelTransform)
{
for (auto CurrentNodeName : nodes) {
UE_LOG(GLTF, Log, TEXT("parsed Node %s"), *ToFString(CurrentNodeName));
tinygltf::Node CurrentNode = Scene->nodes[CurrentNodeName];
for (std::string meshName : CurrentNode.meshes) {
tinygltf::Mesh mesh = Scene->meshes[meshName];
for (tinygltf::Primitive primitive : mesh.primitives) {
if (primitive.mode != TINYGLTF_MODE_TRIANGLES) {
UE_LOG(GLTF, Error, TEXT("Unsupported Mesh Primitive Mode %d "), primitive.mode);
}
//TODO parse or link Material if necesssary
//primitive.material;
ModelTransform = ModelTransform * GetNodeTransform(&CurrentNode);
//TODO CorrectUp Direction
//FTransform Temp(FRotator(0.0f, 0.0f, -90.0f));
//TotalMatrix = TotalMatrix * Temp.ToMatrixWithScale();
//GetBufferData(OutArray, Scene->accessors[primitive.attributes["POSITION"]]);
}
}
ImportNodes(CurrentNode.children, RawMesh, ModelTransform);
}
}
FMatrix UStaticGLTFComponent::GetNodeTransform(tinygltf::Node* Node)
{
if (Node->matrix.size() == 16)
{
FMatrix Ret;
for (int32 i = 0; i < 4; ++i)
{
for (int32 j = 0; j < 4; ++j)
{
// Reverse order since glTF is column major and FMatrix is row major
Ret.M[j][i] = Node->matrix[(4 * i) + j];
}
}
return Ret;
}
else if (Node->rotation.size() == 4 && Node->scale.size() == 3 && Node->translation.size() == 3)
{
FQuat Rotation((float)Node->rotation[0], (float)Node->rotation[1], (float)Node->rotation[2], (float)Node->rotation[3]);
FVector Scale((float)Node->scale[0], (float)Node->scale[1], (float)Node->scale[2]);
FVector Translation((float)Node->translation[0], (float)Node->translation[1], (float)Node->translation[2]);
return FTransform(Rotation, Translation, Scale).ToMatrixWithScale();
}
else
{
return FMatrix::Identity;
}
}
FString UStaticGLTFComponent::ToFString(std::string InString)
{
return FString(InString.c_str());
......@@ -66,4 +153,168 @@ std::string UStaticGLTFComponent::ToStdString(FString InString)
std::wstring WideString(&CharArray[0]);
std::wstring_convert< std::codecvt_utf8<wchar_t> > Convert;
return Convert.to_bytes(WideString);
}
//Buffer Copy Methods:
// Retrieve a value from the buffer, implicitly accounting for endianness
// Adapted from http://stackoverflow.com/questions/13001183/how-to-read-little-endian-integers-from-file-in-c
template <typename T> T UStaticGLTFComponent::BufferValue(void* Data/*, uint8 Size*/)
{
T Ret = T(0);
auto NewData = reinterpret_cast<unsigned char*>(Data);
for (int i = 0; i < sizeof(T); ++i)
{
Ret |= (T)(NewData[i]) << (8 * i);
}
return Ret;
}
// Use unions for floats and doubles since they don't have a bitwise OR operator
template <> float UStaticGLTFComponent::BufferValue(void* Data)
{
assert(sizeof(float) == sizeof(int32));
union
{
float Ret;
int32 IntRet;
};
Ret = 0.0f;
auto NewData = reinterpret_cast<unsigned char*>(Data);
for (int i = 0; i < sizeof(int32); ++i)
{
IntRet |= (int32)(NewData[i]) << (8 * i);
}
return Ret;
}
template <> double UStaticGLTFComponent::BufferValue(void* Data)
{
assert(sizeof(float) == sizeof(int64));
union
{
double Ret;
int64 IntRet;
};
Ret = 0.0;
auto NewData = reinterpret_cast<unsigned char*>(Data);
for (int i = 0; i < sizeof(int64); ++i)
{
IntRet |= (int64)(NewData[i]) << (8 * i);
}
return Ret;
}
template <typename SrcType, typename DstTypse> void UStaticGLTFComponent::BufferCopy(TArray<DstTypse>& OutArray, unsigned char* Data, int32 Count, size_t Stride)
{
for (int32 i = 0; i < Count; ++i)
{
// At this point, assume we can cast directly to the destination type
OutArray.Add((DstType)BufferValue<SrcType>(Data));
Data += Stride;
}
}
template <typename SrcType> void UStaticGLTFComponent::BufferCopy(TArray<FVector2D> &OutArray, unsigned char* Data, int32 Count, size_t Stride)
{
for (int32 i = 0; i < Count; ++i)
{
// At this point, assume we can cast directly to the destination type
OutArray.Add(FVector2D(BufferValue<SrcType>(Data), BufferValue<SrcType>(Data + sizeof(SrcType))));
Data += Stride;
}
}
template <typename SrcType> void UStaticGLTFComponent::BufferCopy(TArray<FVector> &OutArray, unsigned char* Data, int32 Count, size_t Stride)
{
for (int32 i = 0; i < Count; ++i)
{
// At this point, assume we can cast directly to the destination type
OutArray.Add(FVector(BufferValue<SrcType>(Data), BufferValue<SrcType>(Data + sizeof(SrcType)), BufferValue<SrcType>(Data + 2 * sizeof(SrcType))));
Data += Stride;
}
}
template <typename SrcType> void UStaticGLTFComponent::BufferCopy(TArray<FVector4> &OutArray, unsigned char* Data, int32 Count, size_t Stride)
{
for (int32 i = 0; i < Count; ++i)
{
// At this point, assume we can cast directly to the destination type
OutArray.Add(FVector4(BufferValue<SrcType>(Data), BufferValue<SrcType>(Data + sizeof(SrcType)), BufferValue<SrcType>(Data + 2 * sizeof(SrcType)), BufferValue<SrcType>(Data + 3 * sizeof(SrcType))));
Data += Stride;
}
}
template <typename DstType>
bool UStaticGLTFComponent::GetBufferData(TArray<DstType> &OutArray, tinygltf::Accessor* Accessor, bool Append)
{
if (!Accessor)
{
return false;
}
tinygltf::BufferView* BufferView = &Scene->bufferViews[Accessor->bufferView];
if (!BufferView)
{
return false;
}
tinygltf::Buffer* Buffer = &Scene->buffers[BufferView->buffer];
if (!Buffer)
{
return false;
}
if (!Append)
{
OutArray.Empty();
}
size_t Stride;
if (Accessor->byteStride != 0)
{
Stride = Accessor->byteStride;
}
else
{
//FIXME wont work for type
Stride = TypeSize(Accessor->componentType);
switch (Accessor->componentType)
{
case TINYGLTF_TYPE_VEC2: Stride *= 2; break;
case TINYGLTF_TYPE_VEC3: Stride *= 3; break;
case TINYGLTF_TYPE_VEC4: Stride *= 4; break;
default: UE_LOG(GLTF, Error, TEXT("Unsupported Accessor Type %s"), Accessor->componentType); break;
}
}
unsigned char* Start = &Buffer->data[Accessor->byteOffset + BufferView->byteOffset];
switch (Accessor->componentType)
{
case TINYGLTF_COMPONENT_TYPE_BYTE: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_BYTE> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_SHORT: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_SHORT> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_INT: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_INT> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_FLOAT: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_FLOAT> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
case TINYGLTF_COMPONENT_TYPE_DOUBLE: BufferCopy<GLTFType<TINYGLTF_COMPONENT_TYPE_DOUBLE> ::Type,DstType>(OutArray, Start, Accessor->count, Stride); break;
default: BufferCopy<DstType, DstType>(OutArray, Start, Accessor->count, Stride); break;
}
return true;
}
\ No newline at end of file
......@@ -30,6 +30,8 @@ namespace tinygltf
typedef struct MATERIAL Material;
}
struct FRawMesh;
/**
*
*/
......@@ -57,6 +59,55 @@ private:
bool tinygltfLoadSuccess;
FString tinygltfError;
void ImportNodes(std::vector<std::string> nodes, FRawMesh& RawMesh, FMatrix ModelTransform);
/// Returns the transform of a node relative to its parent.
FMatrix GetNodeTransform(tinygltf::Node* Node);
//Copy methods
/// @name Level 3: GetBufferData
///@{
/// Fills a TArray with typed data; works at the glTF Accessor level and figures out which arguments to send to <B>BufferCopy()</B>.
/// @param OutArray The array to fill with data from the imported file.
/// @param Accessor A pointer to a glTF Accessor containing the type data for the geometry attribute.
/// @param Append Whether to add to the array or overwrite the elements currently in it.
//template <typename T> bool GetBufferData (TArray<T> &OutArray, tinygltf::Accessor* Accessor, bool Append = true);
///@}
/// @name Level 1: BufferValue
///@{
/// Obtains a single value from the geometry data buffer, accounting for endianness.
/// Adapted from http://stackoverflow.com/questions/13001183/how-to-read-little-endian-integers-from-file-in-c
/// @param Data A pointer to the raw data to cast to the desired type.
/// @return The typed data value.
template <typename T> T BufferValue(void* Data);
///@}
/// @name Level 2: BufferCopy
///@{
/// Handles filling the TArray at the data type level.
/// @param OutArray The array to fill with data from the imported file.
/// @param Data A pointer to the raw data to use as the argument to <B>BufferValue()</B>.
/// @param Count The number of elements to add to the array i.e. the number of calls to <B>BufferValue()</B>.
/// @param Stride The number of bytes between the first byte of each element - usually the size of one element.
template <typename SrcType, typename DstType> void BufferCopy(TArray<DstType> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector2D> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector4> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
///@}
/// @name Level 3: GetBufferData
///@{
/// Fills a TArray with typed data; works at the glTF Accessor level and figures out which arguments to send to <B>BufferCopy()</B>.
/// @param OutArray The array to fill with data from the imported file.
/// @param Accessor A pointer to a glTF Accessor containing the type data for the geometry attribute.
/// @param Append Whether to add to the array or overwrite the elements currently in it.
template <typename DstType> bool GetBufferData(TArray<DstType> &OutArray, tinygltf::Accessor* Accessor, bool Append = true);
///@}
/// @name String Conversion
///@{
......
......@@ -43,7 +43,7 @@ void AGLTFDisplay::BeginPlay()
//StaticMeshComponent->SetupAttachment(RootComponent);
if (!originalGLTFImport->IsRegistered())
originalGLTFImport->RegisterComponent();
//originalGLTFImport->RegisterComponent();
originalGLTFImport->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
......
......@@ -7,7 +7,7 @@ public class MasterTestProject : ModuleRules
public MasterTestProject(TargetInfo Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", });
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "RawMesh" });
PrivateDependencyModuleNames.AddRange(new string[] { });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment