commons/src/main/com/mbrlabs/mundus/commons/scene3d/GameObject.java
public class GameObject extends SimpleNode<GameObject> implements Iterable<GameObject> {

    public static final String DEFAULT_NAME = "GameObject";

    public String name;
    public boolean active;
    private Array<String> tags;
    private Array<Component> components;

    public final SceneGraph sceneGraph;

    /**
     * @param sceneGraph
     *            scene graph
     * @param name
     *            game object name; can be null
     * @param id
     *            game object id
     */
    public GameObject(SceneGraph sceneGraph, String name, int id) {
        super(id);
        this.sceneGraph = sceneGraph;
        this.name = (name == null) ? DEFAULT_NAME : name;
        this.active = true;
        this.tags = null;
        this.components = new Array<Component>(3);
    }

    /**
     * Make copy with existing gameObject and new id
     *
     * @param gameObject
     *            game object for clone
     */
    public GameObject(GameObject gameObject, int id) {
        super(gameObject, id);
        this.sceneGraph = gameObject.sceneGraph;

        // set name _copy
        this.name = gameObject.name + "_copy";
        this.active = gameObject.active;

        // copy tags
        if (tags != null) {
            Array<String> newTags = new Array<String>();
            for (String t : gameObject.tags) {
                newTags.add(t);
            }
            this.tags = newTags;
        }

        // copy components
        this.components = new Array<Component>();
        for (Component c : gameObject.components) {
            this.components.add(c.clone(this));
        }
        setParent(gameObject.parent);
    }

    /**
     * Calls the render() method for each component in this and all child nodes.
     *
     * @param delta
     *            time since last render
     */
    public void render(float delta) {
        if (active) {
            for (Component component : this.components) {
                component.render(delta);
            }

            if (getChildren() != null) {
                for (GameObject node : getChildren()) {
                    node.render(delta);
                }
            }
        }
    }

    /**
     * Calls the update() method for each component in this and all child nodes.
     *
     * @param delta
     *            time since last update
     */
    public void update(float delta) {
        if (active) {
            for (Component component : this.components) {
                component.update(delta);
            }

            if (getChildren() != null) {
                for (GameObject node : getChildren()) {
                    node.update(delta);
                }
            }
        }
    }

    /**
     * Returns the tags
     * 
     * @return tags or null if none available
     */
    public Array<String> getTags() {
        return this.tags;
    }

    /**
     * Adds a tag.
     * 
     * @param tag
     *            tag to add
     */
    public void addTag(String tag) {
        if (this.tags == null) {
            this.tags = new Array<String>(2);
        }

        this.tags.add(tag);
    }

    /**
     * Finds all component by a given type.
     *
     * @param out
     *            output array
     * @param type
     *            component type
     * @param includeChilds
     *            search in node children of this game object as well?
     * @return components found
     */
    public Array<Component> findComponentsByType(Array<Component> out, Component.Type type, boolean includeChilds) {
        if (includeChilds) {
            for (GameObject go : this) {
                for (Component c : go.components) {
                    if (c.getType() == type) out.add(c);
                }
            }
        } else {
            for (Component c : components) {
                if (c.getType() == type) out.add(c);
            }
        }

        return out;
    }

    /**
     * Finds one component by type.
     *
     * @param type
     *            component type
     * @return component if found or null
     */
    public Component findComponentByType(Component.Type type) {
        for (Component c : components) {
            if (c.getType() == type) return c;
        }

        return null;
    }

    /**
     * Returns all components of this go.
     * 
     * @return components
     */
    public Array<Component> getComponents() {
        return this.components;
    }

    /**
     * Removes a component.
     * 
     * @param component
     *            component to remove
     */
    public void removeComponent(Component component) {
        components.removeValue(component, true);
    }

    /**
     * Adds a component.
     *
     * @param component
     *            component to add
     * @throws InvalidComponentException
     */
    public void addComponent(Component component) throws InvalidComponentException {
        isComponentAddable(component);
        components.add(component);
    }

    /**
     *
     * @param component
     * @throws InvalidComponentException
     */
    public void isComponentAddable(Component component) throws InvalidComponentException {
        // check for component of the same type
        for (Component c : components) {
            if (c.getType() == component.getType()) {
                throw new InvalidComponentException(
                        "One Game object can't have more then 1 component of type " + c.getType());
            }
        }
    }

