1 
2 module ws.gl.model;
3 
4 import file = std.file, std.parallelism;
5 
6 import
7 	std.path,
8 	std.file,
9 	std.algorithm,
10 	std.conv,
11 	ws.io,
12 	ws.exception,
13 	ws.thread.loader,
14 	ws.gl.gl,
15 	ws.gl.batch,
16 	ws.gl.texture,
17 	ws.gl.material,
18 	ws.file.obj,
19 	ws.file.bbatch,
20 	ws.log,
21 	ws.string,
22 	ws.math.vector;
23 
24 
25 __gshared:
26 
27 
28 class Model: Loadable {
29 
30 	string path;
31 	BatchMaterial[] data;
32 
33 	alias Ptr=void*;
34 	bool[Ptr] alreadyAdded;
35 
36 	package Loader batchFinisher;
37 	package Loader materialFinisher;
38 	package Loader glFinisher;
39 
40 	this(string p, Loader glFinisher=null, Loader batchFinisher=null, Loader materialFinisher=null){
41 		path = p;
42 		this.batchFinisher = batchFinisher;
43 		this.materialFinisher = materialFinisher;
44 		this.glFinisher = glFinisher;
45 		if(glFinisher)
46 			glFinisher.run(&finish);
47 		else
48 			finish;
49 	}
50 
51 	override protected void finish(){
52 		loadState = Loading;
53 		if(path.extension == ".obj"){
54 			auto mdl = new OBJ("models/" ~ path);
55 			long count=0;
56 			foreach(object; mdl.objects){
57 				object.materials.values.each!((material){
58 					count++;
59 					auto b = new BatchMaterial;
60 					if(batchFinisher)
61 						batchFinisher.run({
62 							b.batch = modelBatch(material);
63 						});
64 					else if(!glFinisher)
65 						b.batch = modelBatch(material);
66 					else
67 						assert(0, "Running in glFinisher but no way to finish batch in main");
68 					try
69 						b.material = modelMaterial(mdl, material.name, materialFinisher);
70 					catch(Exception e)
71 						Log.warning(e.toString());
72 					data ~= b;
73 				});
74 			}
75 		}else if(path.extension == ".bb"){
76 			BinaryBatch mdl;
77 			if(!exists("models/" ~ path)){
78 				mdl = BinaryBatch.fromObj(path.setExtension("obj"));
79 				mdl.save;
80 			}else
81 				mdl = new BinaryBatch(path);
82 			foreach(vm; mdl.data){
83 				auto b = new BatchMaterial;
84 				data ~= b;
85 				batchFinisher.run({
86 					b.batch = modelBatch(vm);
87 				});
88 			}
89 		}else{
90 			assert(0, "Unknown extension in " ~ path);
91 		}
92 		loadState = Loaded;
93 
94 	}
95 
96 }
97 
98 
99 class BatchMaterial {
100 	Batch batch;
101 	DeferredMaterial material;
102 }
103 
104 
105 auto modelMaterial(OBJ mdl, string material_name, Loader materialFinisher=null){
106 	auto material = new DeferredMaterial(mdl.path ~ ':' ~ material_name);
107 	float[3] col = [1,1,1];
108 	material.addUniform("diffuseColor", col);
109 	bool hasDiffuse = false;
110 	bool hasNormal = false;
111 	foreach(mtllib; mdl.mtllibs){
112 		foreach(mtl; mtllib.mtls){
113 			if(mtl.name == material_name){
114 				if(mtl.mapDiffuse.length){
115 					material.linkVertex("diffuse_tex", "forwardTexCoords");
116 					material.linkFragment("diffuse_tex");
117 					material.addTexture("diffuse", mtl.mapDiffuse);
118 					hasDiffuse = true;
119 				}
120 				if(mtl.illum == 0)
121 					material.linkFragment("unlit");
122 				else
123 					material.linkFragment("lit");
124 				if(mtl.mapBump.length){
125 					//material.linkVertex("normal_bump");
126 					material.linkFragment("normal_bump");
127 					material.addTexture("normal_bump", mtl.mapBump);
128 					hasNormal = true;
129 				}
130 				break;
131 			}
132 		}
133 	}
134 	if(!hasDiffuse){
135 		material.linkFragment("diffuse_default");
136 	}
137 	if(!hasNormal){
138 		material.linkVertex("normal_default", "forwardNormal");
139 		material.linkFragment("normal_default");
140 	}
141 	if(materialFinisher)
142 		materialFinisher.run(&material.finish);
143 	else
144 		material.finish;
145 	return material;
146 }
147 
148 
149 auto modelBatch(OBJ.Material material){
150 	auto batch = new Batch;
151 	batch.begin(material.vertcount);
152 	foreach(polygon; material.polygons){
153 		foreach(vertex; polygon.vertices){
154 			float[2] uvw = vertex.uvw.data[0..2];
155 			batch.addPoint(vertex.pos, vertex.normal, uvw);
156 		}
157 	}
158 	batch.finish;
159 	return batch;
160 }
161 
162 auto modelBatch(VertMat vm){
163 	auto batch = new Batch;
164 	batch.begin(cast(int)(vm.vertices.length));
165 	foreach(vert; vm.vertices)
166 		batch.addPoint(vert[0..3], vert[3..6], vert[6..8]);
167 	batch.finish;
168 	return batch;
169 }
170 
171 
172