Commit 92bf458f by wester

rabbit mq

parent b2501a77
......@@ -64,7 +64,7 @@ bUseSplitscreen=False
TwoPlayerSplitscreenLayout=Horizontal
ThreePlayerSplitscreenLayout=FavorTop
bOffsetPlayerGamepadIds=False
GameInstanceClass=/Script/Engine.GameInstance
GameInstanceClass=/Script/MasterTestProject.MyGameInstance
GameDefaultMap=/Game/DefaultVRMap.DefaultVRMap
ServerDefaultMap=/Engine/Maps/Entry.Entry
GlobalDefaultGameMode=/Game/VR_GameMode.VR_GameMode_C
......@@ -96,6 +96,7 @@ TriangleMeshTriangleMinAreaThreshold=5.000000
bEnableAsyncScene=False
bEnableShapeSharing=False
bEnablePCM=False
bEnableStabilization=False
bWarnMissingLocks=True
bEnable2DPhysics=False
LockedAxis=Invalid
......@@ -115,6 +116,7 @@ bSuppressFaceRemapTable=False
bSupportUVFromHitResults=False
bDisableActiveActors=False
bDisableCCD=False
bEnableEnhancedDeterminism=False
MaxPhysicsDeltaTime=0.033333
bSubstepping=False
bSubsteppingAsync=False
......@@ -123,5 +125,5 @@ MaxSubsteps=6
SyncSceneSmoothingFactor=0.000000
AsyncSceneSmoothingFactor=0.990000
InitialAverageFrameRate=0.016667
PhysXTreeRebuildRate=10
No preview for this file type
......@@ -5,21 +5,10 @@ using System.Collections.Generic;
public class MasterTestProjectTarget : TargetRules
{
public MasterTestProjectTarget(TargetInfo Target)
{
public MasterTestProjectTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
ExtraModuleNames.Add("MasterTestProject");
}
//
// TargetRules interface.
//
public override void SetupBinaries(
TargetInfo Target,
ref List<UEBuildBinaryConfiguration> OutBuildBinaryConfigurations,
ref List<string> OutExtraModuleNames
)
{
OutExtraModuleNames.AddRange( new string[] { "MasterTestProject" } );
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#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"
UStaticGLTFComponent::UStaticGLTFComponent()
{
GLTFPath = TEXT("H:/Repositories/MasterArbeit/glTF-Sample-Models/1.0/Duck/glTF/Duck.gltf");
Loader = new tinygltf::TinyGLTFLoader;
Scene = new tinygltf::Scene;
}
UStaticGLTFComponent::~UStaticGLTFComponent() {
delete Loader;
delete Scene;
}
void UStaticGLTFComponent::OnRegister()
{
Super::OnRegister();
std::string temperror;
tinygltfLoadSuccess = Loader->LoadFromFile((*Scene), temperror, ToStdString(GLTFPath));
tinygltfError = ToFString(temperror);
if(!tinygltfLoadSuccess){
UE_LOG(GLTF, Error, TEXT("gltf loading error: %s"), *tinygltfError);
return;
}
UE_LOG(GLTF, Log, TEXT("gltf parsed %s"), *tinygltfError);
FRawMesh newrawmesh;
//get default scene and root nodes
if (Scene->defaultScene.empty()) {
UE_LOG(GLTF, Error, TEXT("default scene empty "));
}
else {
ImportNodes( Scene->scenes[Scene->defaultScene], newrawmesh, FMatrix());
}
}
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);
}
}
FString UStaticGLTFComponent::ToFString(std::string InString)
{
return FString(InString.c_str());
}
std::string UStaticGLTFComponent::ToStdString(FString InString)
{
auto CharArray = InString.GetCharArray();
std::wstring WideString(&CharArray[0]);
std::wstring_convert< std::codecvt_utf8<wchar_t> > Convert;
return Convert.to_bytes(WideString);
}
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;
}
}
//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;
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Components/StaticMeshComponent.h"
#include <string>
#include <vector>
#include "StaticGLTFComponent.generated.h"
struct FRawMesh;
/// Forward-declared TinyGLTF types since its header can only be #included in one source file.
/// This also means that we must use pointers to these types outside of GLTFMeshBuilder.cpp.
namespace tinygltf
{
class TinyGLTFLoader;
class Scene;
class Node;
struct ACCESSOR;
typedef struct ACCESSOR Accessor;
struct PRIMITIVE;
typedef struct PRIMITIVE Primitive;
struct MESH;
typedef struct MESH Mesh;
struct MATERIAL;
typedef struct MATERIAL Material;
}
/**
*
*/
UCLASS()
class MASTERTESTPROJECT_API UStaticGLTFComponent : public UStaticMeshComponent
{
GENERATED_BODY()
public:
UStaticGLTFComponent();
~UStaticGLTFComponent();
UPROPERTY(Category = GLTF, EditAnywhere, BlueprintReadWrite)
FString GLTFPath;
virtual void OnRegister() override;
private:
tinygltf::TinyGLTFLoader* Loader;
tinygltf::Scene* Scene;
bool tinygltfLoadSuccess;
FString tinygltfError;
void ImportNodes(std::vector<std::string> nodes, FRawMesh& RawMesh, FMatrix ModelTransform);
/// @name String Conversion
///@{
/// Helper functions for converting between Unreal's and STL's strings.
static FString ToFString(std::string InString);
static std::string ToStdString(FString InString);
///@}
/// Returns the transform of a node relative to its parent.
FMatrix GetNodeTransform(tinygltf::Node* Node);
//Copy methods
/// @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);
///@}
};
/*
* Copyright 2009-2010 Cybozu Labs, Inc.
* Copyright 2011-2014 Kazuho Oku
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef picojson_h
#define picojson_h
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
// for isnan/isinf
#if __cplusplus>=201103L
# include <cmath>
#else
extern "C" {
# ifdef _MSC_VER
# include <float.h>
# elif defined(__INTEL_COMPILER)
# include <mathimf.h>
# else
# include <math.h>
# endif
}
#endif
#ifndef PICOJSON_USE_RVALUE_REFERENCE
# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)
# define PICOJSON_USE_RVALUE_REFERENCE 1
# else
# define PICOJSON_USE_RVALUE_REFERENCE 0
# endif
#endif//PICOJSON_USE_RVALUE_REFERENCE
// experimental support for int64_t (see README.mkdn for detail)
#ifdef PICOJSON_USE_INT64
# define __STDC_FORMAT_MACROS
# include <errno.h>
# include <inttypes.h>
#endif
// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
#ifndef PICOJSON_USE_LOCALE
# define PICOJSON_USE_LOCALE 1
#endif
#if PICOJSON_USE_LOCALE
extern "C" {
# include <locale.h>
}
#endif
#ifndef PICOJSON_ASSERT
# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)
#endif
#ifdef _MSC_VER
#define SNPRINTF _snprintf_s
#pragma warning(push)
#pragma warning(disable : 4244) // conversion from int to char
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4702) // unreachable code
#else
#define SNPRINTF snprintf
#endif
namespace picojson {
enum {
null_type,
boolean_type,
number_type,
string_type,
array_type,
object_type
#ifdef PICOJSON_USE_INT64
, int64_type
#endif
};
enum {
INDENT_WIDTH = 2
};
struct null {};
class value {
public:
typedef std::vector<value> array;
typedef std::map<std::string, value> object;
union _storage {
bool boolean_;
double number_;
#ifdef PICOJSON_USE_INT64
int64_t int64_;
#endif
std::string* string_;
array* array_;
object* object_;
};
protected:
int type_;
_storage u_;
public:
value();
value(int type, bool);
explicit value(bool b);
#ifdef PICOJSON_USE_INT64
explicit value(int64_t i);
#endif
explicit value(double n);
explicit value(const std::string& s);
explicit value(const array& a);
explicit value(const object& o);
explicit value(const char* s);
value(const char* s, size_t len);
~value();
value(const value& x);
value& operator=(const value& x);
#if PICOJSON_USE_RVALUE_REFERENCE
value(value&& x)throw();
value& operator=(value&& x)throw();
#endif
void swap(value& x)throw();
template <typename T> bool is() const;
template <typename T> const T& get() const;
template <typename T> T& get();
bool evaluate_as_boolean() const;
const value& get(size_t idx) const;
const value& get(const std::string& key) const;
value& get(size_t idx);
value& get(const std::string& key);
bool contains(size_t idx) const;
bool contains(const std::string& key) const;
std::string to_str() const;
template <typename Iter> void serialize(Iter os, bool prettify = false) const;
std::string serialize(bool prettify = false) const;
private:
template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
template <typename Iter> static void _indent(Iter os, int indent);
template <typename Iter> void _serialize(Iter os, int indent) const;
std::string _serialize(int indent) const;
};
typedef value::array array;
typedef value::object object;
inline value::value() : type_(null_type) {}
inline value::value(int type, bool) : type_(type) {
switch (type) {
#define INIT(p, v) case p##type: u_.p = v; break
INIT(boolean_, false);
INIT(number_, 0.0);
#ifdef PICOJSON_USE_INT64
INIT(int64_, 0);
#endif
INIT(string_, new std::string());
INIT(array_, new array());
INIT(object_, new object());
#undef INIT
default: break;
}
}
inline value::value(bool b) : type_(boolean_type) {
u_.boolean_ = b;
}
#ifdef PICOJSON_USE_INT64
inline value::value(int64_t i) : type_(int64_type) {
u_.int64_ = i;
}
#endif
inline value::value(double n) : type_(number_type) {
if (
#ifdef _MSC_VER
! _finite(n)
#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
std::isnan(n) || std::isinf(n)
#else
isnan(n) || isinf(n)
#endif
) {
throw std::overflow_error("");
}
u_.number_ = n;
}
inline value::value(const std::string& s) : type_(string_type) {
u_.string_ = new std::string(s);
}
inline value::value(const array& a) : type_(array_type) {
u_.array_ = new array(a);
}
inline value::value(const object& o) : type_(object_type) {
u_.object_ = new object(o);
}
inline value::value(const char* s) : type_(string_type) {
u_.string_ = new std::string(s);
}
inline value::value(const char* s, size_t len) : type_(string_type) {
u_.string_ = new std::string(s, len);
}
inline value::~value() {
switch (type_) {
#define DEINIT(p) case p##type: delete u_.p; break
DEINIT(string_);
DEINIT(array_);
DEINIT(object_);
#undef DEINIT
default: break;
}
}
inline value::value(const value& x) : type_(x.type_) {
switch (type_) {
#define INIT(p, v) case p##type: u_.p = v; break
INIT(string_, new std::string(*x.u_.string_));
INIT(array_, new array(*x.u_.array_));
INIT(object_, new object(*x.u_.object_));
#undef INIT
default:
u_ = x.u_;
break;
}
}
inline value& value::operator=(const value& x) {
if (this != &x) {
value t(x);
swap(t);
}
return *this;
}
#if PICOJSON_USE_RVALUE_REFERENCE
inline value::value(value&& x)throw() : type_(null_type) {
swap(x);
}
inline value& value::operator=(value&& x)throw() {
swap(x);
return *this;
}
#endif
inline void value::swap(value& x)throw() {
std::swap(type_, x.type_);
std::swap(u_, x.u_);
}
#define IS(ctype, jtype) \
template <> inline bool value::is<ctype>() const { \
return type_ == jtype##_type; \
}
IS(null, null)
IS(bool, boolean)
#ifdef PICOJSON_USE_INT64
IS(int64_t, int64)
#endif
IS(std::string, string)
IS(array, array)
IS(object, object)
#undef IS
template <> inline bool value::is<double>() const {
return type_ == number_type
#ifdef PICOJSON_USE_INT64
|| type_ == int64_type
#endif
;
}
#define GET(ctype, var) \
template <> inline const ctype& value::get<ctype>() const { \
PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
&& is<ctype>()); \
return var; \
} \
template <> inline ctype& value::get<ctype>() { \
PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
&& is<ctype>()); \
return var; \
}
GET(bool, u_.boolean_)
GET(std::string, *u_.string_)
GET(array, *u_.array_)
GET(object, *u_.object_)
#ifdef PICOJSON_USE_INT64
GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))
GET(int64_t, u_.int64_)
#else
GET(double, u_.number_)
#endif
#undef GET
inline bool value::evaluate_as_boolean() const {
switch (type_) {
case null_type:
return false;
case boolean_type:
return u_.boolean_;
case number_type:
return u_.number_ != 0;
#ifdef PICOJSON_USE_INT64
case int64_type:
return u_.int64_ != 0;
#endif
case string_type:
return ! u_.string_->empty();
default:
return true;
}
}
inline const value& value::get(size_t idx) const {
static value s_null;
PICOJSON_ASSERT(is<array>());
return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
}
inline value& value::get(size_t idx) {
static value s_null;
PICOJSON_ASSERT(is<array>());
return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
}
inline const value& value::get(const std::string& key) const {
static value s_null;
PICOJSON_ASSERT(is<object>());
object::const_iterator i = u_.object_->find(key);
return i != u_.object_->end() ? i->second : s_null;
}
inline value& value::get(const std::string& key) {
static value s_null;
PICOJSON_ASSERT(is<object>());
object::iterator i = u_.object_->find(key);
return i != u_.object_->end() ? i->second : s_null;
}
inline bool value::contains(size_t idx) const {
PICOJSON_ASSERT(is<array>());
return idx < u_.array_->size();
}
inline bool value::contains(const std::string& key) const {
PICOJSON_ASSERT(is<object>());
object::const_iterator i = u_.object_->find(key);
return i != u_.object_->end();
}
inline std::string value::to_str() const {
switch (type_) {
case null_type: return "null";
case boolean_type: return u_.boolean_ ? "true" : "false";
#ifdef PICOJSON_USE_INT64
case int64_type: {
char buf[sizeof("-9223372036854775808")];
SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
return buf;
}
#endif
case number_type: {
char buf[256];
double tmp;
SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
#if PICOJSON_USE_LOCALE
char *decimal_point = localeconv()->decimal_point;
if (strcmp(decimal_point, ".") != 0) {
size_t decimal_point_len = strlen(decimal_point);
for (char *p = buf; *p != '\0'; ++p) {
if (strncmp(p, decimal_point, decimal_point_len) == 0) {
return std::string(buf, p) + "." + (p + decimal_point_len);
}
}
}
#endif
return buf;
}
case string_type: return *u_.string_;
case array_type: return "array";
case object_type: return "object";
default: PICOJSON_ASSERT(0);
#ifdef _MSC_VER
__assume(0);
#endif
}
return std::string();
}
template <typename Iter> void copy(const std::string& s, Iter oi) {
std::copy(s.begin(), s.end(), oi);
}
template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
*oi++ = '"';
for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
switch (*i) {
#define MAP(val, sym) case val: copy(sym, oi); break
MAP('"', "\\\"");
MAP('\\', "\\\\");
MAP('/', "\\/");
MAP('\b', "\\b");
MAP('\f', "\\f");
MAP('\n', "\\n");
MAP('\r', "\\r");
MAP('\t', "\\t");
#undef MAP
default:
if (static_cast<unsigned char>(*i) < 0x20 || *i == 0x7f) {
char buf[7];
SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
copy(buf, buf + 6, oi);
} else {
*oi++ = *i;
}
break;
}
}
*oi++ = '"';
}
template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
return _serialize(oi, prettify ? 0 : -1);
}
inline std::string value::serialize(bool prettify) const {
return _serialize(prettify ? 0 : -1);
}
template <typename Iter> void value::_indent(Iter oi, int indent) {
*oi++ = '\n';
for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
*oi++ = ' ';
}
}
template <typename Iter> void value::_serialize(Iter oi, int indent) const {
switch (type_) {
case string_type:
serialize_str(*u_.string_, oi);
break;
case array_type: {
*oi++ = '[';
if (indent != -1) {
++indent;
}
for (array::const_iterator i = u_.array_->begin();
i != u_.array_->end();
++i) {
if (i != u_.array_->begin()) {
*oi++ = ',';
}
if (indent != -1) {
_indent(oi, indent);
}
i->_serialize(oi, indent);
}
if (indent != -1) {
--indent;
if (! u_.array_->empty()) {
_indent(oi, indent);
}
}
*oi++ = ']';
break;
}
case object_type: {
*oi++ = '{';
if (indent != -1) {
++indent;
}
for (object::const_iterator i = u_.object_->begin();
i != u_.object_->end();
++i) {
if (i != u_.object_->begin()) {
*oi++ = ',';
}
if (indent != -1) {
_indent(oi, indent);
}
serialize_str(i->first, oi);
*oi++ = ':';
if (indent != -1) {
*oi++ = ' ';
}
i->second._serialize(oi, indent);
}
if (indent != -1) {
--indent;
if (! u_.object_->empty()) {
_indent(oi, indent);
}
}
*oi++ = '}';
break;
}
default:
copy(to_str(), oi);
break;
}
if (indent == 0) {
*oi++ = '\n';
}
}
inline std::string value::_serialize(int indent) const {
std::string s;
_serialize(std::back_inserter(s), indent);
return s;
}
template <typename Iter> class input {
protected:
Iter cur_, end_;
int last_ch_;
bool ungot_;
int line_;
public:
input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
int getc() {
if (ungot_) {
ungot_ = false;
return last_ch_;
}
if (cur_ == end_) {
last_ch_ = -1;
return -1;
}
if (last_ch_ == '\n') {
line_++;
}
last_ch_ = *cur_ & 0xff;
++cur_;
return last_ch_;
}
void ungetc() {
if (last_ch_ != -1) {
PICOJSON_ASSERT(! ungot_);
ungot_ = true;
}
}
Iter cur() const { return cur_; }
int line() const { return line_; }
void skip_ws() {
while (1) {
int ch = getc();
if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
ungetc();
break;
}
}
}
bool expect(int expect) {
skip_ws();
if (getc() != expect) {
ungetc();
return false;
}
return true;
}
bool match(const std::string& pattern) {
for (std::string::const_iterator pi(pattern.begin());
pi != pattern.end();
++pi) {
if (getc() != *pi) {
ungetc();
return false;
}
}
return true;
}
};
template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
int uni_ch = 0, hex;
for (int i = 0; i < 4; i++) {
if ((hex = in.getc()) == -1) {
return -1;
}
if ('0' <= hex && hex <= '9') {
hex -= '0';
} else if ('A' <= hex && hex <= 'F') {
hex -= 'A' - 0xa;
} else if ('a' <= hex && hex <= 'f') {
hex -= 'a' - 0xa;
} else {
in.ungetc();
return -1;
}
uni_ch = uni_ch * 16 + hex;
}
return uni_ch;
}
template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {
int uni_ch;
if ((uni_ch = _parse_quadhex(in)) == -1) {
return false;
}
if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
if (0xdc00 <= uni_ch) {
// a second 16-bit of a surrogate pair appeared
return false;
}
// first 16-bit of surrogate pair, get the next one
if (in.getc() != '\\' || in.getc() != 'u') {
in.ungetc();
return false;
}
int second = _parse_quadhex(in);
if (! (0xdc00 <= second && second <= 0xdfff)) {
return false;
}
uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
uni_ch += 0x10000;
}
if (uni_ch < 0x80) {
out.push_back(uni_ch);
} else {
if (uni_ch < 0x800) {
out.push_back(0xc0 | (uni_ch >> 6));
} else {
if (uni_ch < 0x10000) {
out.push_back(0xe0 | (uni_ch >> 12));
} else {
out.push_back(0xf0 | (uni_ch >> 18));
out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
}
out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
}
out.push_back(0x80 | (uni_ch & 0x3f));
}
return true;
}
template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) {
while (1) {
int ch = in.getc();
if (ch < ' ') {
in.ungetc();
return false;
} else if (ch == '"') {
return true;
} else if (ch == '\\') {
if ((ch = in.getc()) == -1) {
return false;
}
switch (ch) {
#define MAP(sym, val) case sym: out.push_back(val); break
MAP('"', '\"');
MAP('\\', '\\');
MAP('/', '/');
MAP('b', '\b');
MAP('f', '\f');
MAP('n', '\n');
MAP('r', '\r');
MAP('t', '\t');
#undef MAP
case 'u':
if (! _parse_codepoint(out, in)) {
return false;
}
break;
default:
return false;
}
} else {
out.push_back(ch);
}
}
return false;
}
template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {
if (! ctx.parse_array_start()) {
return false;
}
size_t idx = 0;
if (in.expect(']')) {
return ctx.parse_array_stop(idx);
}
do {
if (! ctx.parse_array_item(in, idx)) {
return false;
}
idx++;
} while (in.expect(','));
return in.expect(']') && ctx.parse_array_stop(idx);
}
template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {
if (! ctx.parse_object_start()) {
return false;
}
if (in.expect('}')) {
return true;
}
do {
std::string key;
if (! in.expect('"')
|| ! _parse_string(key, in)
|| ! in.expect(':')) {
return false;
}
if (! ctx.parse_object_item(in, key)) {
return false;
}
} while (in.expect(','));
return in.expect('}');
}
template <typename Iter> inline std::string _parse_number(input<Iter>& in) {
std::string num_str;
while (1) {
int ch = in.getc();
if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'
|| ch == 'e' || ch == 'E') {
num_str.push_back(ch);
} else if (ch == '.') {
#if PICOJSON_USE_LOCALE
num_str += localeconv()->decimal_point;
#else
num_str.push_back('.');
#endif
} else {
in.ungetc();
break;
}
}
return num_str;
}
template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {
in.skip_ws();
int ch = in.getc();
switch (ch) {
#define IS(ch, text, op) case ch: \
if (in.match(text) && op) { \
return true; \
} else { \
return false; \
}
IS('n', "ull", ctx.set_null());
IS('f', "alse", ctx.set_bool(false));
IS('t', "rue", ctx.set_bool(true));
#undef IS
case '"':
return ctx.parse_string(in);
case '[':
return _parse_array(ctx, in);
case '{':
return _parse_object(ctx, in);
default:
if (('0' <= ch && ch <= '9') || ch == '-') {
double f;
char *endp;
in.ungetc();
std::string num_str = _parse_number(in);
if (num_str.empty()) {
return false;
}
#ifdef PICOJSON_USE_INT64
{
errno = 0;
intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
if (errno == 0
&& std::numeric_limits<int64_t>::min() <= ival
&& ival <= std::numeric_limits<int64_t>::max()
&& endp == num_str.c_str() + num_str.size()) {
ctx.set_int64(ival);
return true;
}
}
#endif
f = strtod(num_str.c_str(), &endp);
if (endp == num_str.c_str() + num_str.size()) {
ctx.set_number(f);
return true;
}
return false;
}
break;
}
in.ungetc();
return false;
}
class deny_parse_context {
public:
bool set_null() { return false; }
bool set_bool(bool) { return false; }
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t) { return false; }
#endif
bool set_number(double) { return false; }
template <typename Iter> bool parse_string(input<Iter>&) { return false; }
bool parse_array_start() { return false; }
template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {
return false;
}
bool parse_array_stop(size_t) { return false; }
bool parse_object_start() { return false; }
template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {
return false;
}
};
class default_parse_context {
protected:
value* out_;
public:
default_parse_context(value* out) : out_(out) {}
bool set_null() {
*out_ = value();
return true;
}
bool set_bool(bool b) {
*out_ = value(b);
return true;
}
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t i) {
*out_ = value(i);
return true;
}
#endif
bool set_number(double f) {
*out_ = value(f);
return true;
}
template<typename Iter> bool parse_string(input<Iter>& in) {
*out_ = value(string_type, false);
return _parse_string(out_->get<std::string>(), in);
}
bool parse_array_start() {
*out_ = value(array_type, false);
return true;
}
template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
array& a = out_->get<array>();
a.push_back(value());
default_parse_context ctx(&a.back());
return _parse(ctx, in);
}
bool parse_array_stop(size_t) { return true; }
bool parse_object_start() {
*out_ = value(object_type, false);
return true;
}
template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {
object& o = out_->get<object>();
default_parse_context ctx(&o[key]);
return _parse(ctx, in);
}
private:
default_parse_context(const default_parse_context&);
default_parse_context& operator=(const default_parse_context&);
};
class null_parse_context {
public:
struct dummy_str {
void push_back(int) {}
};
public:
null_parse_context() {}
bool set_null() { return true; }
bool set_bool(bool) { return true; }
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t) { return true; }
#endif
bool set_number(double) { return true; }
template <typename Iter> bool parse_string(input<Iter>& in) {
dummy_str s;
return _parse_string(s, in);
}
bool parse_array_start() { return true; }
template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
return _parse(*this, in);
}
bool parse_array_stop(size_t) { return true; }
bool parse_object_start() { return true; }
template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {
return _parse(*this, in);
}
private:
null_parse_context(const null_parse_context&);
null_parse_context& operator=(const null_parse_context&);
};
// obsolete, use the version below
template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
std::string err;
pos = parse(out, pos, last, &err);
return err;
}
template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
input<Iter> in(first, last);
if (! _parse(ctx, in) && err != NULL) {
char buf[64];
SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
*err = buf;
while (1) {
int ch = in.getc();
if (ch == -1 || ch == '\n') {
break;
} else if (ch >= ' ') {
err->push_back(ch);
}
}
}
return in.cur();
}
template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
default_parse_context ctx(&out);
return _parse(ctx, first, last, err);
}
inline std::string parse(value& out, const std::string& s) {
std::string err;
parse(out, s.begin(), s.end(), &err);
return err;
}
inline std::string parse(value& out, std::istream& is) {
std::string err;
parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
std::istreambuf_iterator<char>(), &err);
return err;
}
template <typename T> struct last_error_t {
static std::string s;
};
template <typename T> std::string last_error_t<T>::s;
inline void set_last_error(const std::string& s) {
last_error_t<bool>::s = s;
}
inline const std::string& get_last_error() {
return last_error_t<bool>::s;
}
inline bool operator==(const value& x, const value& y) {
if (x.is<null>())
return y.is<null>();
#define PICOJSON_CMP(type) \
if (x.is<type>()) \
return y.is<type>() && x.get<type>() == y.get<type>()
PICOJSON_CMP(bool);
PICOJSON_CMP(double);
PICOJSON_CMP(std::string);
PICOJSON_CMP(array);
PICOJSON_CMP(object);
#undef PICOJSON_CMP
PICOJSON_ASSERT(0);
#ifdef _MSC_VER
__assume(0);
#endif
return false;
}
inline bool operator!=(const value& x, const value& y) {
return ! (x == y);
}
}
#if !PICOJSON_USE_RVALUE_REFERENCE
namespace std {
template<> inline void swap(picojson::value& x, picojson::value& y)
{
x.swap(y);
}
}
#endif
inline std::istream& operator>>(std::istream& is, picojson::value& x)
{
picojson::set_last_error(std::string());
std::string err = picojson::parse(x, is);
if (! err.empty()) {
picojson::set_last_error(err);
is.setstate(std::ios::failbit);
}
return is;
}
inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
{
x.serialize(std::ostream_iterator<char>(os));
return os;
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
//
// Tiny glTF loader.
//
// Copyright (c) 2015, Syoyo Fujita.
// All rights reserved.
// (Licensed under 2-clause BSD liecense)
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Version:
// - v0.9.2 Support parsing `texture`
// - v0.9.1 Support loading glTF asset from memory
// - v0.9.0 Initial
//
// Tiny glTF loader is using following libraries:
//
// - picojson: C++ JSON library.
// - base64: base64 decode/encode library.
// - stb_image: Image loading library.
//
#ifndef TINY_GLTF_LOADER_H
#define TINY_GLTF_LOADER_H
#include <string>
#include <vector>
#include <map>
namespace tinygltf {
#define TINYGLTF_MODE_POINTS (0)
#define TINYGLTF_MODE_LINE (1)
#define TINYGLTF_MODE_LINE_LOOP (2)
#define TINYGLTF_MODE_TRIANGLES (4)
#define TINYGLTF_MODE_TRIANGLE_STRIP (5)
#define TINYGLTF_MODE_TRIANGLE_FAN (6)
#define TINYGLTF_COMPONENT_TYPE_BYTE (5120)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121)
#define TINYGLTF_COMPONENT_TYPE_SHORT (5122)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123)
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5127)
#define TINYGLTF_TYPE_VEC2 (2)
#define TINYGLTF_TYPE_VEC3 (3)
#define TINYGLTF_TYPE_VEC4 (4)
#define TINYGLTF_TYPE_MAT2 (32 + 2)
#define TINYGLTF_TYPE_MAT3 (32 + 3)
#define TINYGLTF_TYPE_MAT4 (32 + 4)
#define TINYGLTF_TYPE_SCALAR (64 + 1)
#define TINYGLTF_TYPE_VECTOR (64 + 4)
#define TINYGLTF_TYPE_MATRIX (64 + 16)
#define TINYGLTF_IMAGE_FORMAT_JPEG (0)
#define TINYGLTF_IMAGE_FORMAT_PNG (1)
#define TINYGLTF_IMAGE_FORMAT_BMP (2)
#define TINYGLTF_IMAGE_FORMAT_GIF (3)
#define TINYGLTF_TEXTURE_FORMAT_RGBA (6408)
#define TINYGLTF_TEXTURE_TARGET_TEXTURE2D (3553)
#define TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE (5121)
#define TINYGLTF_TARGET_ARRAY_BUFFER (34962)
#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963)
typedef struct PARAMETER {
std::string stringValue;
std::vector<double> numberArray;
} Parameter;
typedef std::map<std::string, Parameter> ParameterMap;
typedef struct IMAGE {
std::string name;
int width;
int height;
int component;
std::vector<unsigned char> image;
} Image;
typedef struct TEXTURE {
int format;
int internalFormat;
std::string sampler; // Required
std::string source; // Required
int target;
int type;
std::string name;
} Texture;
typedef struct MATERIAL {
std::string name;
std::string technique;
ParameterMap values;
} Material;
typedef struct BUFFERVIEW {
std::string name;
std::string buffer; // Required
size_t byteOffset; // Required
size_t byteLength; // default: 0
int target;
} BufferView;
typedef struct ACCESSOR {
std::string bufferView;
std::string name;
size_t byteOffset;
size_t byteStride;
int componentType; // One of TINYGLTF_COMPONENT_TYPE_***
size_t count;
int type; // One of TINYGLTF_TYPE_***
std::vector<double> minValues; // Optional
std::vector<double> maxValues; // Optional
} Accessor;
class Camera {
public:
Camera() {}
~Camera() {}
std::string name;
bool isOrthographic; // false = perspective.
// Some common properties.
float aspectRatio;
float yFov;
float zFar;
float zNear;
};
typedef struct PRIMITIVE {
std::map<std::string, std::string> attributes; // A dictionary object of
// strings, where each string
// is the ID of the accessor
// containing an attribute.
std::string material; // The ID of the material to apply to this primitive
// when rendering.
std::string indices; // The ID of the accessor that contains the indices.
int mode; // one of TINYGLTF_MODE_***
} Primitive;
typedef struct MESH {
std::string name;
std::vector<Primitive> primitives;
} Mesh;
class Node {
public:
Node() {}
~Node() {}
std::string camera; // camera object referenced by this node.
std::string name;
std::vector<std::string> children;
std::vector<double> rotation; // length must be 0 or 4
std::vector<double> scale; // length must be 0 or 3
std::vector<double> translation; // length must be 0 or 3
std::vector<double> matrix; // length must be 0 or 16
std::vector<std::string> meshes;
};
typedef struct BUFFER {
std::string name;
std::vector<unsigned char> data;
} Buffer;
typedef struct ASSET {
std::string generator;
std::string version;
std::string profile_api;
std::string profile_version;
bool premultipliedAlpha;
} Asset;
class Scene {
public:
Scene() {}
~Scene() {}
std::map<std::string, Accessor> accessors;
std::map<std::string, Buffer> buffers;
std::map<std::string, BufferView> bufferViews;
std::map<std::string, Material> materials;
std::map<std::string, Mesh> meshes;
std::map<std::string, Node> nodes;
std::map<std::string, Texture> textures;
std::map<std::string, Image> images;
std::map<std::string, std::vector<std::string> > scenes; // list of nodes
std::string defaultScene;
Asset asset;
};
class TinyGLTFLoader {
public:
TinyGLTFLoader(){};
~TinyGLTFLoader(){};
/// Loads glTF asset from a file.
/// Returns false and set error string to `err` if there's an error.
bool LoadFromFile(Scene &scene, std::string &err,
const std::string &filename);
/// Loads glTF asset from string(memory).
/// `length` = strlen(str);
/// Returns false and set error string to `err` if there's an error.
bool LoadFromString(Scene &scene, std::string &err, const char *str,
const unsigned int length, const std::string &baseDir);
};
} // namespace tinygltf
#ifdef TINYGLTF_LOADER_IMPLEMENTATION
#include <sstream>
#include <fstream>
#include <cassert>
#include "picojson.h"
#include "stb_image.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <wordexp.h>
#endif
using namespace tinygltf;
namespace {
bool FileExists(const std::string &abs_filename) {
bool ret;
FILE *fp = fopen(abs_filename.c_str(), "rb");
if (fp) {
ret = true;
fclose(fp);
} else {
ret = false;
}
return ret;
}
std::string ExpandFilePath(const std::string &filepath) {
#ifdef _WIN32
uint32 len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
char *str = new char[len];
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
std::string s(str);
delete[] str;
return s;
#else
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
// no expansion
std::string s = filepath;
#else
std::string s;
wordexp_t p;
if (filepath.empty()) {
return "";
}
// char** w;
int ret = wordexp(filepath.c_str(), &p, 0);
if (ret) {
// err
s = filepath;
return s;
}
// Use first element only.
if (p.we_wordv) {
s = std::string(p.we_wordv[0]);
wordfree(&p);
} else {
s = filepath;
}
#endif
return s;
#endif
}
std::string JoinPath(const std::string &path0, const std::string &path1) {
if (path0.empty()) {
return path1;
} else {
// check '/'
char lastChar = *path0.rbegin();
if (lastChar != '/') {
return path0 + std::string("/") + path1;
} else {
return path0 + path1;
}
}
}
std::string FindFile(const std::vector<std::string> &paths,
const std::string &filepath) {
for (size_t i = 0; i < paths.size(); i++) {
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
if (FileExists(absPath)) {
return absPath;
}
}
return std::string();
}
// std::string GetFilePathExtension(const std::string& FileName)
//{
// if(FileName.find_last_of(".") != std::string::npos)
// return FileName.substr(FileName.find_last_of(".")+1);
// return "";
//}
std::string GetBaseDir(const std::string &filepath) {
if (filepath.find_last_of("/\\") != std::string::npos)
return filepath.substr(0, filepath.find_last_of("/\\"));
return "";
}
// std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const &s);
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
//#include "base64.h"
//#include <iostream>
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
#if 0
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
#endif
std::string base64_decode(std::string const &encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') &&
is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_];
in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] =
(char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] =
((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++)
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] =
((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
}
return ret;
}
bool LoadExternalFile(std::vector<unsigned char> &out, std::string &err,
const std::string &filename, const std::string &basedir,
size_t reqBytes, bool checkSize) {
out.clear();
std::vector<std::string> paths;
paths.push_back(basedir);
paths.push_back(".");
std::string filepath = FindFile(paths, filename);
if (filepath.empty()) {
err += "File not found : " + filename;
return false;
}
std::ifstream f(filepath.c_str(), std::ifstream::binary);
if (!f) {
err += "File open error : " + filepath;
return false;
}
f.seekg(0, f.end);
size_t sz = f.tellg();
std::vector<unsigned char> buf(sz);
f.seekg(0, f.beg);
f.read(reinterpret_cast<char *>(&buf.at(0)), sz);
f.close();
if (checkSize) {
if (reqBytes == sz) {
out.swap(buf);
return true;
} else {
std::stringstream ss;
ss << "File size mismatch : " << filepath << ", requestedBytes "
<< reqBytes << ", but got " << sz << std::endl;
err += ss.str();
return false;
}
}
out.swap(buf);
return true;
}
bool IsDataURI(const std::string &in) {
std::string header = "data:application/octet-stream;base64,";
if (in.find(header) == 0) {
return true;
}
header = "data:image/png;base64,";
if (in.find(header) == 0) {
return true;
}
header = "data:image/jpeg;base64,";
if (in.find(header) == 0) {
return true;
}
return false;
}
bool DecodeDataURI(std::vector<unsigned char> &out, const std::string &in,
size_t reqBytes, bool checkSize) {
std::string header = "data:application/octet-stream;base64,";
std::string data;
if (in.find(header) == 0) {
data = base64_decode(in.substr(header.size())); // cut mime string.
}
if (data.empty()) {
header = "data:image/jpeg;base64,";
if (in.find(header) == 0) {
data = base64_decode(in.substr(header.size())); // cut mime string.
}
}
if (data.empty()) {
header = "data:image/png;base64,";
if (in.find(header) == 0) {
data = base64_decode(in.substr(header.size())); // cut mime string.
}
}
if (data.empty()) {
return false;
}
if (checkSize) {
if (data.size() != reqBytes) {
return false;
}
out.resize(reqBytes);
} else {
out.resize(data.size());
}
std::copy(data.begin(), data.end(), out.begin());
return true;
return false;
}
bool ParseBooleanProperty(bool &ret, std::string &err,
const picojson::object &o,
const std::string &property, bool required) {
picojson::object::const_iterator it = o.find(property);
if (it == o.end()) {
if (required) {
err += "'" + property + "' property is missing.\n";
}
return false;
}
if (!it->second.is<bool>()) {
if (required) {
err += "'" + property + "' property is not a bool type.\n";
}
return false;
}
ret = it->second.get<bool>();
return true;
}
bool ParseNumberProperty(double &ret, std::string &err,
const picojson::object &o, const std::string &property,
bool required) {
picojson::object::const_iterator it = o.find(property);
if (it == o.end()) {
if (required) {
err += "'" + property + "' property is missing.\n";
}
return false;
}
if (!it->second.is<double>()) {
if (required) {
err += "'" + property + "' property is not a number type.\n";
}
return false;
}
ret = it->second.get<double>();
return true;
}
bool ParseNumberArrayProperty(std::vector<double> &ret, std::string &err,
const picojson::object &o,
const std::string &property, bool required) {
picojson::object::const_iterator it = o.find(property);
if (it == o.end()) {
if (required) {
err += "'" + property + "' property is missing.\n";
}
return false;
}
if (!it->second.is<picojson::array>()) {
if (required) {
err += "'" + property + "' property is not an array.\n";
}
return false;
}
ret.clear();
const picojson::array &arr = it->second.get<picojson::array>();
for (size_t i = 0; i < arr.size(); i++) {
if (!arr[i].is<double>()) {
if (required) {
err += "'" + property + "' property is not a number.\n";
}
return false;
}
ret.push_back(arr[i].get<double>());
}
return true;
}
bool ParseStringProperty(std::string &ret, std::string &err,
const picojson::object &o, const std::string &property,
bool required) {
picojson::object::const_iterator it = o.find(property);
if (it == o.end()) {
if (required) {
err += "'" + property + "' property is missing.\n";
}
return false;
}
if (!it->second.is<std::string>()) {
if (required) {
err += "'" + property + "' property is not a string type.\n";
}
return false;
}
ret = it->second.get<std::string>();
return true;
}
bool ParseStringArrayProperty(std::vector<std::string> &ret, std::string &err,
const picojson::object &o,
const std::string &property, bool required) {
picojson::object::const_iterator it = o.find(property);
if (it == o.end()) {
if (required) {
err += "'" + property + "' property is missing.\n";
}
return false;
}
if (!it->second.is<picojson::array>()) {
if (required) {
err += "'" + property + "' property is not an array.\n";
}
return false;
}
ret.clear();
const picojson::array &arr = it->second.get<picojson::array>();
for (size_t i = 0; i < arr.size(); i++) {
if (!arr[i].is<std::string>()) {
if (required) {
err += "'" + property + "' property is not a string.\n";
}
return false;
}
ret.push_back(arr[i].get<std::string>());
}
return true;
}
bool ParseAsset(Asset &asset, std::string &err, const picojson::object &o) {
ParseStringProperty(asset.generator, err, o, "generator", false);
ParseBooleanProperty(asset.premultipliedAlpha, err, o, "premultipliedAlpha",
false);
ParseStringProperty(asset.version, err, o, "version", false);
picojson::object::const_iterator profile = o.find("profile");
if (profile != o.end()) {
const picojson::value &v = profile->second;
if (v.contains("api") & v.get("api").is<std::string>()) {
asset.profile_api = v.get("api").get<std::string>();
}
if (v.contains("version") & v.get("version").is<std::string>()) {
asset.profile_version = v.get("version").get<std::string>();
}
}
return true;
}
bool ParseImage(Image &image, std::string &err, const picojson::object &o,
const std::string &basedir) {
std::string uri;
if (!ParseStringProperty(uri, err, o, "uri", true)) {
return false;
}
ParseStringProperty(image.name, err, o, "name", false);
std::vector<unsigned char> img;
if (IsDataURI(uri)) {
if (!DecodeDataURI(img, uri, 0, false)) {
err += "Failed to decode 'uri'.\n";
return false;
}
} else {
// Assume external file
if (!LoadExternalFile(img, err, uri, basedir, 0, false)) {
err += "Failed to load external 'uri'.\n";
return false;
}
if (img.empty()) {
err += "File is empty.\n";
return false;
}
}
int w, h, comp;
unsigned char *data =
stbi_load_from_memory(&img.at(0), img.size(), &w, &h, &comp, 0);
if (!data) {
err += "Unknown image format.\n";
return false;
}
if (w < 1 || h < 1) {
err += "Unknown image format.\n";
return false;
}
image.width = w;
image.height = h;
image.component = comp;
image.image.resize(w * h * comp);
std::copy(data, data + w * h * comp, image.image.begin());
return true;
}
bool ParseTexture(Texture &texture, std::string &err, const picojson::object &o,
const std::string &basedir) {
if (!ParseStringProperty(texture.sampler, err, o, "sampler", true)) {
return false;
}
if (!ParseStringProperty(texture.source, err, o, "source", true)) {
return false;
}
ParseStringProperty(texture.name, err, o, "name", false);
double format = TINYGLTF_TEXTURE_FORMAT_RGBA;
ParseNumberProperty(format, err, o, "format", false);
double internalFormat = TINYGLTF_TEXTURE_FORMAT_RGBA;
ParseNumberProperty(internalFormat, err, o, "internalFormat", false);
double target = TINYGLTF_TEXTURE_TARGET_TEXTURE2D;
ParseNumberProperty(target, err, o, "target", false);
double type = TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE;
ParseNumberProperty(type, err, o, "type", false);
texture.format = static_cast<int>(format);
texture.internalFormat = static_cast<int>(internalFormat);
texture.target = static_cast<int>(target);
texture.type = static_cast<int>(type);
return true;
}
bool ParseBuffer(Buffer &buffer, std::string &err, const picojson::object &o,
const std::string &basedir) {
double byteLength;
if (!ParseNumberProperty(byteLength, err, o, "byteLength", true)) {
return false;
}
std::string uri;
if (!ParseStringProperty(uri, err, o, "uri", true)) {
return false;
}
picojson::object::const_iterator type = o.find("type");
if (type != o.end()) {
if (type->second.is<std::string>()) {
const std::string &ty = (type->second).get<std::string>();
if (ty.compare("arraybuffer") == 0) {
// buffer.type = "arraybuffer";
}
}
}
size_t bytes = static_cast<size_t>(byteLength);
if (IsDataURI(uri)) {
if (!DecodeDataURI(buffer.data, uri, bytes, true)) {
err += "Failed to decode 'uri'.\n";
return false;
}
} else {
// Assume external .bin file.
if (!LoadExternalFile(buffer.data, err, uri, basedir, bytes, true)) {
return false;
}
}
ParseStringProperty(buffer.name, err, o, "name", false);
return true;
}
bool ParseBufferView(BufferView &bufferView, std::string &err,
const picojson::object &o) {
std::string buffer;
if (!ParseStringProperty(buffer, err, o, "buffer", true)) {
return false;
}
double byteOffset;
if (!ParseNumberProperty(byteOffset, err, o, "byteOffset", true)) {
return false;
}
double byteLength = 0.0;
ParseNumberProperty(byteLength, err, o, "byteLength", false);
double target = 0.0;
ParseNumberProperty(target, err, o, "target", false);
int targetValue = static_cast<int>(target);
if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) ||
(targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
// OK
} else {
targetValue = 0;
}
bufferView.target = targetValue;
ParseStringProperty(bufferView.name, err, o, "name", false);
bufferView.buffer = buffer;
bufferView.byteOffset = static_cast<size_t>(byteOffset);
bufferView.byteLength = static_cast<size_t>(byteLength);
return true;
}
bool ParseAccessor(Accessor &accessor, std::string &err,
const picojson::object &o) {
std::string bufferView;
if (!ParseStringProperty(bufferView, err, o, "bufferView", true)) {
return false;
}
double byteOffset;
if (!ParseNumberProperty(byteOffset, err, o, "byteOffset", true)) {
return false;
}
double componentType;
if (!ParseNumberProperty(componentType, err, o, "componentType", true)) {
return false;
}
double count = 0.0;
if (!ParseNumberProperty(count, err, o, "count", true)) {
return false;
}
std::string type;
if (!ParseStringProperty(type, err, o, "type", true)) {
return false;
}
if (type.compare("SCALAR") == 0) {
accessor.type = TINYGLTF_TYPE_SCALAR;
} else if (type.compare("VEC2") == 0) {
accessor.type = TINYGLTF_TYPE_VEC2;
} else if (type.compare("VEC3") == 0) {
accessor.type = TINYGLTF_TYPE_VEC3;
} else if (type.compare("VEC4") == 0) {
accessor.type = TINYGLTF_TYPE_VEC4;
} else if (type.compare("MAT2") == 0) {
accessor.type = TINYGLTF_TYPE_MAT2;
} else if (type.compare("MAT3") == 0) {
accessor.type = TINYGLTF_TYPE_MAT3;
} else if (type.compare("MAT4") == 0) {
accessor.type = TINYGLTF_TYPE_MAT4;
} else {
std::stringstream ss;
ss << "Unsupported `type` for accessor object. Got \"" << type << "\"\n";
err += ss.str();
return false;
}
double byteStride = 0.0;
ParseNumberProperty(byteStride, err, o, "byteStride", false);
ParseStringProperty(accessor.name, err, o, "name", false);
accessor.minValues.clear();
accessor.maxValues.clear();
ParseNumberArrayProperty(accessor.minValues, err, o, "min", false);
ParseNumberArrayProperty(accessor.maxValues, err, o, "max", false);
accessor.count = static_cast<size_t>(count);
accessor.bufferView = bufferView;
accessor.byteOffset = static_cast<size_t>(byteOffset);
accessor.byteStride = static_cast<size_t>(byteStride);
{
int comp = static_cast<size_t>(componentType);
if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE &&
comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
// OK
accessor.componentType = comp;
} else {
std::stringstream ss;
ss << "Invalid `componentType` in accessor. Got " << comp << "\n";
err += ss.str();
return false;
}
}
return true;
}
bool ParsePrimitive(Primitive &primitive, std::string &err,
const picojson::object &o) {
if (!ParseStringProperty(primitive.material, err, o, "material", true)) {
return false;
}
double mode = static_cast<double>(TINYGLTF_MODE_TRIANGLES);
ParseNumberProperty(mode, err, o, "mode", false);
int primMode = static_cast<int>(mode);
if (primMode != TINYGLTF_MODE_TRIANGLES) {
err += "Currently TinyGLTFLoader doesn not support primitive mode other \n"
"than TRIANGLES.\n";
return false;
}
primitive.mode = primMode;
primitive.indices = "";
ParseStringProperty(primitive.indices, err, o, "indices", false);
primitive.attributes.clear();
picojson::object::const_iterator attribsObject = o.find("attributes");
if ((attribsObject != o.end()) &&
(attribsObject->second).is<picojson::object>()) {
const picojson::object &attribs =
(attribsObject->second).get<picojson::object>();
picojson::object::const_iterator it(attribs.begin());
picojson::object::const_iterator itEnd(attribs.end());
for (; it != itEnd; it++) {
const std::string &name = it->first;
if (!(it->second).is<std::string>()) {
err += "attribute expects string value.\n";
return false;
}
const std::string &value = (it->second).get<std::string>();
primitive.attributes[name] = value;
}
}
return true;
}
bool ParseMesh(Mesh &mesh, std::string &err, const picojson::object &o) {
ParseStringProperty(mesh.name, err, o, "name", false);
mesh.primitives.clear();
picojson::object::const_iterator primObject = o.find("primitives");
if ((primObject != o.end()) && (primObject->second).is<picojson::array>()) {
const picojson::array &primArray =
(primObject->second).get<picojson::array>();
for (size_t i = 0; i < primArray.size(); i++) {
Primitive primitive;
ParsePrimitive(primitive, err, primArray[i].get<picojson::object>());
mesh.primitives.push_back(primitive);
}
}
return true;
}
bool ParseNode(Node &node, std::string &err, const picojson::object &o) {
ParseStringProperty(node.name, err, o, "name", false);
ParseNumberArrayProperty(node.rotation, err, o, "rotation", false);
ParseNumberArrayProperty(node.scale, err, o, "scale", false);
ParseNumberArrayProperty(node.translation, err, o, "translation", false);
ParseNumberArrayProperty(node.matrix, err, o, "matrix", false);
ParseStringArrayProperty(node.meshes, err, o, "meshes", false);
node.children.clear();
picojson::object::const_iterator childrenObject = o.find("children");
if ((childrenObject != o.end()) &&
(childrenObject->second).is<picojson::array>()) {
const picojson::array &childrenArray =
(childrenObject->second).get<picojson::array>();
for (size_t i = 0; i < childrenArray.size(); i++) {
Node node;
if (!childrenArray[i].is<std::string>()) {
err += "Invalid `children` array.\n";
return false;
}
const std::string &childrenNode = childrenArray[i].get<std::string>();
node.children.push_back(childrenNode);
}
}
return true;
}
bool ParseMaterial(Material &material, std::string &err,
const picojson::object &o) {
ParseStringProperty(material.name, err, o, "name", false);
ParseStringProperty(material.technique, err, o, "technique", false);
material.values.clear();
picojson::object::const_iterator valuesIt = o.find("values");
if ((valuesIt != o.end()) && (valuesIt->second).is<picojson::object>()) {
const picojson::object &valuesObject =
(valuesIt->second).get<picojson::object>();
picojson::object::const_iterator it(valuesObject.begin());
picojson::object::const_iterator itEnd(valuesObject.end());
for (; it != itEnd; it++) {
// Assume number values.
Parameter param;
if (ParseStringProperty(param.stringValue, err, valuesObject, it->first,
false)) {
// Found string property.
} else if (!ParseNumberArrayProperty(param.numberArray, err, valuesObject,
it->first, false)) {
// Fallback to numer property.
double value;
if (ParseNumberProperty(value, err, valuesObject, it->first, false)) {
param.numberArray.push_back(value);
}
}
material.values[it->first] = param;
}
}
return true;
}
}
bool TinyGLTFLoader::LoadFromString(Scene &scene, std::string &err,
const char *str, unsigned int length,
const std::string &baseDir) {
picojson::value v;
std::string perr = picojson::parse(v, str, str + length);
if (!perr.empty()) {
err = perr;
return false;
}
if (v.contains("scene") && v.get("scene").is<std::string>()) {
// OK
} else {
err += "\"scene\" object not found in .gltf\n";
return false;
}
if (v.contains("scenes") && v.get("scenes").is<picojson::object>()) {
// OK
} else {
err += "\"scenes\" object not found in .gltf\n";
return false;
}
if (v.contains("nodes") && v.get("nodes").is<picojson::object>()) {
// OK
} else {
err += "\"nodes\" object not found in .gltf\n";
return false;
}
if (v.contains("accessors") && v.get("accessors").is<picojson::object>()) {
// OK
} else {
err += "\"accessors\" object not found in .gltf\n";
return false;
}
if (v.contains("buffers") && v.get("buffers").is<picojson::object>()) {
// OK
} else {
err += "\"buffers\" object not found in .gltf\n";
return false;
}
if (v.contains("bufferViews") &&
v.get("bufferViews").is<picojson::object>()) {
// OK
} else {
err += "\"bufferViews\" object not found in .gltf\n";
return false;
}
scene.buffers.clear();
scene.bufferViews.clear();
scene.accessors.clear();
scene.meshes.clear();
scene.nodes.clear();
scene.defaultScene = "";
// 0. Parse Asset
if (v.contains("asset") && v.get("asset").is<picojson::object>()) {
const picojson::object &root = v.get("asset").get<picojson::object>();
ParseAsset(scene.asset, err, root);
}
// 1. Parse Buffer
if (v.contains("buffers") && v.get("buffers").is<picojson::object>()) {
const picojson::object &root = v.get("buffers").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Buffer buffer;
if (!ParseBuffer(buffer, err, (it->second).get<picojson::object>(),
baseDir)) {
return false;
}
scene.buffers[it->first] = buffer;
}
}
// 2. Parse BufferView
if (v.contains("bufferViews") &&
v.get("bufferViews").is<picojson::object>()) {
const picojson::object &root = v.get("bufferViews").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
BufferView bufferView;
if (!ParseBufferView(bufferView, err,
(it->second).get<picojson::object>())) {
return false;
}
scene.bufferViews[it->first] = bufferView;
}
}
// 3. Parse Accessor
if (v.contains("accessors") && v.get("accessors").is<picojson::object>()) {
const picojson::object &root = v.get("accessors").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Accessor accessor;
if (!ParseAccessor(accessor, err, (it->second).get<picojson::object>())) {
return false;
}
scene.accessors[it->first] = accessor;
}
}
// 4. Parse Mesh
if (v.contains("meshes") && v.get("meshes").is<picojson::object>()) {
const picojson::object &root = v.get("meshes").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Mesh mesh;
if (!ParseMesh(mesh, err, (it->second).get<picojson::object>())) {
return false;
}
scene.meshes[it->first] = mesh;
}
}
// 5. Parse Node
if (v.contains("nodes") && v.get("nodes").is<picojson::object>()) {
const picojson::object &root = v.get("nodes").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Node node;
if (!ParseNode(node, err, (it->second).get<picojson::object>())) {
return false;
}
scene.nodes[it->first] = node;
}
}
// 6. Parse scenes.
if (v.contains("scenes") && v.get("scenes").is<picojson::object>()) {
const picojson::object &root = v.get("scenes").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
const picojson::object &o = (it->second).get<picojson::object>();
std::vector<std::string> nodes;
if (!ParseStringArrayProperty(nodes, err, o, "nodes", false)) {
return false;
}
scene.scenes[it->first] = nodes;
}
}
// 7. Parse default scenes.
if (v.contains("scene") && v.get("scene").is<std::string>()) {
const std::string defaultScene = v.get("scene").get<std::string>();
scene.defaultScene = defaultScene;
}
// 8. Parse Material
if (v.contains("materials") && v.get("materials").is<picojson::object>()) {
const picojson::object &root = v.get("materials").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Material material;
if (!ParseMaterial(material, err, (it->second).get<picojson::object>())) {
return false;
}
scene.materials[it->first] = material;
}
}
// 9. Parse Image
if (v.contains("images") && v.get("images").is<picojson::object>()) {
const picojson::object &root = v.get("images").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Image image;
if (!ParseImage(image, err, (it->second).get<picojson::object>(),
baseDir)) {
return false;
}
scene.images[it->first] = image;
}
}
// 9. Parse Texture
if (v.contains("textures") && v.get("textures").is<picojson::object>()) {
const picojson::object &root = v.get("textures").get<picojson::object>();
picojson::object::const_iterator it(root.begin());
picojson::object::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
Texture texture;
if (!ParseTexture(texture, err, (it->second).get<picojson::object>(),
baseDir)) {
return false;
}
scene.textures[it->first] = texture;
}
}
return true;
}
bool TinyGLTFLoader::LoadFromFile(Scene &scene, std::string &err,
const std::string &filename) {
std::stringstream ss;
std::ifstream f(filename.c_str());
if (!f) {
ss << "Failed to open file: " << filename << std::endl;
err = ss.str();
return false;
}
f.seekg(0, f.end);
size_t sz = f.tellg();
std::vector<char> buf(sz);
f.seekg(0, f.beg);
f.read(&buf.at(0), sz);
f.close();
std::string basedir = GetBaseDir(filename);
bool ret = LoadFromString(scene, err, &buf.at(0), buf.size(), basedir);
return ret;
}
#endif // TINYGLTF_LOADER_IMPLEMENTATION
#endif // TINY_GLTF_LOADER_H
Copyright (c) 2016, Syoyo Fujita
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
// Fill out your copyright notice in the Description page of Project Settings.
#include "MasterTestProject.h"
#include "GLTFDisplay.h"
// Sets default values
AGLTFDisplay::AGLTFDisplay()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
static ConstructorHelpers::FObjectFinder<UStaticMeshComponent> StaticMeshComp(TEXT("/Game/Content/Duck"));
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
//CreateDefaultSubobject<StaticMesComponent>()
//StaticMeshComponent = CreateDefaultSubobject<StaticMeshComp.Object->StaticClass()>(RootComponent, NAME_None);
//StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("GLTFComponent"));
//newObject, duplicateObject
//if (StaticMeshComp.Succeeded()) {
//}
UE_LOG(LogTemp, Warning, TEXT("Object is %d"), StaticMeshComp.Object);
originalGLTFImport = StaticMeshComp.Object;
if(originalGLTFImport != nullptr)
originalGLTFImport->SetupAttachment(RootComponent);
// StaticMeshComponent->SetVisibility(true);
// StaticMeshComponent->SetHiddenInGame(false);
StaticGLTFComponent = CreateDefaultSubobject<UStaticGLTFComponent>(TEXT("GLTFComponent"));
StaticGLTFComponent->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
void AGLTFDisplay::BeginPlay()
{
Super::BeginPlay();
FVector zero = FVector(0);
//StaticMeshComponent->RegisterComponent();
//StaticMeshComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
//StaticMeshComponent->SetupAttachment(RootComponent);
if (!originalGLTFImport->IsRegistered()) {
//originalGLTFImport->RegisterComponent();
}
originalGLTFImport->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
StaticMeshComponentCopy = DuplicateObject<UStaticMeshComponent>(originalGLTFImport, this);
if (!StaticMeshComponentCopy->IsRegistered()) {
StaticMeshComponentCopy->RegisterComponent();
}
StaticMeshComponentCopy->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
StaticMeshComponentCopy->SetRelativeLocation(FVector(100.f));
StaticGLTFComponent->SetRelativeLocation(FVector(-100.f));
SetActorLocation(zero, false);
}
// Called every frame
void AGLTFDisplay::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "GLTF/StaticGLTFComponent.h"
#include "GLTFDisplay.generated.h"
UCLASS()
class MASTERTESTPROJECT_API AGLTFDisplay : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AGLTFDisplay();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly)
UStaticMeshComponent *originalGLTFImport;
UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly)
UStaticMeshComponent *StaticMeshComponentCopy;
UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly)
UStaticGLTFComponent *StaticGLTFComponent;
};
......@@ -17,15 +17,15 @@ public class MasterTestProject : ModuleRules
}
public MasterTestProject(TargetInfo Target)
{
public MasterTestProject(ReadOnlyTargetRules Target) : base (Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ImageWrapper", "RawMesh", "HTTP", "Json", "JsonUtilities", "ProceduralMeshComponent", "RHI", "RenderCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
LoadAssimp(Target);
LoadAMQP(Target);
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
......@@ -36,7 +36,7 @@ public class MasterTestProject : ModuleRules
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
public bool LoadAssimp(TargetInfo Target)
public bool LoadAssimp(ReadOnlyTargetRules Target)
{
bool isLibrarySupported = false;
......@@ -74,6 +74,46 @@ public class MasterTestProject : ModuleRules
return isLibrarySupported;
}
public bool LoadAMQP(ReadOnlyTargetRules Target)
{
bool isLibrarySupported = false;
if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))
{
isLibrarySupported = true;
// string PlatformString = (Target.Platform == UnrealTargetPlatform.Win64) ? "x64" : "x86";
string LibrariesPath = Path.Combine("H:\\Repositories\\rabbitmq-c\\vs17\\librabbitmq\\Debug");
// string dllPath = Path.Combine(ThirdPartyPath, "assimp", "bin", "Debug");
//test your path with:
//using System; Console.WriteLine("");
Console.WriteLine(".. Target {0}", Target.Platform);
Console.WriteLine("... LibrariesPath -> " + LibrariesPath);
// Console.WriteLine("... DLLPath -> " + dllPath);
PublicLibraryPaths.Add(LibrariesPath);
//PublicLibraryPaths.Add(dllPath);
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "rabbitmq.4.lib"));// + PlatformString + ".lib"));
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "librabbitmq.4.lib"));// + PlatformString + ".lib"));
//sPublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "zlibstaticd.lib"));
// PublicDelayLoadDLLs.Add(Path.Combine(dllPath, "assimp-vc140-mt.dll"));
}
if (isLibrarySupported)
{
// Include path
PublicIncludePaths.Add(Path.Combine("H:\\Repositories\\rabbitmq-c\\librabbitmq"));
}
Definitions.Add(string.Format("WITH_RABBITMQ_BINDING={0}", isLibrarySupported ? 1 : 0));
return isLibrarySupported;
}
public bool LoadAssimp2(TargetInfo Target)
{
bool isLibrarySupported = false;
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "MasterTestProject.h"
#include "MyGameInstance.h"
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "RabbitMQConnection.h"
#include "MyGameInstance.generated.h"
/**
*
*/
UCLASS()
class MASTERTESTPROJECT_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
URabbitMQConnection* connection = nullptr;
};
......@@ -48,9 +48,9 @@ void APointCloudActor::setPoints(UTexture2D* PointCloud, FVector pos, FVector sc
}
void APointCloudActor::setColors(UTexture2D* Colors) {
Material->SetTextureParameterValue(FName("Colors"), Colors);
this->Colors = Colors;
void APointCloudActor::setColors(UTexture2D* ColorsTexture) {
Material->SetTextureParameterValue(FName("Colors"), ColorsTexture);
this->Colors = ColorsTexture;
StaticMeshComponent->SetMaterial(0, Material);
}
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "MasterTestProject.h"
#include "RabbitMQConnection.h"
URabbitMQConnection::URabbitMQConnection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
char const *hostname = "10.1.7.49";
int port = 5672;
conn = amqp_new_connection();
socket = amqp_tcp_socket_new(conn);
if (!socket) {
UE_LOG(TILES, Error, TEXT("No RabbitMQ Socket"));
}
int status = amqp_socket_open(socket, hostname, port);
if (status) {
UE_LOG(TILES, Error, TEXT("Cann not Open Socket"));
}
amqp_rpc_reply_t returncode = amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest");
if (AMQP_RESPONSE_NORMAL != returncode.reply_type) {
UE_LOG(TILES, Error, TEXT("Unable to Login"));
}
amqp_channel_open(conn, 1);
returncode = amqp_get_rpc_reply(conn);
if (AMQP_RESPONSE_NORMAL != returncode.reply_type) {
UE_LOG(TILES, Error, TEXT("Opening channel error"));
}
success = true;
}
URabbitMQConnection::~URabbitMQConnection()
{
if (!success) {
return;
}
amqp_rpc_reply_t returncode = amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
if (AMQP_RESPONSE_NORMAL != returncode.reply_type) {
UE_LOG(TILES, Error, TEXT("Closing channel error"));
}
returncode = amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
if (AMQP_RESPONSE_NORMAL != returncode.reply_type) {
UE_LOG(TILES, Error, TEXT("Closing connection error"));
}
int errorcode = amqp_destroy_connection(conn);
if (errorcode != 0) {
UE_LOG(TILES, Error, TEXT("Ending AMQP error"));
}
}
bool URabbitMQConnection::publishMessage(char const * Message)
{
if (!success){
UE_LOG(TILES, Warning, TEXT("Cant send Messsage, no Connection"));
return false;
}
char const *exchange = "";
char const *routingkey = "to_hololense";
// char const *messagebody = "{\"timestamp\":15.600000381469727,\"start\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"end\":{\"x\":1.0,\"y\":5.0,\"z\":16.0}}";
amqp_basic_properties_t props;
props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
props.content_type = amqp_cstring_bytes("text/plain");
props.delivery_mode = 2; /* persistent delivery mode */
int errorcode = amqp_basic_publish(conn,
1,
amqp_cstring_bytes(exchange),
amqp_cstring_bytes(routingkey),
0,
0,
&props,
amqp_cstring_bytes(Message));
if (errorcode != 0) {
UE_LOG(TILES, Error, TEXT("Publishing error"));
}
//UE_LOG(TILES, Warning, TEXT("Published Message %s"), Message);
return true;
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include <amqp_tcp_socket.h>
#include <amqp.h>
#include <amqp_framing.h>
#include "RabbitMQConnection.generated.h"
/**
*
*/
UCLASS()
class MASTERTESTPROJECT_API URabbitMQConnection : public UObject
{
GENERATED_BODY()
public:
bool success = false;
amqp_socket_t *socket = NULL;
amqp_connection_state_t conn;
URabbitMQConnection(const FObjectInitializer& ObjectInitializer);
~URabbitMQConnection();
bool publishMessage(char const * Message);
protected:
};
......@@ -426,14 +426,14 @@ void ATilesetActor::parsePointCloudTile(const TArray<uint8> data, FTile * tile)
UTexture2D* ColorTexture = nullptr;
if (FeatureTableJSON->HasField("RGB")) {
// RGB = uint8[3]
uint32 featureTableBinaryOffset = pntheader->getFeatureStart() + pntheader->featureTable.featureTableJSONByteLength;
TSharedPtr<FJsonObject> binaryBodyReference = FeatureTableJSON->GetObjectField("RGB");
int32 byteOffset = binaryBodyReference->GetIntegerField("byteOffset");
uint8* start = (uint8*)(data.GetData() + pntheader->getFeatureBinaryStart() + byteOffset);
featureTableBinaryOffset = pntheader->getFeatureStart() + pntheader->featureTable.featureTableJSONByteLength;
binaryBodyReference = FeatureTableJSON->GetObjectField("RGB");
byteOffset = binaryBodyReference->GetIntegerField("byteOffset");
start = (uint8*)(data.GetData() + pntheader->getFeatureBinaryStart() + byteOffset);
// creat pooint texture
TArray<FLinearColor> *ColorRGB = new TArray<FLinearColor>();
uint8* pos = start;
pos = start;
for (size_t i = 0; i < instances_length; i += 1)
{
FLinearColor temp = FLinearColor((*pos) / 255.0, (*(pos + 1)) / 255.0, (*(pos + 2)) / 255.0, 1.0F);
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "MasterTestProject.h"
#include "MyGameInstance.h"
#include "VRPawnCode.h"
// Sets default values
AVRPawnCode::AVRPawnCode()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AVRPawnCode::BeginPlay()
{
Super::BeginPlay();
UMyGameInstance *gameinstance = Cast<UMyGameInstance>(GetGameInstance());
if (gameinstance != nullptr && !gameinstance->connection) {
gameinstance->connection = NewObject<URabbitMQConnection>();
}
char const *messagebody = "{\"timestamp\":15.600000381469727,\"start\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"end\":{\"x\":1.0,\"y\":5.0,\"z\":16.0}}";
}
// Called every frame
void AVRPawnCode::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AVRPawnCode::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AVRPawnCode::PublishMessage(FVector start, FVector end)
{
UMyGameInstance *gameinstance = Cast<UMyGameInstance>(GetGameInstance());
FString Message = FString::Printf(TEXT("{\"timestamp\":%d,\"start\":{\"x\":%f,\"y\":%f,\"z\":%f},\"end\":{\"x\":%f,\"y\":%f,\"z\":%f}}"), 0.0f, start.X, start.Y, start.Z, end.X, end.Y, end.Z);
UE_LOG(TILES, Warning, TEXT("Published Message %s"), *Message);
gameinstance->connection->publishMessage(TCHAR_TO_ANSI(*Message));
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "RabbitMQConnection.h"
#include "VRPawnCode.generated.h"
UCLASS()
class MASTERTESTPROJECT_API AVRPawnCode : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AVRPawnCode();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION(BlueprintCallable, Category = "RabbitMQ")
void PublishMessage(FVector start, FVector end);
};
......@@ -5,21 +5,10 @@ using System.Collections.Generic;
public class MasterTestProjectEditorTarget : TargetRules
{
public MasterTestProjectEditorTarget(TargetInfo Target)
{
public MasterTestProjectEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
}
ExtraModuleNames.Add("MasterTestProject");
}
//
// TargetRules interface.
//
public override void SetupBinaries(
TargetInfo Target,
ref List<UEBuildBinaryConfiguration> OutBuildBinaryConfigurations,
ref List<string> OutExtraModuleNames
)
{
OutExtraModuleNames.AddRange( new string[] { "MasterTestProject" } );
}
}
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