    @Override
    public Iterator<GameObject> iterator() {
        return new DepthFirstIterator(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        GameObject that = (GameObject) o;

        if (id != that.id) return false;
        if (!name.equals(that.name)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = (id ^ (id >>> 16));
        result = 31 * result + name.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return name;
    }

}
editor/src/main/com/mbrlabs/mundus/editor/core/registry/ProjectRef.java
public class ProjectRef {

    private String name;
    private String path;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

}
editor/src/main/com/mbrlabs/mundus/editor/core/project/ProjectContext.java
public class ProjectContext implements Disposable {

    private static final String TAG = ProjectContext.class.getSimpleName();

    public ProjectSettings settings;
    public String path;
    public String name;

    public Array<String> scenes;
    public EditorScene currScene;

    public EditorAssetManager assetManager;

    private int idProvider;

    /** set by kryo when project is loaded. do not use this */
    public String activeSceneName;

    public ProjectContext(int idProvider) {
        scenes = new Array<>();
        settings = new ProjectSettings();
        currScene = new EditorScene();
        this.idProvider = idProvider;
    }

    public synchronized int obtainID() {
        idProvider += 1;
        return idProvider;
    }

    public synchronized int inspectCurrentID() {
        return idProvider;
    }

    @Override
    public void dispose() {
        Log.debug(TAG, "Disposing current project: {}", path);
        if (assetManager != null) {
            assetManager.dispose();
        }
    }

}
commons/src/main/com/mbrlabs/mundus/commons/assets/Asset.java
public abstract class Asset implements Disposable {

    protected FileHandle file;
    protected Meta meta;

    /**
     *
     * @param meta
     * @param assetFile
     */
    public Asset(Meta meta, FileHandle assetFile) {
        this.meta = meta;
        this.file = assetFile;
    }

    public Meta getMeta() {
        return meta;
    }

    public String getName() {
        return file.name();
    }

    public FileHandle getFile() {
        return file;
    }

    public String getID() {
        return meta.getUuid();
    }

    @Override
    public String toString() {
        return "[" + getMeta().getType().toString() + "] " + file.name();
    }

    /**
     * Loads the asset.
     *
     * Loads the asset from disk and creates it.
     */
    public abstract void load();

    /**
     * Resolves all dependencies of this asset.
     *
     * Before calling this method all assets must have been loaded using the
     * load() method.
     * 
     * @param assets
     *            map of loaded assets with asset id as key
     */
    public abstract void resolveDependencies(Map<String, Asset> assets);

    /**
     * Applies dependent assets to this one.
     *
     * If dependencies have been set, this method applies them to the asset.
     * Note, that the asset and all it's set dependencies must have called
     * load() before calling this method.
     */
    public abstract void applyDependencies();

}
editor/src/main/com/mbrlabs/mundus/editor/core/registry/Registry.java
public class Registry {

    public static final String HOME_DIR = FilenameUtils.concat(FileUtils.getUserDirectoryPath(), ".mundus/");
    public static final String LOGS_DIR = FilenameUtils.concat(HOME_DIR, "logs/");
    public static final String TEMP_DIR = FilenameUtils.concat(HOME_DIR, "temp/");
    public static final String HOME_DATA_FILE = FilenameUtils.concat(HOME_DIR, "mundus.registry");

    private List<ProjectRef> projects;
    private ProjectRef lastProject;
    private Settings settings;

    private KryoManager kryoManager;

    public Registry() {
        projects = new ArrayList<>();
        settings = new Settings();
    }

    public FileHandle createTempFolder() {
        String tempFolderPath = FilenameUtils.concat(TEMP_DIR, UUID.randomUUID().toString()) + "/";
        FileHandle tempFolder = Gdx.files.absolute(tempFolderPath);
        tempFolder.mkdirs();

        return tempFolder;
    }

    public void purgeTempDirectory() {
        for (FileHandle f : Gdx.files.absolute(TEMP_DIR).list()) {
            f.deleteDirectory();
        }
    }

    public ProjectRef createProjectRef(String name, String folder) {
        ProjectRef projectRef = new ProjectRef();
        projectRef.setName(name);
        projectRef.setPath(FilenameUtils.concat(folder, name));
        projects.add(projectRef);

        return projectRef;
    }

    public List<ProjectRef> getProjects() {
        return projects;
    }

    public Settings getSettings() {
        return settings;
    }

    public ProjectRef getLastOpenedProject() {
        return lastProject;
    }

    public ProjectRef getLastProject() {
        return lastProject;
    }

    public void setLastProject(ProjectRef lastProject) {
        this.lastProject = lastProject;
    }

    public void setSettings(Settings settings) {
        this.settings = settings;
    }
}
editor/src/main/com/mbrlabs/mundus/editor/core/project/ProjectSettings.java
public class ProjectSettings {

    private ExportSettings export = new ExportSettings();

    public ExportSettings getExport() {
        return export;
    }

    /**
     *
     */
    public class ExportSettings {
        public JsonWriter.OutputType jsonType = JsonWriter.OutputType.json;
        public boolean compressScenes = false;
        public boolean allAssets = true;
        public FileHandle outputFolder;
    }

}
editor/src/main/com/mbrlabs/mundus/editor/core/registry/KeyboardLayout.java
public enum KeyboardLayout {
    /** German layout. */
    QWERTZ,
    /** English layout */
    QWERTY
}
commons/src/main/com/mbrlabs/mundus/commons/scene3d/SceneGraph.java
public class SceneGraph {

    protected GameObject root;

    public Scene scene;
    public ModelBatch batch;

    private GameObject selected;

    public SceneGraph(Scene scene) {
        root = new GameObject(this, null, -1);
        root.initChildrenArray();
        root.active = false;
        this.scene = scene;
    }

    public void render() {
        render(Gdx.graphics.getDeltaTime());
    }

    public void render(float delta) {
        batch.begin(scene.cam);
        for (GameObject go : root.getChildren()) {
            go.render(delta);
        }
        batch.end();
    }

    public void update() {
        update(Gdx.graphics.getDeltaTime());
    }

    public void update(float delta) {
        for (GameObject go : root.getChildren()) {
            go.update(delta);
        }
    }

    public Array<GameObject> getGameObjects() {
        return root.getChildren();
    }

    public void addGameObject(GameObject go) {
        root.addChild(go);
    }

    public GameObject getSelected() {
        return selected;
    }

    public void setSelected(GameObject selected) {
        this.selected = selected;
    }

}
commons/src/main/com/mbrlabs/mundus/commons/scene3d/components/Component.java
public interface Component {

    enum Type {
        MODEL, TERRAIN, LIGHT, PARTICLE_SYSTEM
    }

    GameObject getGameObject();

    void render(float delta);

    void update(float delta);

    Type getType();

    void setType(Type type);

    void remove();

    Component clone(GameObject go);
}
commons/src/main/com/mbrlabs/mundus/commons/assets/ModelAsset.java
public class ModelAsset extends Asset {

    private Model model;

    private Map<String, MaterialAsset> defaultMaterials;

    public ModelAsset(Meta meta, FileHandle assetFile) {
        super(meta, assetFile);
        defaultMaterials = new HashMap<String, MaterialAsset>();
    }

    public Model getModel() {
        return model;
    }

    public Map<String, MaterialAsset> getDefaultMaterials() {
        return defaultMaterials;
    }

    @Override
    public void load() {
        // TODO don't create a new loader each time
        MG3dModelLoader loader = new MG3dModelLoader(new UBJsonReader());
        model = loader.loadModel(file);
    }

    @Override
    public void resolveDependencies(Map<String, Asset> assets) {
        // materials
        MetaModel metaModel = meta.getModel();
        for (String g3dbMatID : metaModel.getDefaultMaterials().keys()) {
            String uuid = metaModel.getDefaultMaterials().get(g3dbMatID);
            defaultMaterials.put(g3dbMatID, (MaterialAsset) assets.get(uuid));
        }
    }

    @Override
    public void applyDependencies() {
        if (model == null) return;

        // materials
        for (Material mat : model.materials) {
            MaterialAsset materialAsset = defaultMaterials.get(mat.id);
            if (materialAsset == null) continue;
            materialAsset.applyToMaterial(mat);
        }
    }

    @Override
    public void dispose() {
        if (model != null) {
            model.dispose();
        }
    }

}
editor/src/main/com/mbrlabs/mundus/editor/scene3d/components/PickableTerrainComponent.java
public class PickableTerrainComponent extends TerrainComponent implements PickableComponent {

    public PickableTerrainComponent(GameObject go, Shader shader) {
        super(go, shader);
    }

    @Override
    public void encodeRaypickColorId() {
        PickerIDAttribute goIDa = PickerColorEncoder.encodeRaypickColorId(gameObject);
        terrain.getTerrain().modelInstance.materials.first().set(goIDa);
    }

    @Override
    public void renderPick() {
        gameObject.sceneGraph.batch.render(terrain.getTerrain(), Shaders.INSTANCE.getPickerShader());
    }

}
commons/src/main/com/mbrlabs/mundus/commons/assets/TerrainAsset.java
public class TerrainAsset extends Asset {

    private float[] data;

    // dependencies
    private PixmapTextureAsset splatmap;
    private TextureAsset splatBase;
    private TextureAsset splatR;
    private TextureAsset splatG;
    private TextureAsset splatB;
    private TextureAsset splatA;

    private Terrain terrain;

    public TerrainAsset(Meta meta, FileHandle assetFile) {
        super(meta, assetFile);
    }

    public float[] getData() {
        return data;
    }

    public PixmapTextureAsset getSplatmap() {
        return splatmap;
    }

    public void setSplatmap(PixmapTextureAsset splatmap) {
        this.splatmap = splatmap;
        if (splatmap == null) {
            meta.getTerrain().setSplatmap(null);
        } else {
            meta.getTerrain().setSplatmap(splatmap.getID());
        }
    }

    public TextureAsset getSplatBase() {
        return splatBase;
    }

    public void setSplatBase(TextureAsset splatBase) {
        this.splatBase = splatBase;
        if (splatBase == null) {
            meta.getTerrain().setSplatBase(null);
        } else {
            meta.getTerrain().setSplatBase(splatBase.getID());

        }
    }

    public TextureAsset getSplatR() {
        return splatR;
    }

    public void setSplatR(TextureAsset splatR) {
        this.splatR = splatR;
        if (splatR == null) {
            getMeta().getTerrain().setSplatR(null);
        } else {
            meta.getTerrain().setSplatR(splatR.getID());

        }
    }

    public TextureAsset getSplatG() {
        return splatG;
    }

    public void setSplatG(TextureAsset splatG) {
        this.splatG = splatG;
        if (splatG == null) {
            meta.getTerrain().setSplatG(null);
        } else {
            meta.getTerrain().setSplatG(splatG.getID());
        }
    }

    public TextureAsset getSplatB() {
        return splatB;
    }

    public void setSplatB(TextureAsset splatB) {
        this.splatB = splatB;
        if (splatB == null) {
            meta.getTerrain().setSplatB(null);
        } else {
            meta.getTerrain().setSplatB(splatB.getID());
        }
    }

    public TextureAsset getSplatA() {
        return splatA;
    }

    public void setSplatA(TextureAsset splatA) {
        this.splatA = splatA;
        if (splatA == null) {
            meta.getTerrain().setSplatA(null);
        } else {
            meta.getTerrain().setSplatA(splatA.getID());
        }
    }

    public Terrain getTerrain() {
        return terrain;
    }

    @Override
    public void load() {
        // load height data from terra file
        final FloatArray floatArray = new FloatArray();

        DataInputStream is;
        try {
            is = new DataInputStream(file.read());
            while (is.available() > 0) {
                floatArray.add(is.readFloat());
            }
            is.close();
        } catch (EOFException e) {
            // e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        data = floatArray.toArray();

        terrain = new Terrain(meta.getTerrain().getSize(), data);
        terrain.init();
        terrain.update();
    }

    @Override
    public void resolveDependencies(Map<String, Asset> assets) {
        // splatmap
        String id = meta.getTerrain().getSplatmap();
        if (id != null && assets.containsKey(id)) {
            setSplatmap((PixmapTextureAsset) assets.get(id));
        }

        // splat channel base
        id = meta.getTerrain().getSplatBase();
        if (id != null && assets.containsKey(id)) {
            setSplatBase((TextureAsset) assets.get(id));
        }

        // splat channel r
        id = meta.getTerrain().getSplatR();
        if (id != null && assets.containsKey(id)) {
            setSplatR((TextureAsset) assets.get(id));
        }

        // splat channel g
        id = meta.getTerrain().getSplatG();
        if (id != null && assets.containsKey(id)) {
            setSplatG((TextureAsset) assets.get(id));
        }

        // splat channel b
        id = meta.getTerrain().getSplatB();
        if (id != null && assets.containsKey(id)) {
            setSplatB((TextureAsset) assets.get(id));
        }

        // splat channel a
        id = meta.getTerrain().getSplatA();
        if (id != null && assets.containsKey(id)) {
            setSplatA((TextureAsset) assets.get(id));
        }
    }

    @Override
    public void applyDependencies() {
        TerrainTexture terrainTexture = terrain.getTerrainTexture();

        if (splatmap == null) {
            terrainTexture.setSplatmap(null);
        } else {
            terrainTexture.setSplatmap(new SplatMap(splatmap));
        }
        if (splatBase == null) {
            terrainTexture.removeTexture(SplatTexture.Channel.BASE);
        } else {
            terrainTexture.setSplatTexture(new SplatTexture(SplatTexture.Channel.BASE, splatBase));
        }
        if (splatR == null) {
            terrainTexture.removeTexture(SplatTexture.Channel.R);
        } else {
            terrainTexture.setSplatTexture(new SplatTexture(SplatTexture.Channel.R, splatR));
        }
        if (splatG == null) {
            terrainTexture.removeTexture(SplatTexture.Channel.G);
        } else {
            terrainTexture.setSplatTexture(new SplatTexture(SplatTexture.Channel.G, splatG));
        }
        if (splatB == null) {
            terrainTexture.removeTexture(SplatTexture.Channel.B);
        } else {
            terrainTexture.setSplatTexture(new SplatTexture(SplatTexture.Channel.B, splatB));
        }
        if (splatA == null) {
            terrainTexture.removeTexture(SplatTexture.Channel.A);
        } else {
            terrainTexture.setSplatTexture(new SplatTexture(SplatTexture.Channel.A, splatA));
        }

        terrain.update();
    }

    @Override
    public void dispose() {

    }
}
editor/src/main/com/mbrlabs/mundus/editor/core/registry/Settings.java
public class Settings {

    private String fbxConvBinary = "";
    private KeyboardLayout keyboardLayout;

    public String getFbxConvBinary() {
        return fbxConvBinary;
    }

    public void setFbxConvBinary(String fbxConvBinary) {
        this.fbxConvBinary = fbxConvBinary;
    }

    public KeyboardLayout getKeyboardLayout() {
        return keyboardLayout;
    }

    public void setKeyboardLayout(KeyboardLayout keyboardLayout) {
        this.keyboardLayout = keyboardLayout;
    }

}
commons/src/main/com/mbrlabs/mundus/commons/env/Fog.java
public class Fog {

    public float density = 0.001f;
    public float gradient = 1.5f;
    public Color color = new Color(Color.WHITE);

}
editor/src/main/com/mbrlabs/mundus/editor/utils/Log.java
public class Log {

    private static final String TAG = Log.class.getSimpleName();

    public static final int TRACE = 5;
    public static final int DEBUG = 4;
    public static final int INFO = 3;
    public static final int WARN = 2;
    public static final int ERROR = 1;
    public static final int FATAL = 0;

    public static int LOG_LEVEL = TRACE;

    private static File logFile;
    private static PrintWriter logFileWriter;
    private static SimpleDateFormat msgDateFormat = new SimpleDateFormat("[HH:mm]");

    public static void init() {
        System.setErr(new ErrorStreamInterceptor(System.err));
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable) {
                Log.exception(TAG, throwable);
                Log.fatal(TAG, "Uncaught exception occurred, error report will be saved");
                logFileWriter.flush();
            }
        });

        prepareLogFile();
    }

