Browse Source

Adding JSON scene import to ToolCore

Josh Engebretson 10 years ago
parent
commit
e45feeec02

+ 997 - 0
Source/ToolCore/Import/JSONSceneImporter.cpp

@@ -0,0 +1,997 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#include "AtomicEditor.h"
+#include <rapidjson/document.h>
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/prettywriter.h>
+
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/File.h>
+#include "JSONSceneImporter.h"
+
+using namespace rapidjson;
+
+namespace AtomicEditor
+{
+
+static unsigned char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int _base64Decode(const unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len )
+{
+    static char inalphabet[256], decoder[256];
+    int i, bits, c = 0, char_count, errors = 0;
+    unsigned int input_idx = 0;
+    unsigned int output_idx = 0;
+
+    for (i = (sizeof alphabet) - 1; i >= 0 ; i--) {
+        inalphabet[alphabet[i]] = 1;
+        decoder[alphabet[i]] = i;
+    }
+
+    char_count = 0;
+    bits = 0;
+    for( input_idx=0; input_idx < input_len ; input_idx++ ) {
+        c = input[ input_idx ];
+        if (c == '=')
+            break;
+        if (c > 255 || ! inalphabet[c])
+            continue;
+        bits += decoder[c];
+        char_count++;
+        if (char_count == 4) {
+            output[ output_idx++ ] = (bits >> 16);
+            output[ output_idx++ ] = ((bits >> 8) & 0xff);
+            output[ output_idx++ ] = ( bits & 0xff);
+            bits = 0;
+            char_count = 0;
+        } else {
+            bits <<= 6;
+        }
+    }
+
+    if( c == '=' ) {
+        switch (char_count) {
+        case 1:
+            errors++;
+            break;
+        case 2:
+            output[ output_idx++ ] = ( bits >> 10 );
+            break;
+        case 3:
+            output[ output_idx++ ] = ( bits >> 16 );
+            output[ output_idx++ ] = (( bits >> 8 ) & 0xff);
+            break;
+        }
+    } else if ( input_idx < input_len ) {
+        if (char_count) {
+            errors++;
+        }
+    }
+
+    *output_len = output_idx;
+    return errors;
+}
+
+bool JSONComponent::Parse(const rapidjson::Value& value)
+{
+    for (Value::ConstMemberIterator oitr = value.MemberBegin();
+         oitr != value.MemberEnd(); ++oitr)
+    {
+        if (!strcmp(oitr->name.GetString(), "enabled"))
+        {
+            enabled_ = oitr->value.IsTrue();
+        }
+    }
+
+    return true;
+
+}
+
+JSONTransform::JSONTransform(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "Transform")
+{
+
+    JSONComponent::Parse(value);
+
+    for (Value::ConstMemberIterator oitr = value.MemberBegin();
+         oitr != value.MemberEnd(); ++oitr)
+    {
+        if (!strcmp(oitr->name.GetString(), "localPosition"))
+        {
+            importer->ReadVector3FromArray(oitr->value, localPosition_);
+        }
+        else if (!strcmp(oitr->name.GetString(), "localScale"))
+        {
+            importer->ReadVector3FromArray(oitr->value, localScale_);
+        }
+        else if (!strcmp(oitr->name.GetString(), "localRotation"))
+        {
+            importer->ReadQuaternionFromArray(oitr->value, localRotation_);
+        }
+    }
+}
+
+
+JSONMeshRenderer::JSONMeshRenderer(JSONSceneImporter* importer, const rapidjson::Value& value, const char* type) :
+    JSONComponent(importer, type)
+  , mesh_(0)
+  , castShadows_(false)
+  , receiveShadows_(false)
+  , lightmapIndex_(-1)
+{
+    JSONComponent::Parse(value);
+
+    for (Value::ConstMemberIterator oitr = value.MemberBegin();
+         oitr != value.MemberEnd(); ++oitr)
+    {
+        if (!strcmp(oitr->name.GetString(), "mesh"))
+        {
+            mesh_ = importer->GetMesh(oitr->value.GetString());
+        }
+        else if (!strcmp(oitr->name.GetString(), "castShadows"))
+        {
+            castShadows_ = oitr->value.IsTrue();
+        }
+        else if (!strcmp(oitr->name.GetString(), "receiveShadows"))
+        {
+            receiveShadows_ = oitr->value.IsTrue();
+        }
+        else if (!strcmp(oitr->name.GetString(), "lightmapIndex"))
+        {
+            lightmapIndex_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "lightmapTilingOffset"))
+        {
+            importer->ReadVector4FromArray(oitr->value, lightmapTilingOffset_);
+        }
+        else if (!strcmp(oitr->name.GetString(), "materials"))
+        {
+            for (Value::ConstValueIterator mitr = oitr->value.Begin(); mitr != oitr->value.End(); mitr++)
+            {
+                JSONMaterial* material = importer->GetMaterial((*mitr).GetString());
+                assert(material);
+                materials_.Push(material);
+            }
+
+        }
+    }
+}
+
+JSONSkinnedMeshRenderer::JSONSkinnedMeshRenderer(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONMeshRenderer(importer, value, "SkinnedMeshRenderer")
+{
+
+}
+
+JSONAnimation::JSONAnimation(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "Animation")
+{
+    JSONComponent::Parse(value);
+
+    const Value::Member* jclips = value.FindMember("clips");
+
+    assert(jclips);
+
+    for (Value::ConstValueIterator clipitr = jclips->value.Begin(); clipitr != jclips->value.End(); clipitr++)
+    {
+        const Value::Member* clipname = clipitr->FindMember("name");
+        const Value::Member* clipnodes = clipitr->FindMember("nodes");
+
+        AnimationClip* aclip = new AnimationClip();
+        aclip->name_ = clipname->value.GetString();
+
+        for (Value::ConstValueIterator nodeitr = clipnodes->value.Begin(); nodeitr != clipnodes->value.End(); nodeitr++)
+        {
+            AnimationNode* node = new AnimationNode();
+            const Value::Member* nodename = nodeitr->FindMember("name");
+            const Value::Member* keyframes = nodeitr->FindMember("keyframes");
+
+            node->name_ = nodename->value.GetString();
+
+            for (Value::ConstValueIterator keyitr = keyframes->value.Begin(); keyitr != keyframes->value.End(); keyitr++)
+            {
+                Keyframe* keyframe = new Keyframe();
+
+                const Value::Member* jpos = keyitr->FindMember("pos");
+                const Value::Member* jscale = keyitr->FindMember("scale");
+                const Value::Member* jrot = keyitr->FindMember("rot");
+                const Value::Member* jtime = keyitr->FindMember("time");
+
+                keyframe->time_ = (float) jtime->value.GetDouble();
+                importer_->ReadVector3FromArray(jpos->value, keyframe->pos_);
+                importer_->ReadVector3FromArray(jscale->value, keyframe->scale_);
+                importer_->ReadQuaternionFromArray(jrot->value, keyframe->rot_);
+
+                node->keyframes_.Push(keyframe);
+            }
+
+            aclip->nodes_.Push(node);
+
+        }
+
+        clips_.Push(aclip);
+
+    }
+
+}
+
+JSONTimeOfDay::JSONTimeOfDay(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "TimeOfDay"),
+    timeOn_(0),
+    timeOff_(0)
+{
+    JSONComponent::Parse(value);
+
+    const Value::Member* jtimeOn = value.FindMember("timeOn");
+    if (jtimeOn)
+        timeOn_ = (float) jtimeOn->value.GetDouble();
+
+    const Value::Member* jtimeOff = value.FindMember("timeOff");
+    if (jtimeOff)
+        timeOff_ = (float) jtimeOff->value.GetDouble();
+}
+
+JSONLight::JSONLight(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "Light"),
+    lightType_("Point"),
+    range_(10),
+    color_(1, 1, 1, 1),
+    castsShadows_(false),
+    realtime_(false)
+{
+    JSONComponent::Parse(value);
+
+    const Value::Member* jlightType = value.FindMember("lightType");
+    if (jlightType)
+        lightType_ = jlightType->value.GetString();
+
+    const Value::Member* jrange = value.FindMember("range");
+    if (jrange)
+        range_ = (float) jrange->value.GetDouble();
+
+    const Value::Member* jcolor = value.FindMember("color");
+    if (jcolor)
+        importer->ReadColorFromArray(jcolor->value, color_);
+
+    const Value::Member* jcastsShadows = value.FindMember("castsShadows");
+    if (jcastsShadows)
+        castsShadows_ = jcastsShadows->value.GetBool();
+
+    const Value::Member* jrealtime = value.FindMember("realtime");
+    if (jrealtime)
+        realtime_ = jrealtime->value.GetBool();
+}
+
+
+JSONRigidBody::JSONRigidBody(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "RigidBody"),
+    mass_(0)
+{
+    JSONComponent::Parse(value);
+
+    const Value::Member* jmass = value.FindMember("mass");
+    if (jmass)
+        mass_ = (float) jmass->value.GetDouble();
+}
+
+
+JSONMeshCollider::JSONMeshCollider(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "MeshCollider")
+{
+    JSONComponent::Parse(value);
+
+}
+
+JSONBoxCollider::JSONBoxCollider(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "BoxCollider")
+{
+    JSONComponent::Parse(value);
+
+    const Value::Member* jcenter= value.FindMember("center");
+    if (jcenter)
+        importer->ReadVector3FromArray(jcenter->value, center_);
+
+    const Value::Member* jsize= value.FindMember("size");
+    if (jsize)
+        importer->ReadVector3FromArray(jsize->value, size_);
+}
+
+JSONTerrain::JSONTerrain(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "Terrain")
+  , heightmapHeight_(0)
+  , heightmapWidth_(0)
+  , heightmapResolution_(0)
+  , alphamapWidth_(0)
+  , alphamapHeight_(0)
+  , alphamapLayers_(0)
+  , alphaMapLength_(0)
+  , heightMapLength_(0)
+{
+    JSONComponent::Parse(value);
+
+    String base64Height;
+    String base64Alpha;
+
+    for (Value::ConstMemberIterator oitr = value.MemberBegin();
+         oitr != value.MemberEnd(); ++oitr)
+    {
+        if (!strcmp(oitr->name.GetString(), "heightmapHeight"))
+        {
+            heightmapHeight_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "heightmapWidth"))
+        {
+            heightmapWidth_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "heightmapResolution"))
+        {
+            heightmapResolution_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "alphamapWidth"))
+        {
+            alphamapWidth_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "alphamapHeight"))
+        {
+            alphamapHeight_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "alphamapLayers"))
+        {
+            alphamapLayers_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "base64HeightLength"))
+        {
+            heightMapLength_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "base64AlphaLength"))
+        {
+            alphaMapLength_ = oitr->value.GetInt();
+        }
+        else if (!strcmp(oitr->name.GetString(), "base64Height"))
+        {
+            base64Height = oitr->value.GetString();
+        }
+        else if (!strcmp(oitr->name.GetString(), "base64Alpha"))
+        {
+            base64Alpha = oitr->value.GetString();
+        }
+        else if (!strcmp(oitr->name.GetString(), "heightmapScale"))
+        {
+            importer->ReadVector3FromArray(oitr->value, heightmapScale_);
+        }
+        else if (!strcmp(oitr->name.GetString(), "size"))
+        {
+            importer->ReadVector3FromArray(oitr->value, size_);
+        }
+
+    }
+
+    heightMap_ = new float[heightMapLength_];
+    alphaMap_ = new float[alphaMapLength_];
+
+    unsigned int length = 0;
+    int errors;
+
+    errors = _base64Decode((const unsigned char*)base64Height.CString(), base64Height.Length(), (unsigned char*) heightMap_.Get(), &length);
+
+    assert(!errors);
+    assert(length == heightMapLength_);
+
+    length = 0;
+
+    errors = _base64Decode((const unsigned char*)base64Alpha.CString(), base64Alpha.Length(),  (unsigned char*) alphaMap_.Get(), &length);
+
+    assert(!errors);
+    assert(length == alphaMapLength_);
+
+}
+
+JSONCamera::JSONCamera(JSONSceneImporter* importer, const rapidjson::Value& value) :
+    JSONComponent(importer, "Camera")
+{
+    JSONComponent::Parse(value);
+}
+
+JSONNode::JSONNode(JSONSceneImporter* importer, const rapidjson::Value& value) : importer_(importer)
+
+{
+    for (Value::ConstMemberIterator oitr = value.MemberBegin();
+         oitr != value.MemberEnd(); ++oitr)
+    {
+        if (!strcmp(oitr->name.GetString(), "name"))
+        {
+            name_ = oitr->value.GetString();
+        }
+        else if (!strcmp(oitr->name.GetString(), "children"))
+        {
+            for (Value::ConstValueIterator citr = oitr->value.Begin(); citr != oitr->value.End(); citr++)
+            {
+                if (!(*citr).IsObject())
+                    continue;
+
+                AddChild(new JSONNode(importer, *citr));
+            }
+        }
+        else if (!strcmp(oitr->name.GetString(), "components"))
+        {
+            for (Value::ConstValueIterator citr = oitr->value.Begin(); citr != oitr->value.End(); citr++)
+            {
+                if (!(*citr).IsObject())
+                    continue;
+
+                const Value::Member* jtype = citr->FindMember("type");
+
+                if (!jtype)
+                    continue;
+
+                String type = jtype->value.GetString();
+
+                if (type == "Transform")
+                {
+                    components_.Push(new JSONTransform(importer_, *citr));
+                }
+                else if (type == "MeshRenderer")
+                {
+                    components_.Push(new JSONMeshRenderer(importer_, *citr));
+                }
+                else if (type == "SkinnedMeshRenderer")
+                {
+                    components_.Push(new JSONSkinnedMeshRenderer(importer_, *citr));
+                }
+                else if (type == "Animation")
+                {
+                    components_.Push(new JSONAnimation(importer_, *citr));
+                }
+                else if (type == "Camera")
+                {
+                    components_.Push(new JSONCamera(importer_, *citr));
+                }
+                else if (type == "Terrain")
+                {
+                    components_.Push(new JSONTerrain(importer_, *citr));
+                }
+                else if (type == "RigidBody")
+                {
+                    components_.Push(new JSONRigidBody(importer_, *citr));
+                }
+                else if (type == "MeshCollider")
+                {
+                    components_.Push(new JSONMeshCollider(importer_, *citr));
+                }
+                else if (type == "BoxCollider")
+                {
+                    components_.Push(new JSONBoxCollider(importer_, *citr));
+                }
+                else if (type == "Light")
+                {
+                    components_.Push(new JSONLight(importer_, *citr));
+                }
+                else if (type == "TimeOfDay")
+                {
+                    components_.Push(new JSONTimeOfDay(importer_, *citr));
+                }
+
+            }
+        }
+    }
+}
+
+JSONSceneImporter::JSONSceneImporter(Context* context) : Importer(context)
+  , document_(new Document())
+
+{
+
+}
+
+void JSONSceneImporter::ReadColorFromArray(const rapidjson::Value& value, Color& color)
+{
+    if (!value.IsArray() || (value.Size() < 3 || value.Size() > 4))
+        return;
+
+    color.r_ = color.g_ = color.b_ = color.a_ = 1.0f;
+
+    color.r_ = (float) value[SizeType(0)].GetDouble();
+    color.g_ = (float) value[SizeType(1)].GetDouble();
+    color.b_ = (float) value[SizeType(2)].GetDouble();
+    if (value.Size() ==  4)
+        color.a_ = (float) value[SizeType(3)].GetDouble();
+
+}
+
+void JSONSceneImporter::ReadVector2FromArray(const rapidjson::Value& value, Vector2& v)
+{
+    if (!value.IsArray() || value.Size() != 2)
+        return;
+
+    v.x_ = (float) value[SizeType(0)].GetDouble();
+    v.y_ = (float) value[SizeType(1)].GetDouble();
+
+}
+
+void JSONSceneImporter::ReadVector3FromArray(const rapidjson::Value& value, Vector3& v)
+{
+    if (!value.IsArray() || value.Size() != 3)
+        return;
+
+    v.x_ = (float) value[SizeType(0)].GetDouble();
+    v.y_ = (float) value[SizeType(1)].GetDouble();
+    v.z_ = (float) value[SizeType(2)].GetDouble();
+}
+
+void JSONSceneImporter::ReadVector4FromArray(const rapidjson::Value& value, Vector4& v)
+{
+    if (!value.IsArray() || value.Size() != 4)
+        return;
+
+    v.x_ = (float) value[SizeType(0)].GetDouble();
+    v.y_ = (float) value[SizeType(1)].GetDouble();
+    v.z_ = (float) value[SizeType(2)].GetDouble();
+    v.w_ = (float) value[SizeType(3)].GetDouble();
+}
+
+void JSONSceneImporter::ReadQuaternionFromArray(const rapidjson::Value& value, Quaternion& q)
+{
+    if (!value.IsArray() || value.Size() != 4)
+        return;
+
+    q.x_ = (float) value[SizeType(0)].GetDouble();
+    q.y_ = (float) value[SizeType(1)].GetDouble();
+    q.z_ = (float) value[SizeType(2)].GetDouble();
+    q.w_ = (float) value[SizeType(3)].GetDouble();
+
+}
+
+void JSONSceneImporter::ReadMatrix4FromArray(const rapidjson::Value& value, Matrix4& m)
+{
+    if (!value.IsArray() || value.Size() != 16)
+        return;
+
+    float mf[16];
+    for (SizeType i = 0; i < 16; i++)
+        mf[i] = (float) value[i].GetDouble();
+
+    m = Matrix4(mf);
+
+}
+
+
+bool JSONSceneImporter::ParseMaterials(const rapidjson::Value& value)
+{
+    const Value::Member* jmaterials = value.FindMember("materials");
+    if (jmaterials && jmaterials->value.IsArray())
+    {
+        for (Value::ConstValueIterator itr = jmaterials->value.Begin(); itr != jmaterials->value.End(); itr++)
+        {
+            if ((*itr).IsObject())
+            {
+                String name = "Anonymous Material";
+                String shader;
+                String mainTexture;
+                Vector2 mainTextureOffset(0.0f, 0.0f);
+                Vector2 mainTextureScale(1.0f, 1.0f);
+                int passCount = 1;
+                int renderQueue = 0;
+                Color color(1, 1, 1, 1);
+
+                for (Value::ConstMemberIterator oitr = (*itr).MemberBegin();
+                     oitr != (*itr).MemberEnd(); ++oitr)
+                {
+
+                    if (!strcmp(oitr->name.GetString(), "name"))
+                    {
+                        name = oitr->value.GetString();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "shader"))
+                    {
+                        shader = oitr->value.GetString();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "mainTexture"))
+                    {
+                        mainTexture = oitr->value.GetString();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "mainTextureOffset"))
+                    {
+                        ReadVector2FromArray(oitr->value, mainTextureOffset);
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "mainTextureScale"))
+                    {
+                        ReadVector2FromArray(oitr->value, mainTextureScale);
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "renderQueue"))
+                    {
+                        renderQueue = oitr->value.GetInt();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "passCount"))
+                    {
+                        passCount = oitr->value.GetInt();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "color"))
+                    {
+                        ReadColorFromArray(oitr->value, color);
+                    }
+                }
+
+                JSONMaterial* material = new JSONMaterial(name);
+
+                material->SetColor(color);
+                material->SetMainTexture(mainTexture);
+                material->SetMainTextureOffset(mainTextureOffset);
+                material->SetMainTextureScale(mainTextureScale);
+                material->SetPassCount(passCount);
+                material->SetRenderQueue(renderQueue);
+                material->SetShader(shader);
+
+                AddMaterial(material);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseMeshes(const rapidjson::Value& value)
+{
+    const Value::Member* jmeshes = value.FindMember("meshes");
+    if (jmeshes && jmeshes->value.IsArray())
+    {
+        for (Value::ConstValueIterator itr = jmeshes->value.Begin(); itr != jmeshes->value.End(); itr++)
+        {
+            if ((*itr).IsObject())
+            {
+                JSONMesh* mesh = new JSONMesh("Anonymous Mesh");
+
+                for (Value::ConstMemberIterator oitr = (*itr).MemberBegin();
+                     oitr != (*itr).MemberEnd(); ++oitr)
+                {
+
+                    if (!strcmp(oitr->name.GetString(), "name"))
+                    {
+                        mesh->SetName(oitr->value.GetString());
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "triangles"))
+                    {
+                        if (oitr->value.IsArray())
+                        {
+                            for (Value::ConstValueIterator triangleArrayItr = oitr->value.Begin();
+                                 triangleArrayItr != oitr->value.End(); triangleArrayItr++)
+                            {
+                                PODVector<int>& triangles = mesh->AddSubMesh();
+
+                                for (Value::ConstValueIterator vertexItr = triangleArrayItr->Begin();
+                                     vertexItr != triangleArrayItr->End(); vertexItr++)
+                                {
+                                    triangles.Push((*vertexItr).GetInt());
+                                }
+
+                            }
+                        }
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "vertexPositions"))
+                    {
+                        Vector3 pos;
+                        PODVector<Vector3>& vpos = mesh->GetVertexPositions();
+                        for (Value::ConstValueIterator vertexItr = oitr->value.Begin();
+                             vertexItr != oitr->value.End(); vertexItr++)
+                        {
+
+                            ReadVector3FromArray(*vertexItr, pos);
+                            vpos.Push(pos);
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "vertexNormals"))
+                    {
+                        Vector3 pos;
+                        PODVector<Vector3>& vnorm = mesh->GetVertexNormals();
+                        for (Value::ConstValueIterator vertexItr = oitr->value.Begin();
+                             vertexItr != oitr->value.End(); vertexItr++)
+                        {
+
+                            ReadVector3FromArray(*vertexItr, pos);
+                            vnorm.Push(pos);
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "vertexTangents"))
+                    {
+                        Vector4 tangent;
+                        PODVector<Vector4>& vtangents = mesh->GetVertexTangents();
+                        for (Value::ConstValueIterator vertexItr = oitr->value.Begin();
+                             vertexItr != oitr->value.End(); vertexItr++)
+                        {
+
+                            ReadVector4FromArray(*vertexItr, tangent);
+                            vtangents.Push(tangent);
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "boneWeights"))
+                    {
+                        PODVector<JSONMesh::BoneWeight>& boneWeights = mesh->GetBoneWeights();
+
+                        for (Value::ConstValueIterator bitr = oitr->value.Begin();
+                             bitr != oitr->value.End(); bitr++)
+                        {
+                            JSONMesh::BoneWeight bw;
+                            const Value::Member* indexes = bitr->FindMember("indexes");
+                            const Value::Member* weights = bitr->FindMember("weights");
+
+                            for (int i = 0; i < 4; i++)
+                            {
+                                bw.indexes_[i] = indexes->value[SizeType(i)].GetInt();
+                                bw.weights_[i] = (float) weights->value[SizeType(i)].GetDouble();
+                            }
+
+                            boneWeights.Push(bw);
+
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "rootBone"))
+                    {
+                        mesh->SetRootBone(oitr->value.GetString());
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "bindPoses"))
+                    {
+                        Vector<Matrix4>& bindPoses = mesh->GetBindPoses();
+
+                        for (Value::ConstValueIterator bitr = oitr->value.Begin();
+                             bitr != oitr->value.End(); bitr++)
+                        {
+                            Matrix4 m;
+                            ReadMatrix4FromArray(*bitr, m);
+                            bindPoses.Push(m);
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "bones"))
+                    {
+                        Vector<JSONMesh::Bone>& bones = mesh->GetBones();
+
+                        if (!oitr->value.IsNull())
+                        {
+                            for (Value::ConstValueIterator bitr = oitr->value.Begin();
+                                 bitr != oitr->value.End(); bitr++)
+                            {
+                                const Value::Member* pos = bitr->FindMember("localPosition");
+                                const Value::Member* rot = bitr->FindMember("localRotation");
+                                const Value::Member* scale = bitr->FindMember("localScale");
+                                const Value::Member* name = bitr->FindMember("name");
+                                const Value::Member* parentName = bitr->FindMember("parentName");
+
+                                JSONMesh::Bone bone;
+
+                                ReadVector3FromArray(pos->value, bone.pos_);
+                                ReadVector3FromArray(scale->value, bone.scale_);
+                                ReadQuaternionFromArray(rot->value, bone.rot_);
+                                bone.name_ = name->value.GetString();
+                                bone.parentName_ = parentName->value.GetString();
+
+                                bones.Push(bone);
+                            }
+                        }
+
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "vertexUV") ||
+                             !strcmp(oitr->name.GetString(), "vertexUV2"))
+                    {
+                        Vector2 uv;
+                        PODVector<Vector2>& uvs = !strcmp(oitr->name.GetString(), "vertexUV") ?
+                                    mesh->GetUVSet(0) : mesh->GetUVSet(1);
+
+                        for (Value::ConstValueIterator uvItr = oitr->value.Begin();
+                             uvItr != oitr->value.End(); uvItr++)
+                        {
+
+                            ReadVector2FromArray(*uvItr, uv);
+                            uvs.Push(uv);
+                        }
+
+                    }
+
+                }
+
+                AddMesh(mesh);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseShaders(const rapidjson::Value& value)
+{
+    const Value::Member* jshaders = value.FindMember("shaders");
+    if (jshaders && jshaders->value.IsArray())
+    {
+        for (Value::ConstValueIterator itr = jshaders->value.Begin(); itr != jshaders->value.End(); itr++)
+        {
+            if ((*itr).IsObject())
+            {
+                String name = "Anonymous Shader";
+                int renderQueue = 0;
+
+                for (Value::ConstMemberIterator oitr = (*itr).MemberBegin();
+                     oitr != (*itr).MemberEnd(); ++oitr)
+                {
+                    if (!strcmp(oitr->name.GetString(), "name"))
+                    {
+                        name = oitr->value.GetString();
+                    }
+                    else if (!strcmp(oitr->name.GetString(), "renderQueue"))
+                    {
+                        renderQueue = oitr->value.GetInt();
+                    }
+
+                }
+
+                AddShader(new JSONShader(name, renderQueue));
+            }
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseTextures(const rapidjson::Value& value)
+{
+    const Value::Member* jtextures = value.FindMember("textures");
+    if (jtextures && jtextures->value.IsArray())
+    {
+        for (Value::ConstValueIterator itr = jtextures->value.Begin(); itr != jtextures->value.End(); itr++)
+        {
+            String name;
+            String base64PNG;
+            int base64PNGLength = 0;
+
+            if ((*itr).IsObject())
+            {
+                const Value::Member* jname = (*itr).FindMember("name");
+                if (jname && jname->value.IsString())
+                {
+                    name = jname->value.GetString();
+                }
+                const Value::Member* jbase64PNG = (*itr).FindMember("base64PNG");
+                if (jbase64PNG)
+                {
+                    base64PNG = jbase64PNG->value.GetString();
+                }
+                const Value::Member* jbase64PNGLength = (*itr).FindMember("base64PNGLength");
+                if (jbase64PNGLength)
+                {
+                    base64PNGLength = jbase64PNGLength->value.GetInt();
+                }
+
+            }
+
+            SharedArrayPtr<unsigned char> pngPixels;
+            pngPixels = new unsigned char[base64PNGLength];
+
+            unsigned int length = 0;
+            int errors = _base64Decode((const unsigned char*)base64PNG.CString(), base64PNG.Length(), pngPixels.Get(), &length);
+
+            assert(!errors);
+            assert(length == base64PNGLength);
+
+            JSONTexture* texture = new JSONTexture(name);
+            texture->SetPNGPixels(pngPixels, base64PNGLength);
+            AddTexture(texture);
+
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseLightmaps(const rapidjson::Value& value)
+{
+    const Value::Member* jlightmaps = value.FindMember("lightmaps");
+    if (jlightmaps && jlightmaps->value.IsArray())
+    {
+        for (Value::ConstValueIterator itr = jlightmaps->value.Begin(); itr != jlightmaps->value.End(); itr++)
+        {
+            String name;
+            String base64PNG;
+            int base64PNGLength = 0;
+
+            if ((*itr).IsObject())
+            {
+                const Value::Member* jname = (*itr).FindMember("filename");
+                if (jname && jname->value.IsString())
+                {
+                    name = jname->value.GetString();
+                }
+                const Value::Member* jbase64PNG = (*itr).FindMember("base64PNG");
+                if (jbase64PNG)
+                {
+                    base64PNG = jbase64PNG->value.GetString();
+                }
+                const Value::Member* jbase64PNGLength = (*itr).FindMember("base64PNGLength");
+                if (jbase64PNGLength)
+                {
+                    base64PNGLength = jbase64PNGLength->value.GetInt();
+                }
+
+            }
+
+            SharedArrayPtr<unsigned char> pngPixels;
+            pngPixels = new unsigned char[base64PNGLength];
+
+            unsigned int length = 0;
+            int errors = _base64Decode((const unsigned char*)base64PNG.CString(), base64PNG.Length(), pngPixels.Get(), &length);
+
+            assert(!errors);
+            assert(length == base64PNGLength);
+
+            JSONLightmap* lightmap = new JSONLightmap(name);
+            lightmap->SetPNGPixels(pngPixels, base64PNGLength);
+            AddLightmap(lightmap);
+
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseResources(const rapidjson::Value& value)
+{
+
+    ParseTextures(value);
+    ParseLightmaps(value);
+    ParseShaders(value);
+    ParseMaterials(value);
+    ParseMeshes(value);
+
+    return true;
+}
+
+bool JSONSceneImporter::ParseHierarchy(const rapidjson::Value& value)
+{
+    for (Value::ConstValueIterator itr = value.Begin(); itr != value.End(); itr++)
+    {
+        if ((*itr).IsObject())
+        {
+            hierarchy_.Push(new JSONNode(this, *itr));
+        }
+    }
+
+    return true;
+}
+
+bool JSONSceneImporter::Import(const String& path)
+{
+    File jsonFile(context_, path);
+
+    String json;
+
+    jsonFile.ReadText(json);
+
+    if (document_->Parse<0>(json.CString()).HasParseError())
+    {
+        LOGERRORF("Could not parse JSON data from %s", path.CString());
+        return false;
+    }
+    const Value::Member* name = document_->FindMember("name");
+    if (name)
+        sceneName_ = name->value.GetString();
+
+    const Value::Member* jresources = document_->FindMember("resources");
+    if (jresources)
+        ParseResources(jresources->value);
+
+    const Value::Member* jhierarchy = document_->FindMember("hierarchy");
+    if (jhierarchy)
+        ParseHierarchy(jhierarchy->value);
+
+    return true;
+}
+
+JSONSceneImporter::~JSONSceneImporter()
+{
+    if (document_)
+        delete document_;
+}
+
+}

+ 934 - 0
Source/ToolCore/Import/JSONSceneImporter.h

@@ -0,0 +1,934 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#pragma once
+
+#include <Atomic/Container/List.h>
+#include <Atomic/Core/Object.h>
+
+using namespace Atomic;
+
+namespace rapidjson
+{
+template<typename CharType> struct UTF8;
+class CrtAllocator;
+template <typename BaseAllocator> class MemoryPoolAllocator;
+template <typename Encoding, typename Allocator> class GenericValue;
+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
+template <typename Encoding, typename Allocator> class GenericDocument;
+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Document;
+}
+
+
+namespace AtomicEditor
+{
+
+class JSONSceneImporter;
+
+class JSONResource
+{
+public:
+
+    void SetName(const String& name)
+    {
+        name_ = name;
+    }
+
+    const String& GetName() const
+    {
+        return name_;
+    }
+
+
+protected:
+    JSONResource(String name) : name_(name) {}
+
+private:
+
+    String name_;
+
+};
+
+class JSONTexture : public JSONResource
+{
+public:
+
+    JSONTexture(const String& name) : JSONResource(name)
+    {
+
+    }
+
+    unsigned char* GetPNGPixels(unsigned& length) const
+    {
+        length = length_;
+        return pngPixels_.Get();
+    }
+
+
+    void SetPNGPixels(SharedArrayPtr<unsigned char>& pngPixels, unsigned length)
+    {
+        length_ = length;
+        pngPixels_ = pngPixels;
+    }
+
+
+private:
+
+    SharedArrayPtr<unsigned char> pngPixels_;
+    unsigned length_;
+};
+
+class JSONLightmap : public JSONResource
+{
+public:
+
+    JSONLightmap(const String& name) : JSONResource(name)
+    {
+
+    }
+
+    unsigned char* GetPNGPixels(unsigned& length) const
+    {
+        length = length_;
+        return pngPixels_.Get();
+    }
+
+
+    void SetPNGPixels(SharedArrayPtr<unsigned char>& pngPixels, unsigned length)
+    {
+        length_ = length;
+        pngPixels_ = pngPixels;
+    }
+
+
+private:
+
+    SharedArrayPtr<unsigned char> pngPixels_;
+    unsigned length_;
+};
+
+
+class JSONShader: public JSONResource
+{
+public:
+
+    JSONShader(const String& name, int renderQueue) :
+        JSONResource(name), renderQueue_(renderQueue)
+    {
+
+    }
+
+private:
+
+    int renderQueue_;
+
+};
+
+class JSONMaterial : public JSONResource
+{
+public:
+
+    JSONMaterial(const String& name) :
+        JSONResource(name),
+        mainTextureOffset_(0.0f, 0.0f),
+        mainTextureScale_(1.0f, 1.0f),
+        passCount_(1),
+        color_(1, 1, 1, 1),
+        renderQueue_(0)
+    {
+
+    }
+
+    const String& GetShader() const
+    {
+        return shader_;
+    }
+
+    void SetShader(const String& shader)
+    {
+        shader_ = shader;
+    }
+
+    const String& GetMainTexture() const
+    {
+        return mainTexture_;
+    }
+
+    void SetMainTexture(const String& mainTexture)
+    {
+        mainTexture_ = mainTexture;
+    }
+
+    void SetMainTextureOffset(const Vector2& offset)
+    {
+        mainTextureOffset_ = offset;
+    }
+
+    void SetMainTextureScale(const Vector2& scale)
+    {
+        mainTextureScale_ = scale;
+    }
+
+    void SetColor(const Color& color)
+    {
+        color_ = color;
+    }
+
+    void SetPassCount(int count)
+    {
+        passCount_ = count;
+    }
+
+    void SetRenderQueue(int renderQueue)
+    {
+        renderQueue_ = renderQueue;
+    }
+
+private:
+
+    String shader_;
+    String mainTexture_;
+    Vector2 mainTextureOffset_;
+    Vector2 mainTextureScale_;
+    int passCount_;
+    Color color_;
+    int renderQueue_;
+    List<String> shaderKeywords_;
+};
+
+
+class JSONMesh : public JSONResource
+{
+public:
+
+    struct BoneWeight
+    {
+        int indexes_[4];
+        float weights_[4];
+    };
+
+    class Bone
+    {
+    public:
+        Vector3 pos_;
+        Vector3 scale_;
+        Quaternion rot_;
+        String name_;
+        String parentName_;
+    };
+
+    JSONMesh(const String& name) :
+        JSONResource(name)
+    {
+
+    }
+
+    PODVector<int>& AddSubMesh()
+    {
+        triangles_.Resize(triangles_.Size() + 1);
+        return triangles_.Back();
+    }
+
+    unsigned GetSubMeshCount()
+    {
+        return triangles_.Size();
+    }
+
+    PODVector<int>& GetSubMesh(unsigned index)
+    {
+        return triangles_.At(index);
+    }
+
+    unsigned GetVertexCount() const
+    {
+        return vertexPositions_.Size();
+    }
+
+    PODVector<Vector3>& GetVertexPositions()
+    {
+        return vertexPositions_;
+    }
+
+    PODVector<Vector3>& GetVertexNormals()
+    {
+        return vertexNormals_;
+    }
+
+    PODVector<Vector4>& GetVertexTangents()
+    {
+        return vertexTangents_;
+    }
+
+    unsigned GetNumUVSets() const
+    {
+        return vertexUV_.Size();
+    }
+
+    PODVector<Vector2>& GetUVSet(int idx)
+    {
+        while (vertexUV_.Size() <= idx)
+        {
+            AddUVSet();
+        }
+
+        return vertexUV_.At(idx);
+
+    }
+
+    PODVector<BoneWeight>& GetBoneWeights()
+    {
+        return boneWeights_;
+    }
+
+    Vector<Matrix4>& GetBindPoses()
+    {
+        return bindPoses_;
+    }
+
+    Vector<Bone>& GetBones()
+    {
+        return bones_;
+    }
+
+    const String& GetRootBone() const
+    {
+        return rootBone_;
+    }
+
+    void SetRootBone(const String& rootBone)
+    {
+        rootBone_ = rootBone;
+    }
+
+private:
+
+    PODVector<Vector2>& AddUVSet()
+    {
+        vertexUV_.Resize(vertexUV_.Size() + 1);
+        return vertexUV_.Back();
+    }
+
+
+    PODVector<Vector3> vertexPositions_;
+    PODVector<Vector3> vertexNormals_;
+    PODVector<Vector4> vertexTangents_;
+
+    Vector<PODVector<Vector2> > vertexUV_;
+
+    Vector<Matrix4> bindPoses_;
+    Vector<Bone> bones_;
+    PODVector<BoneWeight> boneWeights_;
+    String rootBone_;
+
+    //broken into submeshes
+    Vector<PODVector<int> > triangles_;
+
+};
+
+class JSONComponent
+{
+public:
+
+    const String& GetType() const
+    {
+        return type_;
+    }
+
+protected:
+
+    JSONComponent(JSONSceneImporter* importer, const String& type) : type_(type), enabled_(true)
+    {
+
+    }
+
+
+protected:
+
+    bool Parse(const rapidjson::Value& value);
+
+    String type_;
+    JSONSceneImporter* importer_;
+
+    bool enabled_;
+
+
+};
+
+class JSONTransform : public JSONComponent
+{
+public:
+
+    JSONTransform(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    const Vector3& GetLocalPosition() const
+    {
+        return localPosition_;
+    }
+    const Vector3& GetLocalScale() const
+    {
+        return localScale_;
+    }
+    const Quaternion& GetLocalRotation() const
+    {
+        return localRotation_;
+    }
+
+private:
+
+    Vector3 localPosition_;
+    Vector3 localScale_;
+    Quaternion localRotation_;
+};
+
+class JSONMeshRenderer: public JSONComponent
+{
+public:
+
+    JSONMeshRenderer(JSONSceneImporter* importer, const rapidjson::Value& value, const char *type = "MeshRenderer");
+
+    const JSONMesh* GetMesh() const
+    {
+        return mesh_;
+    }
+
+    bool GetCastShadows() const
+    {
+        return castShadows_;
+    }
+
+    bool GetReceiveShadows() const
+    {
+        return receiveShadows_;
+    }
+
+    unsigned GetNumMaterials() const
+    {
+        return materials_.Size();
+    }
+
+    const JSONMaterial* GetMaterial(unsigned index) const
+    {
+        return materials_.At(index);
+    }
+
+    int GetLightmapIndex() const
+    {
+        return lightmapIndex_;
+    }
+
+    const Vector4& GetLightmapTilingOffset() const
+    {
+        return lightmapTilingOffset_;
+    }
+
+protected:
+
+    JSONMesh* mesh_;
+    bool castShadows_;
+    bool receiveShadows_;
+    int lightmapIndex_;
+    Vector4 lightmapTilingOffset_;
+    PODVector<JSONMaterial*> materials_;
+
+};
+
+class JSONSkinnedMeshRenderer: public JSONMeshRenderer
+{
+public:
+
+    JSONSkinnedMeshRenderer(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+};
+
+class JSONTimeOfDay : public JSONComponent
+{
+public:
+
+    JSONTimeOfDay(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    float GetTimeOn() const
+    {
+        return timeOn_;
+    }
+
+    void SetTimeOn(float value)
+    {
+        timeOn_ = value;
+    }
+
+    float GetTimeOff() const
+    {
+        return timeOff_;
+    }
+
+    void SetTimeOff(float value)
+    {
+        timeOff_ = value;
+    }
+
+private:
+
+    float timeOn_;
+    float timeOff_;
+
+
+};
+
+
+class JSONLight : public JSONComponent
+{
+public:
+
+    JSONLight(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    float GetRange() const
+    {
+        return range_;
+    }
+
+    void SetRange(float range)
+    {
+        range_ = range;
+    }
+
+    void SetLightType(const String& lightType)
+    {
+        lightType_ = lightType;
+    }
+
+    const String& GetLightType() const
+    {
+        return lightType_;
+    }
+
+    void SetColor(const Color& color)
+    {
+        color_ = color;
+    }
+
+    const Color& GetColor() const
+    {
+        return color_;
+    }
+
+    void SetCastsShadows(bool castsShadows)
+    {
+        castsShadows_ = castsShadows;
+    }
+
+    bool GetCastsShadows() const
+    {
+        return castsShadows_;
+    }
+
+    void SetRealtime(bool realtime)
+    {
+        realtime_ = realtime;
+    }
+
+    bool GetRealtime() const
+    {
+        return realtime_;
+    }
+
+private:
+
+    String lightType_;
+    float range_;
+    Color color_;
+    bool castsShadows_;
+    bool realtime_;
+};
+
+
+class JSONRigidBody : public JSONComponent
+{
+public:
+
+    JSONRigidBody(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    float GetMass() const
+    {
+        return mass_;
+    }
+
+    void SetMass(float mass)
+    {
+        mass_ = mass;
+    }
+
+private:
+    float mass_;
+};
+
+class JSONMeshCollider : public JSONComponent
+{
+public:
+
+    JSONMeshCollider(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+};
+
+class JSONBoxCollider : public JSONComponent
+{
+public:
+
+    JSONBoxCollider(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    const Vector3& GetCenter() const
+    {
+        return center_;
+    }
+
+    const Vector3& GetSize() const
+    {
+        return size_;
+    }
+
+    void SetCenter(const Vector3& center)
+    {
+        center_ = center;
+    }
+
+    void SetSize(const Vector3& size)
+    {
+        size_ = size;
+    }
+
+private:
+    Vector3 center_;
+    Vector3 size_;
+};
+
+class JSONAnimation : public JSONComponent
+{
+public:
+
+    class Keyframe
+    {
+    public:
+        Vector3 pos_;
+        Vector3 scale_;
+        Quaternion rot_;
+        float time_;
+    };
+
+    class AnimationNode
+    {
+    public:
+        String name_;
+        Vector<Keyframe*> keyframes_;
+    };
+
+    class AnimationClip
+    {
+    public:
+        String name_;
+        Vector<AnimationNode*> nodes_;
+
+        float GetDuration() const
+        {
+            float maxTime = -1.0f;
+            for (unsigned i = 0 ; i < nodes_.Size(); i++)
+            {
+                if (nodes_[i]->keyframes_.Size())
+                    if (nodes_[i]->keyframes_.Back()->time_ > maxTime)
+                        maxTime = nodes_[i]->keyframes_.Back()->time_;
+            }
+
+            return maxTime;
+        }
+
+    };
+
+    const Vector<AnimationClip*>& GetClips() const
+    {
+        return clips_;
+    }
+
+    JSONAnimation(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+private:
+
+    Vector<AnimationClip*> clips_;
+
+};
+
+class JSONTerrain: public JSONComponent
+{
+public:
+
+    JSONTerrain(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    int GetHeightMapWidth() const
+    {
+        return heightmapWidth_;
+    }
+
+    int GetHeightMapHeight() const
+    {
+        return heightmapHeight_;
+    }
+
+    int GetHeightMapResolution() const
+    {
+        return heightmapResolution_;
+    }
+
+    const Vector3& GetHeightMapScale() const
+    {
+        return heightmapScale_;
+    }
+
+    const Vector3& GetHeightMapSize() const
+    {
+        return size_;
+    }
+
+    int GetAlphaMapWidth() const
+    {
+        return alphamapWidth_;
+    }
+
+    int GetAlphaMapHeight() const
+    {
+        return alphamapHeight_;
+    }
+
+    int GetAlphaMapLayers() const
+    {
+        return alphamapLayers_;
+    }
+
+    const float* GetHeightMap(unsigned& length) const
+    {
+        length = heightMapLength_;
+        return heightMap_.Get();
+    }
+
+    const float* GetAlphaMap(unsigned& length) const
+    {
+        length = alphaMapLength_;
+        return alphaMap_.Get();
+    }
+
+private:
+    int heightmapHeight_;
+    int heightmapWidth_;
+    int heightmapResolution_;
+
+    Vector3 heightmapScale_;
+    Vector3 size_;
+
+    int alphamapWidth_;
+    int alphamapHeight_;
+    int alphamapLayers_;
+
+    SharedArrayPtr<float> heightMap_;
+    unsigned heightMapLength_;
+    SharedArrayPtr<float> alphaMap_;
+    unsigned alphaMapLength_;
+
+};
+
+class JSONCamera: public JSONComponent
+{
+public:
+
+    JSONCamera(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+
+private:
+
+};
+
+
+class JSONNode
+{
+public:
+
+    JSONNode(JSONSceneImporter* importer, const rapidjson::Value& value);
+
+    const String& GetName() const
+    {
+        return name_;
+    }
+
+    const PODVector<JSONComponent*>& GetComponents() const
+    {
+        return components_;
+
+    }
+
+    const PODVector<JSONNode*>& GetChildren() const
+    {
+        return children_;
+    }
+
+    void AddChild(JSONNode* child)
+    {
+        children_.Push(child);
+    }
+
+private:
+
+    String name_;
+    JSONSceneImporter* importer_;
+
+    PODVector<JSONComponent*> components_;
+    PODVector<JSONNode*> children_;
+
+};
+
+
+class Importer: public Object
+{
+    OBJECT(Importer);
+
+public:
+
+    Importer(Context* context) : Object(context) {}
+
+private:
+
+};
+
+
+class JSONSceneImporter: public Importer
+{
+    OBJECT(JSONSceneImporter);
+
+public:
+
+    JSONSceneImporter(Context* context);
+
+    bool Import(const String& path);
+
+    void ReadVector2FromArray(const rapidjson::Value& value, Vector2& v);
+    void ReadVector3FromArray(const rapidjson::Value& value, Vector3& v);
+    void ReadVector4FromArray(const rapidjson::Value& value, Vector4& v);
+    void ReadQuaternionFromArray(const rapidjson::Value& value, Quaternion& q);
+    void ReadMatrix4FromArray(const rapidjson::Value& value, Matrix4& m);
+    void ReadColorFromArray(const rapidjson::Value& value, Color& color);
+
+    JSONMesh* GetMesh(const String& name)
+    {
+        for (unsigned i = 0; i < meshes_.Size(); i++)
+        {
+            if (meshes_[i]->GetName() == name)
+                return meshes_[i];
+        }
+
+        return NULL;
+    }
+
+    JSONMaterial* GetMaterial(const String& name)
+    {
+        for (unsigned i = 0; i < materials_.Size(); i++)
+        {
+            if (materials_[i]->GetName() == name)
+                return materials_[i];
+        }
+
+        return NULL;
+    }
+
+    const PODVector<JSONTexture*>& GetTexture()
+    {
+        return textures_;
+    }
+
+    const PODVector<JSONLightmap*>& GetLightmaps()
+    {
+        return lightmaps_;
+    }
+
+    const PODVector<JSONShader*>& GetShaders()
+    {
+        return shaders_;
+    }
+
+    const PODVector<JSONMaterial*>& GetMaterials()
+    {
+        return materials_;
+    }
+
+    const PODVector<JSONTexture*>& GetTextures()
+    {
+        return textures_;
+    }
+
+    const PODVector<JSONNode*>& GetHierarchy() const
+    {
+        return hierarchy_;
+    }
+
+
+    PODVector<JSONMesh*>& GetMeshes()
+    {
+        return meshes_;
+    }
+
+    const String& GetSceneName() const
+    {
+        return sceneName_;
+    }
+
+
+    virtual ~JSONSceneImporter();
+
+private:
+
+    void AddTexture(JSONTexture* texture)
+    {
+        textures_.Push(texture);
+    }
+
+    void AddLightmap(JSONLightmap* lightmap)
+    {
+        lightmaps_.Push(lightmap);
+    }
+
+    void AddShader(JSONShader* shader)
+    {
+        shaders_.Push(shader);
+    }
+
+    void AddMaterial(JSONMaterial* material)
+    {
+        materials_.Push(material);
+    }
+
+    void AddMesh(JSONMesh* mesh)
+    {
+        meshes_.Push(mesh);
+    }
+
+    bool ParseShaders(const rapidjson::Value& value);
+    bool ParseTextures(const rapidjson::Value& value);
+    bool ParseLightmaps(const rapidjson::Value& value);
+    bool ParseMaterials(const rapidjson::Value& value);
+    bool ParseMeshes(const rapidjson::Value& value);
+
+    bool ParseResources(const rapidjson::Value& value);
+
+    bool ParseHierarchy(const rapidjson::Value& value);
+
+    rapidjson::Document* document_;
+
+    String sceneName_;
+
+    PODVector<JSONTexture*> textures_;
+    PODVector<JSONLightmap*> lightmaps_;
+    PODVector<JSONShader*> shaders_;
+    PODVector<JSONMaterial*> materials_;
+    PODVector<JSONMesh*> meshes_;
+
+    PODVector<JSONNode*> hierarchy_;
+
+};
+
+
+
+}

+ 991 - 0
Source/ToolCore/Import/JSONSceneProcess.cpp

@@ -0,0 +1,991 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#include <stdint.h>
+
+#include "AtomicEditor.h"
+#include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/IO/Log.h>
+
+#include <Atomic/Resource/Image.h>
+
+#include <Atomic/Graphics/IndexBuffer.h>
+#include <Atomic/Graphics/VertexBuffer.h>
+#include <Atomic/Graphics/Geometry.h>
+
+#include <Atomic/Graphics/Octree.h>
+#include <Atomic/Graphics/Zone.h>
+#include <Atomic/Atomic3D/AnimatedModel.h>
+#include <Atomic/Atomic3D/StaticModel.h>
+#include <Atomic/Atomic3D/LMStaticModel.h>
+#include <Atomic/Atomic3D/Terrain.h>
+#include <Atomic/Atomic3D/Animation.h>
+#include <Atomic/Graphics/DebugRenderer.h>
+#include <Atomic/Physics/CollisionShape.h>
+#include <Atomic/Physics/RigidBody.h>
+#include <Atomic/Physics/PhysicsWorld.h>
+#include <Atomic/Environment/TimeOfDay.h>
+
+#include "JSONSceneProcess.h"
+#include "JSONSceneImporter.h"
+
+static String __rootFolder = "/Users/josh/Desktop/Test/Resources";
+
+namespace AtomicEditor
+{
+
+bool JSONSceneProcess::ProcessTextures()
+{
+    const PODVector<JSONTexture*>& textures = importer_->GetTextures();
+
+    for (unsigned i = 0; i < textures.Size(); i++)
+    {
+        const JSONTexture* jtexture = textures.At(i);
+
+        unsigned length;
+        const unsigned char* pixels = jtexture->GetPNGPixels(length);
+
+        String filename = __rootFolder + "/Textures/" + jtexture->GetName() + ".png";
+
+        SharedPtr<File> file (new File(context_, filename, FILE_WRITE));
+
+        file->Write(pixels, length);
+
+        file->Close();
+
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessLightmaps()
+{
+    const PODVector<JSONLightmap*>& lightmaps = importer_->GetLightmaps();
+
+    for (unsigned i = 0; i < lightmaps.Size(); i++)
+    {
+        const JSONLightmap* jlightmap = lightmaps.At(i);
+
+        unsigned length;
+        const unsigned char* pixels = jlightmap->GetPNGPixels(length);
+
+        String filename = __rootFolder + "/Textures/" + jlightmap->GetName() + ".png";
+
+        SharedPtr<File> file (new File(context_, filename, FILE_WRITE));
+
+        file->Write(pixels, length);
+
+        file->Close();
+
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessMaterials()
+{
+    const PODVector<JSONMaterial*>& materials = importer_->GetMaterials();
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    for (unsigned i = 0; i < materials.Size(); i++)
+    {
+        const JSONMaterial* jmaterial = materials.At(i);
+
+        const String& shader = jmaterial->GetShader();
+
+        //LOGINFOF("Shader: %s", shader.CString());
+
+        // TODO: factor in lightmaps
+        bool lightmap = false;
+
+        String technique("Diff.xml");
+
+        if (!lightmap)
+        {
+            if (shader == "Transparent/Diffuse")
+                technique = "DiffAlpha.xml";
+            else if (shader == "Transparent/Cutout/Diffuse")
+                technique = "DiffAlphaMask.xml";
+            else if (shader == "Transparent/Cutout/Specular")
+                technique = "DiffAlphaMask.xml";
+            else if (shader == "Transparent/Specular")
+                technique = "DiffAlpha.xml";
+            else if (shader == "Hidden/Nature/Tree Creator Leaves Fast Optimized")
+                technique = "DiffAlphaMask.xml";
+        }
+        else
+        {
+            technique = "DiffLightMap.xml";
+            if (shader == "Transparent/Diffuse")
+                technique = "DiffLightMapAlpha.xml";
+            else if (shader == "Transparent/Cutout/Diffuse")
+                technique = "DiffLightMapAlpha.xml";
+            else if (shader == "Transparent/Cutout/Specular")
+                technique = "DiffLightMapAlpha.xml";
+            else if (shader == "Transparent/Specular")
+                technique = "DiffLightMapAlpha.xml";
+        }
+
+        SharedPtr<Material> material;
+        material = new Material(context_);
+
+        material->SetName("Materials/" + jmaterial->GetName() + ".xml");
+
+        Technique* _technique = cache->GetResource<Technique>("Techniques/" + technique);
+        assert(_technique);
+
+        material->SetTechnique(0, _technique);
+
+        const String& mainTexture = jmaterial->GetMainTexture();
+        if (mainTexture.Length())
+        {
+            Texture2D* texture = cache->GetResource<Texture2D>("Textures/" + mainTexture + ".png");
+            material->SetTexture(TU_DIFFUSE, texture);
+        }
+
+        materials_[jmaterial->GetName()] = material;
+
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::WriteMaterials()
+{
+    String materialFolder("Materials");
+    HashMap<String, SharedPtr<Material> >::Iterator itr = materials_.Begin();
+    while (itr != materials_.End())
+    {
+        Material* material = itr->second_;
+        SharedPtr<File> file;
+        file = new File(context_, __rootFolder + "/" + material->GetName(), FILE_WRITE);
+        material->Save(*file);
+        itr++;
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::WriteModels()
+{
+    HashMap<String, SharedPtr<Model> >::Iterator itr = models_.Begin();
+    while (itr != models_.End())
+    {
+        Model* model = itr->second_;
+        SharedPtr<File> file;
+        file = new File(context_, __rootFolder + "/" + model->GetName(), FILE_WRITE);
+        model->Save(*file);
+        itr++;
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::WriteHierarchy(Scene* scene)
+{
+
+
+    List<SharedPtr<Node> >::Iterator itr = hierarchy_.Begin();
+    while (itr != hierarchy_.End())
+    {
+        scene->AddChild(*itr);
+        itr++;
+    }
+
+    File file(context_);
+
+    bool useXML = true;
+
+    String filename;
+
+    filename.AppendWithFormat("%s", importer_->GetSceneName().CString());
+
+    if (!useXML)
+        filename += ".scene";
+    else
+        filename += ".xml";
+
+    filename = __rootFolder + "/Scenes/" + filename;
+
+    if (!file.Open(filename, FILE_WRITE))
+        ErrorExit("Could not open output file: Scenes/Test.bin");
+
+    if (useXML)
+        scene->SaveXML(file);
+    else
+        scene->Save(file);
+
+
+    file.Close();
+
+
+    return true;
+}
+
+
+bool JSONSceneProcess::ProcessModels()
+{
+    PODVector<JSONMesh*>& meshes = importer_->GetMeshes();
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    for (unsigned i = 0; i < meshes.Size(); i++)
+    {
+        JSONMesh* jmesh = meshes.At(i);
+
+        SharedPtr<Model> model(new Model(context_));
+
+        model->SetName("Models/" + jmesh->GetName() + ".mdl");
+
+        unsigned vertexElementMask = MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1;// | MASK_COLOR;
+
+        if (jmesh->GetNumUVSets() == 2)
+            vertexElementMask |= MASK_TEXCOORD2;
+
+        PODVector<JSONMesh::BoneWeight>& boneWeights = jmesh->GetBoneWeights();
+
+        if (boneWeights.Size())
+            vertexElementMask |= (MASK_BLENDWEIGHTS | MASK_BLENDINDICES);
+
+        // the model has to have 65535 or less indices to avoid 32 bit indices, check this
+        SharedPtr<IndexBuffer> ib (new IndexBuffer(context_));
+        SharedPtr<VertexBuffer> vb (new VertexBuffer(context_));
+
+        // even though shadowing, need to "SetData()" on these below
+        // could we SetData with the shadowed data?
+        ib->SetShadowed(true);
+        vb->SetShadowed(true);
+
+        // Setup Vertex Data
+        unsigned vertexCount = jmesh->GetVertexCount();
+
+        vb->SetSize(vertexCount, vertexElementMask);
+
+        BoundingBox bbox;
+
+        PODVector<Vector3>& vpos =  jmesh->GetVertexPositions();
+        PODVector<Vector3>& vnorm = jmesh->GetVertexNormals();
+        PODVector<Vector4>& vtan = jmesh->GetVertexTangents();
+        PODVector<Vector2>& uv0 = jmesh->GetUVSet(0);
+        PODVector<Vector2>& uv1 = jmesh->GetUVSet(1);
+
+        PODVector<float> vdata;
+
+        unsigned vertexSize = 8;
+        if (vertexElementMask & MASK_TEXCOORD2)
+            vertexSize += 2;
+
+        if (vertexElementMask & MASK_BLENDWEIGHTS)
+            vertexSize += 5;
+
+        vdata.Resize(vertexCount * vertexSize);
+
+        // TODO: we should be identifying unique vertices
+        float* v = &vdata[0];
+
+        for (unsigned j = 0; j < vertexCount; j++)
+        {
+            if (j < vpos.Size())
+            {
+                *v = vpos[j].x_; v++;
+                *v = vpos[j].y_; v++;
+                *v = vpos[j].z_; v++;
+            }
+            else
+            {
+                *v = 0; v++;
+                *v = 0; v++;
+                *v = 0; v++;
+            }
+
+            if (j < vnorm.Size())
+            {
+                *v = vnorm[j].x_; v++;
+                *v = vnorm[j].y_; v++;
+                *v = vnorm[j].z_; v++;
+            }
+            else
+            {
+                *v = 0; v++;
+                *v = 0; v++;
+                *v = 0; v++;
+            }
+
+            if (j < uv0.Size())
+            {
+                *v = uv0[j].x_; v++;
+                *v = -uv0[j].y_; v++;
+            }
+            else
+            {
+                *v = 0; v++;
+                *v = 0; v++;
+            }
+
+            if (vertexElementMask &  MASK_TEXCOORD2)
+            {
+                if (j < uv1.Size())
+                {
+                    *v = uv1[j].x_; v++;
+                    *v = -uv1[j].y_; v++;
+                }
+                else
+                {
+                    *v = 0; v++;
+                    *v = 0; v++;
+                }
+            }
+
+            if (vertexElementMask & MASK_BLENDWEIGHTS)
+            {
+                JSONMesh::BoneWeight& boneWeight = boneWeights[j];
+
+                for (unsigned k = 0; k < 4; ++k)
+                {
+                    *v = boneWeight.weights_[k]; v++;
+                }
+            }
+            if (vertexElementMask & MASK_BLENDINDICES)
+            {
+                JSONMesh::BoneWeight& boneWeight = boneWeights[j];
+
+                unsigned char* destBytes = (unsigned char*)v;
+                ++v;
+                for (unsigned k = 0; k < 4; ++k)
+                {
+                    *destBytes++ = (unsigned char) boneWeight.indexes_[k];
+                }
+            }
+
+
+            bbox.Merge(vpos[j]);
+
+        }
+
+        vb->SetData(&vdata[0]);
+
+        unsigned numIndices = 0;
+        PODVector<uint16_t> allIndices;
+
+        unsigned numGeom = jmesh->GetSubMeshCount();
+        for (unsigned j = 0; j < numGeom; j++)
+        {
+            PODVector<int>& submesh = jmesh->GetSubMesh(j);
+
+            numIndices += submesh.Size();
+
+            for (unsigned k = 0; k < submesh.Size(); k++)
+            {
+                allIndices.Push((uint16_t) submesh[k]);
+            }
+        }
+
+        ib->SetSize(numIndices, false);
+
+        ib->SetData(&allIndices[0]);
+
+        Vector<SharedPtr<Geometry> > geometry;
+
+        uint16_t start = 0;
+        for (unsigned j = 0; j < numGeom; j++)
+        {
+            PODVector<int>& submesh = jmesh->GetSubMesh(j);
+
+            SharedPtr<Geometry> geom(new Geometry(context_));
+            geometry.Push(geom);
+
+            geom->SetIndexBuffer(ib);
+            geom->SetVertexBuffer(0, vb, vertexElementMask);
+            geom->SetDrawRange(TRIANGLE_LIST, start, submesh.Size(), false);
+
+            start += submesh.Size();
+        }
+
+        model->SetNumGeometries(geometry.Size());
+
+        Vector<SharedPtr<VertexBuffer> > vbVector;
+        Vector<SharedPtr<IndexBuffer> > ibVector;
+
+        vbVector.Push(vb);
+        ibVector.Push(ib);
+
+        PODVector<unsigned> emptyMorphRange;
+        model->SetVertexBuffers(vbVector, emptyMorphRange, emptyMorphRange);
+        model->SetIndexBuffers(ibVector);
+
+        Vector<JSONMesh::Bone>& jbones = jmesh->GetBones();
+
+        // FIXME: we need to get the bounds or calculate propoer
+        if (jbones.Size())
+        {
+            bbox.min_ *= 2;
+            bbox.max_ *= 2;
+
+        }
+
+        // see fixme's for skeletal geo center/bounds
+        for (unsigned j = 0; j < geometry.Size(); j++)
+        {
+            model->SetNumGeometryLodLevels(j, 1);
+            model->SetGeometry(j, 0, geometry[j]);
+            // this could be finer grained
+            // also, fix this for skeletal
+            model->SetGeometryCenter(j, jbones.Size() ? Vector3::ZERO : bbox.Center());//Vector3::ZERO);
+        }
+
+        // FIXME: skeletal bounds is off
+        if (!jbones.Size())
+            model->SetBoundingBox(bbox);
+        else
+            model->SetBoundingBox(BoundingBox(-1024, 1024));
+
+        // Build skeleton if necessary
+        if (jbones.Size())
+        {
+            Skeleton skeleton;
+            Vector<Bone>& bones = skeleton.GetModifiableBones();
+
+            unsigned rootindex = 0;
+
+            const String& rootBoneName = jmesh->GetRootBone();
+
+            for (unsigned j = 0; j < jbones.Size(); ++j)
+            {
+                JSONMesh::Bone& jbone = jbones[j];
+
+                if (jbone.name_ == rootBoneName)
+                {
+                    rootindex = j;
+                    break;
+                }
+
+            }
+
+            for (unsigned j = 0; j < jbones.Size(); ++j)
+            {
+                JSONMesh::Bone& jbone = jbones[j];
+
+                String boneName(jbone.name_);
+
+                Bone newBone;
+                newBone.name_ = boneName;
+                newBone.initialPosition_ = jbone.pos_;
+                newBone.initialRotation_ = jbone.rot_;
+                newBone.initialScale_ = jbone.scale_;
+
+                // Get offset information if exists
+                newBone.offsetMatrix_ = Matrix3x4(jmesh->GetBindPoses()[j]);
+                //newBone.radius_ = model.boneRadii_[i];
+                //newBone.boundingBox_ = model.boneHitboxes_[i];
+                //newBone.collisionMask_ = BONECOLLISION_SPHERE | BONECOLLISION_BOX;
+                newBone.parentIndex_ = j;
+                bones.Push(newBone);
+            }
+
+            // Set the bone hierarchy
+            for (unsigned j = 0; j < jbones.Size(); ++j)
+            {
+                JSONMesh::Bone& jbone = jbones[j];
+
+                String parentName = jbone.parentName_;
+
+                if (!parentName.Length())
+                {
+                    bones[j].parentIndex_ = j;
+                }
+                else
+                {
+                    for (unsigned k = 0; k < bones.Size(); ++k)
+                    {
+                        if (bones[k].name_ == parentName)
+                        {
+                            bones[j].parentIndex_ = k;
+                            break;
+                        }
+                    }
+
+                }
+
+            }
+
+            skeleton.SetRootBoneIndex(rootindex);
+
+            model->SetSkeleton(skeleton);
+        }
+
+        models_[jmesh->GetName()] = model;
+
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONTransform* jtransform)
+{
+    node->SetPosition(jtransform->GetLocalPosition());
+    node->SetRotation(jtransform->GetLocalRotation());
+    node->SetScale(jtransform->GetLocalScale());
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONTimeOfDay* jtime )
+{
+    TimeOfDay* timeofday = node->CreateComponent<TimeOfDay>();
+    timeofday->SetTimeOn(jtime->GetTimeOn());
+    timeofday->SetTimeOff(jtime->GetTimeOff());
+    return true;
+}
+
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONLight* jlight )
+{
+    if (!jlight->GetRealtime() || jlight->GetLightType() != "Point")
+        return true;
+
+    Light* light = node->CreateComponent<Light>();
+    light->SetRange(jlight->GetRange());
+    light->SetCastShadows(jlight->GetCastsShadows());
+    light->SetColor(jlight->GetColor());
+    light->SetLightType(LIGHT_POINT);
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONBoxCollider* jbox )
+{
+    CollisionShape* shape = node->CreateComponent<CollisionShape>();
+    shape->SetBox(jbox->GetSize(), jbox->GetCenter());
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONMeshCollider* jmesh )
+{
+    // JSONMeshCollider should store the mesh, as this may not be on node
+    CollisionShape* shape = node->CreateComponent<CollisionShape>();
+    StaticModel* model = node->GetComponent<StaticModel>();
+
+    if (!model || !model->GetModel())
+    {
+        LOGWARNING("Missing model for MeshCollier");
+        return true;
+    }
+
+    assert(model && model->GetModel());
+    if (model)
+        shape->SetTriangleMesh(model->GetModel());
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONRigidBody* jbody )
+{
+    RigidBody* body = node->CreateComponent<RigidBody>();
+    body->SetMass(jbody->GetMass());
+    return true;
+}
+
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONTerrain* jterrain)
+{
+    int heightmapHeight = jterrain->GetHeightMapHeight();
+    int heightmapWidth = jterrain->GetHeightMapWidth();
+    unsigned length;
+    const float* heightmap = jterrain->GetHeightMap(length);
+
+    const Vector3 heightmapScale = jterrain->GetHeightMapScale();
+    const Vector3 heightmapSize = jterrain->GetHeightMapSize();
+
+    PODVector<uint8_t> bytes;
+
+    bytes.Resize(heightmapHeight * heightmapWidth * 4);
+
+    uint8_t* out = &bytes[0];
+
+    for (int y = 0; y < heightmapHeight; y++)
+    {
+        for (int x = 0; x < heightmapWidth; x++)
+        {
+            float h = heightmap[y * heightmapWidth + x];
+            uint8_t hbyte = uint8_t(255.0 * h);
+            *out++ = hbyte;
+            *out++ = hbyte;
+            *out++ = hbyte;
+            *out++ = 255;
+        }
+    }
+
+    SharedPtr<Image> image(new Image(context_));
+
+    image->SetSize(heightmapWidth, heightmapHeight, 4);
+    image->SetData(&bytes[0]);
+
+    String heightMapPath = __rootFolder + "/Textures/TerrainHeightMap.png";
+    image->SavePNG(heightMapPath);
+
+    int alphamapWidth = jterrain->GetAlphaMapHeight();
+    int alphamapHeight = jterrain->GetAlphaMapWidth();
+    int alphamapLayers = jterrain->GetAlphaMapLayers();
+
+    if (alphamapLayers > 3)
+        alphamapLayers = 3;
+
+    const float* alphamap = jterrain->GetAlphaMap(length);
+
+    bytes.Resize( alphamapWidth * alphamapWidth * 4);
+
+    memset (&bytes[0], 255, alphamapWidth * alphamapWidth * 4);
+
+    for (int i = 0; i < alphamapLayers; i++)
+    {
+        uint8_t* out = &bytes[i];
+
+        for (int y = 0; y < alphamapHeight; y++)
+        {
+            for (int x = 0; x < alphamapWidth; x++)
+            {
+                float w = alphamap[(i * (alphamapWidth * alphamapHeight)) + y * alphamapWidth + x ];
+                uint8_t wbyte = uint8_t(255.0 * w);
+                *out = wbyte;
+                out += 4;
+            }
+        }
+    }
+
+    SharedPtr<Image> alphaWeights(new Image(context_));
+
+    alphaWeights->SetSize(alphamapWidth, alphamapHeight, 4);
+    alphaWeights->SetData(&bytes[0]);
+
+    String alphaWeightsPath = __rootFolder + "/Textures/TerrainWeights.png";
+    alphaWeights->SavePNG(alphaWeightsPath);
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    Image* heightMap = cache->GetResource<Image>(heightMapPath);
+
+    Material* material = cache->GetResource<Material>("Materials/DemoTerrain.xml");
+
+    Terrain* terrain = node->CreateComponent<Terrain>();
+
+    terrain->SetHeightMap(heightMap);
+    terrain->SetMaterial(material);
+    terrain->SetSmoothing(true);
+
+    //terrain->SetPatchSize(64);
+    //terrain->SetSpacing(Vector3(2.0f, 0.5f, 2.0f)); // Spacing between vertices and vertical resolution of the height map
+    //terrain->SetSmoothing(true);
+
+    Vector3 spacing = heightmapScale;
+
+    spacing.y_ = heightmapScale.y_ / 250.0f;
+
+    terrain->SetSpacing(spacing);
+
+    Vector3 pos = node->GetPosition();
+    pos.x_ += heightmapSize.x_/2.0f;
+    pos.y_  += .1f;
+    pos.z_ += heightmapSize.z_/2.0f;
+
+    node->SetPosition(pos);
+
+    Quaternion rotation;
+    rotation = node->GetRotation();
+
+    rotation.FromEulerAngles(0, -90, 0);
+
+    node->SetRotation(rotation);
+
+    RigidBody* body = node->CreateComponent<RigidBody>();
+    // use layer 2 for static
+    body->SetCollisionLayer(2);
+    body->SetFriction(1.0f);
+    CollisionShape* shape = node->CreateComponent<CollisionShape>();
+    shape->SetTerrain();
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONAnimation* janim )
+{
+    const Vector<JSONAnimation::AnimationClip*>& clips =  janim->GetClips();
+
+    for (unsigned i = 0; i < clips.Size(); i++)
+    {
+        const JSONAnimation::AnimationClip* clip = clips[i];
+
+        SharedPtr<Animation> outAnim(new Animation(context_));
+        outAnim->SetAnimationName(clip->name_);
+        outAnim->SetLength(clip->GetDuration());
+
+        Vector<AnimationTrack> tracks;
+
+        for (unsigned j = 0; j < clip->nodes_.Size(); ++j)
+        {
+            const JSONAnimation::AnimationNode* node = clip->nodes_[j];
+
+            String channelName = node->name_;
+
+            if (channelName.Contains('/'))
+            {
+                channelName = channelName.Split('/').Back();
+            }
+
+            AnimationTrack track;
+            track.name_ = channelName;
+            track.nameHash_ = channelName;
+            // TODO: optimize channels
+            track.channelMask_ |= (CHANNEL_POSITION | CHANNEL_ROTATION | CHANNEL_SCALE);
+
+            //assert(node->keyframes_.Size());
+
+            for (unsigned k = 0; k < node->keyframes_.Size(); k++)
+            {
+                const JSONAnimation::Keyframe* keyframe = node->keyframes_[k];
+
+                AnimationKeyFrame key;
+
+                key.time_ = keyframe->time_;
+                key.position_ = keyframe->pos_;
+                key.rotation_ = keyframe->rot_;
+                key.scale_ = keyframe->scale_;
+
+                track.keyFrames_.Push(key);
+
+            }
+
+            tracks.Push(track);
+
+        }
+
+        outAnim->SetTracks(tracks);
+
+        String filename = __rootFolder;
+
+        filename.AppendWithFormat("/Models/AS_FatZombie_FBX_FatZombie_LOD0_%s.ani", clip->name_.CString());
+
+        File outFile(context_);
+        if (!outFile.Open(filename, FILE_WRITE))
+            ErrorExit("Could not open output file for animation");
+        outAnim->Save(outFile);
+
+
+    }
+
+
+    return true;
+
+
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONMeshRenderer* jmeshrenderer )
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    StaticModel* staticModel = NULL;
+    int lightmapIndex = jmeshrenderer->GetLightmapIndex();
+
+    if (lightmapIndex >= 0)
+    {
+        LMStaticModel* lmstatic = node->CreateComponent<LMStaticModel>();
+        staticModel = lmstatic;
+
+        const Vector4& tilingOffset = jmeshrenderer->GetLightmapTilingOffset();
+        lmstatic->lightmapTilingOffset_ = tilingOffset;
+
+        lmstatic->lightmapTilingOffset_.w_ = -lmstatic->lightmapTilingOffset_.w_;
+
+        String lightmapName;
+
+        lightmapName.AppendWithFormat("Textures/%s_Lightmap_%i.png", importer_->GetSceneName().CString(), lightmapIndex);
+
+        Texture2D* texture = cache->GetResource<Texture2D>(lightmapName);
+        assert(texture);
+        lmstatic->SetLightmapTexure(texture);
+    }
+    else
+        staticModel = node->CreateComponent<StaticModel>();
+
+    const JSONMesh* mesh = jmeshrenderer->GetMesh();
+
+    assert(models_.Contains(mesh->GetName()));
+
+    Model* model = models_[mesh->GetName()];
+
+    staticModel->SetModel(model);
+
+    for (unsigned i = 0; i < jmeshrenderer->GetNumMaterials(); i++)
+    {
+        const JSONMaterial* jmat = jmeshrenderer->GetMaterial(i);
+
+        assert(materials_.Contains(jmat->GetName()));
+
+        staticModel->SetMaterial(i, materials_[jmat->GetName()]);
+
+    }
+
+    staticModel->SetCastShadows(jmeshrenderer->GetCastShadows());
+
+    /*
+    CollisionShape* shape = node->CreateComponent<CollisionShape>();
+    shape->SetTriangleMesh(model, 0);
+    node->CreateComponent<RigidBody>();
+    */
+
+    BoundingBox bbox = model->GetBoundingBox();
+    bbox.Transform(node->GetWorldTransform());
+
+    Vector3 size = bbox.Size();
+    //staticModel->SetDrawDistance(size.Length() * 30.0f);
+    //staticModel->SetShadowDistance(size.Length() * 10.0f);
+
+    return true;
+}
+
+bool JSONSceneProcess::ProcessComponent(Node* node, const JSONSkinnedMeshRenderer* jmeshrenderer )
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    AnimatedModel* animatedModel =  node->CreateComponent<AnimatedModel>();
+
+    const JSONMesh* mesh = jmeshrenderer->GetMesh();
+
+    assert(models_.Contains(mesh->GetName()));
+
+    Model* model = models_[mesh->GetName()];
+
+    animatedModel->SetModel(model);
+
+    for (unsigned i = 0; i < jmeshrenderer->GetNumMaterials(); i++)
+    {
+        const JSONMaterial* jmat = jmeshrenderer->GetMaterial(i);
+
+        assert(materials_.Contains(jmat->GetName()));
+
+        animatedModel->SetMaterial(i, materials_[jmat->GetName()]);
+
+    }
+
+    animatedModel->SetCastShadows(jmeshrenderer->GetCastShadows());
+
+    return true;
+}
+
+Node* JSONSceneProcess::ProcessNode(const JSONNode* jnode, Node* parent)
+{
+    Node* node = parent->CreateChild(jnode->GetName());
+
+    const PODVector<JSONComponent*>& components = jnode->GetComponents();
+
+    for (unsigned i = 0; i < components.Size(); i++)
+    {
+        const JSONComponent* c = components.At(i);
+
+        if (c->GetType() == "Transform")
+        {
+            ProcessComponent(node, (const JSONTransform*) c);
+        }
+        else if (c->GetType() == "MeshRenderer")
+        {
+            ProcessComponent(node, (const JSONMeshRenderer*) c);
+        }
+        else if (c->GetType() == "SkinnedMeshRenderer")
+        {
+            ProcessComponent(node, (const JSONSkinnedMeshRenderer*) c);
+        }
+        else if (c->GetType() == "Terrain")
+        {
+            ProcessComponent(node, (const JSONTerrain*) c);
+        }
+        else if (c->GetType() == "Animation")
+        {
+            ProcessComponent(node, (const JSONAnimation*) c);
+        }
+        else if (c->GetType() == "BoxCollider")
+        {
+            ProcessComponent(node, (const JSONBoxCollider*) c);
+        }
+        else if (c->GetType() == "MeshCollider")
+        {
+            ProcessComponent(node, (const JSONMeshCollider*) c);
+        }
+        else if (c->GetType() == "RigidBody")
+        {
+            ProcessComponent(node, (const JSONRigidBody*) c);
+        }
+        else if (c->GetType() == "Light")
+        {
+            ProcessComponent(node, (const JSONLight*) c);
+        }
+        else if (c->GetType() == "TimeOfDay")
+        {
+            ProcessComponent(node, (const JSONTimeOfDay*) c);
+        }
+    }
+
+    if (node->GetComponent<CollisionShape>() && !node->GetComponent<RigidBody>())
+    {
+        RigidBody* body = node->CreateComponent<RigidBody>();
+        body->SetCollisionLayer(2);
+
+    }
+
+    const PODVector<JSONNode*>& children = jnode->GetChildren();
+
+    for (unsigned i = 0; i < children.Size(); i++)
+    {
+        node->AddChild(ProcessNode(children.At(i), node));
+    }
+
+    return node;
+}
+
+bool JSONSceneProcess::ProcessHierarchy(Scene* scene)
+{
+    const PODVector<JSONNode*>& hierarchy = importer_->GetHierarchy();
+
+    for (unsigned i = 0; i < hierarchy.Size(); i++)
+    {
+        hierarchy_.Push(SharedPtr<Node>(ProcessNode(hierarchy[i], scene)));
+    }
+
+    return true;
+}
+
+bool JSONSceneProcess::Process()
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    cache->AddResourceDir(__rootFolder);
+    scene_ = new Scene(context_);
+    scene_->CreateComponent<PhysicsWorld>();
+    scene_->CreateComponent<Octree>();
+    scene_->CreateComponent<DebugRenderer>();
+
+    Node* zoneNode = scene_->CreateChild("Zone");
+    Zone* zone = zoneNode->CreateComponent<Zone>();
+    zone->SetBoundingBox(BoundingBox(-10000.0f, 10000.f));
+    zone->SetAmbientColor(Color(1, 1, 1));
+
+    ProcessTextures();
+    ProcessLightmaps();
+    ProcessMaterials();
+    ProcessModels();
+    ProcessHierarchy(scene_);
+
+    return true;
+}
+
+bool JSONSceneProcess::Write()
+{
+
+    WriteMaterials();
+    WriteModels();
+    WriteHierarchy(scene_);
+
+    return true;
+}
+
+
+}
+
+

+ 85 - 0
Source/ToolCore/Import/JSONSceneProcess.h

@@ -0,0 +1,85 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#pragma once
+
+#include <Atomic/Container/HashMap.h>
+#include <Atomic/Container/List.h>
+
+#include <Atomic/Resource/ResourceCache.h>
+#include <Atomic/Graphics/Technique.h>
+#include <Atomic/Graphics/Texture2D.h>
+#include <Atomic/Graphics/Material.h>
+#include <Atomic/Atomic3D/Model.h>
+#include <Atomic/Scene/Scene.h>
+
+using namespace Atomic;
+
+namespace AtomicEditor
+{
+
+class JSONSceneImporter;
+class JSONNode;
+class JSONTransform;
+class JSONMeshRenderer;
+class JSONSkinnedMeshRenderer;
+class JSONAnimation;
+class JSONTerrain;
+class JSONBoxCollider;
+class JSONMeshCollider;
+class JSONRigidBody;
+class JSONLight;
+class JSONTimeOfDay;
+
+class JSONSceneProcess : public Object
+{
+
+    OBJECT(JSONSceneProcess);
+
+public:
+
+    JSONSceneProcess(Context* context, JSONSceneImporter* importer) : Object(context)
+    {
+        importer_ = importer;
+    }
+
+    bool Process();
+    bool Write();
+
+private:
+
+    HashMap<String, SharedPtr<Material> > materials_;
+    HashMap<String, SharedPtr<Model> > models_;
+
+    SharedPtr<Scene> scene_ ;
+    List<SharedPtr<Node> > hierarchy_;
+
+    bool WriteMaterials();
+    bool WriteModels();
+    bool WriteHierarchy(Scene *scene);
+
+    bool ProcessTextures();
+    bool ProcessLightmaps();
+    bool ProcessMaterials();
+    bool ProcessModels();
+
+    bool ProcessComponent(Node* node, const JSONTransform* jtransform );
+    bool ProcessComponent(Node* node, const JSONMeshRenderer* jmeshrenderer );
+    bool ProcessComponent(Node* node, const JSONSkinnedMeshRenderer* jmeshrenderer );
+    bool ProcessComponent(Node* node, const JSONAnimation* janim );
+    bool ProcessComponent(Node* node, const JSONTerrain* jterrain );
+    bool ProcessComponent(Node* node, const JSONBoxCollider* jbox );
+    bool ProcessComponent(Node* node, const JSONMeshCollider* jmesh );
+    bool ProcessComponent(Node* node, const JSONLight* jlight );
+    bool ProcessComponent(Node* node, const JSONRigidBody* jbody );
+    bool ProcessComponent(Node* node, const JSONTimeOfDay* jtime );
+    Node* ProcessNode(const JSONNode* jnode, Node *parent);
+
+    bool ProcessHierarchy(Scene *scene);
+
+    SharedPtr<JSONSceneImporter> importer_;
+
+};
+
+}