1 module core.prefabs;
2 import core.gameobject;
3 import components;
4 import utility.filepath, utility.config;
5 
6 import yaml;
7 import gl3n.linalg;
8 import std.variant;
9 
10 final abstract class Prefabs
11 {
12 public static:
13 	alias prefabs this;
14 
15 	Prefab[string] prefabs;
16 
17 	void initialize()
18 	{
19 		foreach( key; prefabs.keys )
20 			prefabs.remove( key );
21 
22 		void addObject( Node object )
23 		{
24 			auto name = object[ "Name" ].as!string;
25 
26 			prefabs[ name ] = new Prefab( object );
27 		}
28 
29 		foreach( file; FilePath.scanDirectory( FilePath.Resources.Prefabs, "*.yml" ) )
30 		{
31 			auto object = Config.loadYaml( file.fullPath );
32 
33 			if( object.isSequence() )
34 				foreach( Node innerObj; object )
35 					addObject( innerObj );
36 			else
37 				addObject( object );
38 		}
39 	}
40 }
41 
42 final class Prefab
43 {
44 public:
45 	this( Node yml )
46 	{
47 		transform = new Transform;
48 		Variant prop;
49 		Node innerNode;
50 
51 		// Try to get from script
52 		if( Config.tryGet!string( "Script.ClassName", prop, yml ) )
53 			scriptClass = ClassInfo.find( prop.get!string );
54 		else
55 			scriptClass = null;
56 
57 		if( Config.tryGet!string( "Camera", prop, yml ) )
58 		{
59 			//TODO: Setup camera
60 		}
61 
62 		if( Config.tryGet!string( "Material", prop, yml ) )
63 			componentReferences ~= Assets.get!Material( prop.get!string );
64 
65 		if( Config.tryGet!string( "AwesomiumView", prop, yml ) )
66 		{
67 			//TODO: Initialize Awesomium view
68 		}
69 
70 		if( Config.tryGet!string( "Mesh", prop, yml ) )
71 			componentReferences ~= Assets.get!Mesh( prop.get!string );
72 
73 		if( Config.tryGet( "Transform", innerNode, yml ) )
74 		{
75 			vec3 transVec;
76 			if( Config.tryGet( "Scale", transVec, innerNode ) )
77 				transform.scale = transVec;
78 			if( Config.tryGet( "Position", transVec, innerNode ) )
79 				transform.position = transVec;
80 			if( Config.tryGet( "Rotation", transVec, innerNode ) )
81 				transform.rotation = quat.euler_rotation( transVec.y, transVec.z, transVec.x );
82 		}
83 
84 		if( Config.tryGet!Light( "Light", prop, innerNode ) )
85 		{
86 			componentReferences ~= prop.get!Light;
87 		}
88 	}
89 
90 	this()
91 	{
92 		transform = new Transform;
93 		scriptClass = null;
94 	}
95 
96 	final GameObject createInstance( const ClassInfo overrideScript = null )
97 	{
98 		GameObject result;
99 
100 		auto script = overrideScript is null ? scriptClass : overrideScript;
101 
102 		if( script )
103 			result = cast(GameObject)script.create();
104 		else
105 			result = new GameObject;
106 
107 		result.transform.scale.vector[ 0..3 ] = transform.scale.vector[ 0..3 ];
108 		result.transform.position.vector[ 0..3 ] = transform.position.vector[ 0..3 ];
109 		result.transform.rotation.x = transform.rotation.x;
110 		result.transform.rotation.y = transform.rotation.y;
111 		result.transform.rotation.z = transform.rotation.z;
112 		//result.transform.rotation.w = transform.rotation.w;
113 
114 		foreach( cpn; componentReferences )
115 			result.addComponent( cpn );
116 
117 		foreach( cpncls; componentCreations )
118 		{
119 			auto inst = cast(Component)cpncls.create();
120 			result.addComponent( inst );
121 			inst.owner = result;
122 		}
123 
124 		result.transform.updateMatrix();
125 
126 		return result;
127 	}
128 
129 private:
130 	const ClassInfo scriptClass;
131 	Transform transform;
132 	Component[] componentReferences;
133 	ClassInfo[] componentCreations;
134 }