    public static void dispose() {
        info(TAG, "Disposing");
        logFileWriter.close();
    }

    public static FileHandle getLogFile() {
        return Gdx.files.absolute(logFile.getAbsolutePath());
    }

    private static void prepareLogFile() {
        File logDirectory = new File(Registry.LOGS_DIR);
        System.out.println("INFO: Ensuring log directory(" + Registry.LOGS_DIR + ") exists...");
        logDirectory.mkdirs();

        SimpleDateFormat fileDateFormat = new SimpleDateFormat("yy-MM-dd");
        String fileName = fileDateFormat.format(new Date());
        fileName = "mundus_" + fileName + ".log";

        try {
            logFile = new File(logDirectory, fileName);
            logFile.createNewFile();
            logFileWriter = new PrintWriter(new FileWriter(logFile, true));
        } catch (IOException e) {
            exception(TAG, e);
        }

        logFileWriter.println();
        info(TAG, "Logging activated. Log file [{}] created. ", fileName);
    }

    public static String getLogStoragePath() {
        return logFile.getParent();
    }

    // Log with tag
    public static void trace(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= TRACE) {
            msg = completeMsg(msg, params);
            print("[Trace][" + tag + "] " + msg);
        }
    }

    public static void debug(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= DEBUG) {
            msg = completeMsg(msg, params);
            print("[Debug][" + tag + "] " + msg);
        }
    }

    public static void info(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= INFO) {
            msg = completeMsg(msg, params);
            print("[Info][" + tag + "] " + msg);
        }
    }

    public static void warn(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= WARN) {
            msg = completeMsg(msg, params);
            print("[Warning][" + tag + "] " + msg);
        }
    }

    public static void error(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= ERROR) {
            msg = completeMsg(msg, params);
            printErr("[Error][" + tag + "] " + msg);
        }
    }

    public static void fatal(String tag, String msg, Object... params) {
        if (LOG_LEVEL >= FATAL) {
            msg = completeMsg(msg, params);
            printErr("[Fatal][" + tag + "] " + msg);
        }
    }

    private static void print(String msg) {
        msg = getTimestamp() + msg;
        logFileWriter.println(msg);
        logFileWriter.flush();
        System.out.println(msg);
    }

    private static void printErr(String msg) {
        msg = getTimestamp() + msg;
        System.err.println(msg);
    }

    public static void exception(String tag, Throwable e) {
        String stack = ExceptionUtils.getStackTrace(e);
        fatal(tag, stack);
    }

    private static String getTimestamp() {
        return msgDateFormat.format(new Date());
    }

    private static class ErrorStreamInterceptor extends PrintStream {

        public ErrorStreamInterceptor(OutputStream out) {
            super(out, true);
        }

        @Override
        public void print(String s) {
            super.print(s);
            if (logFileWriter != null) {
                logFileWriter.println(s);
            }
        }
    }

    private static String completeMsg(String msg, Object... params) {
        for (Object p : params)
            msg = msg.replaceFirst("\\{\\}", String.valueOf(p));
        return msg;
    }

    /**
     * Log msg with tag To save memory values will be concat to strings only
     * when log level really is set Use {} in the msg as wild card
     * 
     * @param logLevel
     * @param msg
     * @param params
     */
    public static void log(int logLevel, String tag, String msg, Object... params) {
        switch (logLevel) {
        case TRACE:
            trace(tag, msg, params);
            break;
        case DEBUG:
            debug(tag, msg, params);
            break;
        case INFO:
            info(tag, msg, params);
            break;
        case WARN:
            warn(tag, msg, params);
            break;
        case ERROR:
            error(tag, msg, params);
            break;
        case FATAL:
            fatal(tag, msg, params);
            break;
        default:
            error(tag, "Log level " + logLevel + " is not supported!");
        }
    }

    public final static void printHeadLine(String title) {
        print("|                  > " + title + " <)");
    }

    public final static void printUpperSeperationLine() {
        print("↓‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾BEGIN‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾↓");
    }

    public final static void printLowerSeperationLine() {
        print("↑_______________________END_______________________↑");
    }
}
commons/src/main/com/mbrlabs/mundus/commons/env/lights/BaseLight.java
public class BaseLight {

    public final Color color = new Color(1, 1, 1, 1);
    public float intensity = 1f;

}
editor/src/main/com/mbrlabs/mundus/editor/core/EditorScene.java
public class EditorScene extends Scene {

    public Viewport viewport;

    public EditorScene() {
        super();
    }

}
editor/src/main/com/mbrlabs/mundus/editor/scene3d/components/PickableModelComponent.java
public class PickableModelComponent extends ModelComponent implements PickableComponent {

    public PickableModelComponent(GameObject go, Shader shader) {
        super(go, shader);
    }

    @Override
    public void encodeRaypickColorId() {
        PickerIDAttribute goIDa = PickerColorEncoder.encodeRaypickColorId(gameObject);
        this.modelInstance.materials.first().set(goIDa);
    }

    @Override
    public void renderPick() {
        gameObject.sceneGraph.batch.render(modelInstance, Shaders.INSTANCE.getPickerShader());
    }

    @Override
    public Component clone(GameObject go) {
        PickableModelComponent mc = new PickableModelComponent(go, shader);
        mc.modelAsset = this.modelAsset;
        mc.modelInstance = new ModelInstance(modelAsset.getModel());
        mc.shader = this.shader;
        mc.encodeRaypickColorId();
        return mc;
    }
}
commons/src/main/com/mbrlabs/mundus/commons/assets/MaterialAsset.java
public class MaterialAsset extends Asset {

    private static final ObjectMap<String, String> MAP = new ObjectMap<String, String>();

    public static final String EXTENSION = ".mat";

    // property keys
    public static final String PROP_DIFFUSE_COLOR = "diffuse.color";
    public static final String PROP_DIFFUSE_TEXTURE = "diffuse.texture";
    public static final String PROP_MAP_NORMAL = "map.normal";
    public static final String PROP_SHININESS = "shininess";
    public static final String PROP_OPACITY = "opacity";

    // ids of dependent assets
    private String diffuseTextureID;
    private String normalMapID;

    private Color diffuseColor = Color.WHITE.cpy();
    private TextureAsset diffuseTexture;
    private TextureAsset normalMap;
    private float shininess = 0f;
    private float opacity = 0f;

    public MaterialAsset(Meta meta, FileHandle assetFile) {
        super(meta, assetFile);
    }

    @Override
    public void load() {
        MAP.clear();
        try {
            PropertiesUtils.load(MAP, file.reader());
            // shininess & opacity
            try {
                String value = MAP.get(PROP_SHININESS, null);
                if (value != null) {
                    shininess = Float.valueOf(value);
                }
                value = MAP.get(PROP_OPACITY, null);
                if (value != null) {
                    opacity = Float.valueOf(value);
                }
            } catch (NumberFormatException nfe) {
                nfe.printStackTrace();
            }

            // diffuse color
            String diffuseHex = MAP.get(PROP_DIFFUSE_COLOR);
            if (diffuseHex != null) {
                diffuseColor = Color.valueOf(diffuseHex);
            }

            // asset dependencies
            diffuseTextureID = MAP.get(PROP_DIFFUSE_TEXTURE, null);
            normalMapID = MAP.get(PROP_MAP_NORMAL, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Applies this material asset to the libGDX material.
     *
     * @param material
     * @return
     */
    public Material applyToMaterial(Material material) {
        if (diffuseColor != null) {
            material.set(new ColorAttribute(ColorAttribute.Diffuse, diffuseColor));
        }
        if (diffuseTexture != null) {
            material.set(new TextureAttribute(TextureAttribute.Diffuse, diffuseTexture.getTexture()));
        } else {
            material.remove(TextureAttribute.Diffuse);
        }
        material.set(new FloatAttribute(FloatAttribute.Shininess, shininess));

        return material;
    }

    public float getShininess() {
        return shininess;
    }

    public void setShininess(float shininess) {
        this.shininess = shininess;
    }

    public float getOpacity() {
        return opacity;
    }

    public void setOpacity(float opacity) {
        this.opacity = opacity;
    }

    public TextureAsset getNormalMap() {
        return normalMap;
    }

    public void setNormalMap(TextureAsset normalMap) {
        this.normalMap = normalMap;
        normalMapID = normalMap.getID();
    }

    public TextureAsset getDiffuseTexture() {
        return diffuseTexture;
    }

    public void setDiffuseTexture(TextureAsset diffuseTexture) {
        this.diffuseTexture = diffuseTexture;
        if (diffuseTexture != null) {
            this.diffuseTextureID = diffuseTexture.getID();
        } else {
            this.diffuseTextureID = null;
        }
    }

    public Color getDiffuseColor() {
        return diffuseColor;
    }

    @Override
    public void resolveDependencies(Map<String, Asset> assets) {
        if (diffuseTextureID != null && assets.containsKey(diffuseTextureID)) {
            diffuseTexture = (TextureAsset) assets.get(diffuseTextureID);
        }
        if (normalMapID != null && assets.containsKey(normalMapID)) {
            normalMap = (TextureAsset) assets.get(normalMapID);
        }
    }

    @Override
    public void applyDependencies() {
        // nothing to apply
    }

    @Override
    public void dispose() {
        // nothing to dispose
    }

}
commons/src/main/com/mbrlabs/mundus/commons/Scene.java
public class Scene implements Disposable {

    private String name;
    private long id;

    public SceneGraph sceneGraph;
    public MundusEnvironment environment;
    public Skybox skybox;

    @Deprecated // TODO not here
    public Array<TerrainAsset> terrains;
    @Deprecated // TODO not here
    public GameObject currentSelection;

    public PerspectiveCamera cam;

    public Scene() {
        environment = new MundusEnvironment();
        currentSelection = null;
        terrains = new Array<TerrainAsset>();

        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(0, 1, -3);
        cam.lookAt(0, 1, -1);
        cam.near = 0.2f;
        cam.far = 10000;

        DirectionalLight dirLight = new DirectionalLight();
        dirLight.color.set(1, 1, 1, 1);
        dirLight.intensity = 1f;
        dirLight.direction.set(0, -1f, 0);
        dirLight.direction.nor();
        environment.add(dirLight);
        environment.getAmbientLight().intensity = 0.3f;

        sceneGraph = new SceneGraph(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Override
    public void dispose() {
        if (skybox != null) {
            skybox.dispose();
        }
    }
}


Question: import java.util.Locale;
import java.util.Map;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.JsonWriter;
import com.mbrlabs.mundus.commons.Scene;
import com.mbrlabs.mundus.commons.assets.Asset;
import com.mbrlabs.mundus.commons.assets.MaterialAsset;
import com.mbrlabs.mundus.commons.assets.ModelAsset;
import com.mbrlabs.mundus.commons.assets.TerrainAsset;
import com.mbrlabs.mundus.commons.env.Fog;
import com.mbrlabs.mundus.commons.env.lights.BaseLight;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.SceneGraph;
import com.mbrlabs.mundus.commons.scene3d.components.Component;
import com.mbrlabs.mundus.editor.core.EditorScene;
import com.mbrlabs.mundus.editor.core.kryo.descriptors.*;
import com.mbrlabs.mundus.editor.core.project.ProjectContext;
import com.mbrlabs.mundus.editor.core.project.ProjectSettings;
import com.mbrlabs.mundus.editor.core.registry.KeyboardLayout;
import com.mbrlabs.mundus.editor.core.registry.ProjectRef;
import com.mbrlabs.mundus.editor.core.registry.Registry;
import com.mbrlabs.mundus.editor.core.registry.Settings;
import com.mbrlabs.mundus.editor.scene3d.components.PickableModelComponent;
import com.mbrlabs.mundus.editor.scene3d.components.PickableTerrainComponent;
import com.mbrlabs.mundus.editor.shader.Shaders;
import com.mbrlabs.mundus.editor.utils.Log;
        return go;
    }

    public static GameObjectDescriptor convert(GameObject go) {

        GameObjectDescriptor descriptor = new GameObjectDescriptor();
        descriptor.setName(go.name);
        descriptor.setId(go.id);
        descriptor.setActive(go.active);

        // translation
        go.getLocalPosition(tempVec);
        final float[] transform = descriptor.getTransform();
        transform[0] = tempVec.x;
        transform[1] = tempVec.y;
        transform[2] = tempVec.z;

        // rotation
        go.getLocalRotation(tempQuat);
        transform[3] = tempQuat.x;
        transform[4] = tempQuat.y;
        transform[5] = tempQuat.z;
        transform[6] = tempQuat.w;

        // scaling
        go.getLocalScale(tempVec);
        transform[7] = tempVec.x;
        transform[8] = tempVec.y;
        transform[9] = tempVec.z;

        // convert components
        for (Component c : go.getComponents()) {
            if (c.getType() == Component.Type.MODEL) {
                descriptor.setModelComponent(convert((PickableModelComponent) c));
            } else if (c.getType() == Component.Type.TERRAIN) {
                descriptor.setTerrainComponent(convert((PickableTerrainComponent) c));
            }
        }

        // TODO TAGS !!!!!!!!!!!!!!!!!!!!!!!!!!!

        // recursively convert children
        if (go.getChildren() != null) {
            for (GameObject c : go.getChildren()) {
                descriptor.getChilds().add(convert(c));
            }
        }

        return descriptor;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // ModelComponent
    /////////////////////////////////////////////////////////////////////////////////////////////////////

    public static PickableModelComponent convert(ModelComponentDescriptor descriptor, GameObject go,
            Map<String, Asset> assets) {
        ModelAsset model = (ModelAsset) assets.get(descriptor.getModelID());

        if (model == null) {
            Log.fatal(TAG, "MModel for MModelInstance not found: {}", descriptor.getModelID());
            return null;
        }

        PickableModelComponent component = new PickableModelComponent(go, Shaders.INSTANCE.getModelShader());
        component.setModel(model, false);

        for (String g3dbMatID : descriptor.getMaterials().keySet()) {
            String uuid = descriptor.getMaterials().get(g3dbMatID);
            MaterialAsset matAsset = (MaterialAsset) assets.get(uuid);
            component.getMaterials().put(g3dbMatID, matAsset);
        }

        return component;
    }

    public static ModelComponentDescriptor convert(PickableModelComponent modelComponent) {
        ModelComponentDescriptor descriptor = new ModelComponentDescriptor();
        descriptor.setModelID(modelComponent.getModelAsset().getID());

        // materials
        for (String g3dbMatID : modelComponent.getMaterials().keys()) {
            descriptor.getMaterials().put(g3dbMatID, modelComponent.getMaterials().get(g3dbMatID).getID());
        }

        return descriptor;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // TerrainComponent
    /////////////////////////////////////////////////////////////////////////////////////////////////////

    public static PickableTerrainComponent convert(TerrainComponentDescriptor descriptor, GameObject go,
            Map<String, Asset> assets) {
        // find terrainAsset
        TerrainAsset terrain = (TerrainAsset) assets.get(descriptor.getTerrainID());

        if (terrain == null) {
            Log.fatal(TAG, "Terrain for TerrainInstance not found");
            return null;
        }

        terrain.getTerrain().transform = go.getTransform();
        PickableTerrainComponent terrainComponent = new PickableTerrainComponent(go, Shaders.INSTANCE.getTerrainShader());
        terrainComponent.setTerrain(terrain);

        return terrainComponent;
    }

    public static TerrainComponentDescriptor convert(PickableTerrainComponent terrainComponent) {
        TerrainComponentDescriptor descriptor = new TerrainComponentDescriptor();
        descriptor.setTerrainID(terrainComponent.getTerrain().getID());

        return descriptor;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // Fog
    /////////////////////////////////////////////////////////////////////////////////////////////////////

Answer:     public static Fog convert(FogDescriptor fogDescriptor) {