1 /* 2 Copyright (c) 2014-2015 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 module dgl.asset.dgl2; 30 31 import std.stdio; 32 import std.string; 33 import std.conv; 34 import std.format; 35 import std.path; 36 37 import dlib.core.memory; 38 import dlib.core.stream; 39 import dlib.filesystem.filesystem; 40 import dlib.math.vector; 41 import dlib.math.quaternion; 42 import dlib.geometry.triangle; 43 44 import dgl.dml.dml; 45 import dgl.graphics.material; 46 import dgl.graphics.texture; 47 import dgl.graphics.scene; 48 import dgl.graphics.entity; 49 import dgl.graphics.mesh; 50 import dgl.asset.resman; 51 import dgl.asset.serialization; 52 53 /* 54 * DGL2 is a simple chunk-based binary scene format for DGL. It is a successor of DGL format (DGL1). 55 * Main change from DGL1 is the usage of DML (DGL Markup Language) instead of JSON for serializing game-specific properties. 56 * DGL2 supports meshes, entities and per-polygon materials with maximum of 8 texture slots. 57 * You can create DGL2 scenes in Blender, via our exporter (io_export_dgl2.py). 58 */ 59 60 //version = DGLDebug; 61 62 enum ChunkType 63 { 64 HEADER = 0, 65 END = 1, 66 TRIMESH = 2, 67 MATERIAL = 3, 68 ENTITY = 4 69 } 70 71 struct DataChunk 72 { 73 ushort type; 74 int id; 75 ushort nameSize; 76 uint dataSize; 77 string name; 78 ubyte[] data; 79 80 string toString() 81 { 82 return format( 83 "type = %s\nid = %s\nnameSize = %s\ndataSize = %s\nname = %s", 84 type.to!ChunkType, id, 85 nameSize, dataSize, name 86 ); 87 } 88 89 void free() 90 { 91 if (name.length) 92 Delete(name); 93 if (data.length) 94 Delete(data); 95 } 96 } 97 98 struct DGLTriangle 99 { 100 int m; 101 Vector3f[3] v; 102 Vector3f[3] n; 103 Vector2f[3] uv1; 104 Vector2f[3] uv2; 105 } 106 107 void calcTriangleData(Triangle* tri, DGLTriangle* dglTri) 108 { 109 tri.v[0] = dglTri.v[0]; 110 tri.v[1] = dglTri.v[1]; 111 tri.v[2] = dglTri.v[2]; 112 113 tri.n[0] = dglTri.n[0]; 114 tri.n[1] = dglTri.n[1]; 115 tri.n[2] = dglTri.n[2]; 116 117 tri.t1[0] = dglTri.uv1[0]; 118 tri.t1[1] = dglTri.uv1[1]; 119 tri.t1[2] = dglTri.uv1[2]; 120 121 tri.t2[0] = dglTri.uv2[0]; 122 tri.t2[1] = dglTri.uv2[1]; 123 tri.t2[2] = dglTri.uv2[2]; 124 125 tri.materialIndex = dglTri.m; 126 127 tri.normal = planeNormal(tri.v[0], tri.v[1], tri.v[2]); 128 129 tri.barycenter = (tri.v[0] + tri.v[1] + tri.v[2]) / 3; 130 131 tri.d = (tri.v[0].x * tri.normal.x + 132 tri.v[0].y * tri.normal.y + 133 tri.v[0].z * tri.normal.z); 134 135 tri.edges[0] = tri.v[1] - tri.v[0]; 136 tri.edges[1] = tri.v[2] - tri.v[1]; 137 tri.edges[2] = tri.v[0] - tri.v[2]; 138 } 139 140 void loadDGL2(InputStream istrm, Scene scene) 141 { 142 assert(scene !is null); 143 144 DataChunk readChunk() 145 { 146 DataChunk chunk; 147 chunk.type = read!ushort(istrm); 148 chunk.id = read!int(istrm); 149 chunk.nameSize = read!ushort(istrm); 150 chunk.dataSize = read!uint(istrm); 151 152 if (chunk.nameSize > 0) 153 { 154 auto nameData = New!(ubyte[])(chunk.nameSize); 155 istrm.fillArray(nameData); 156 chunk.name = cast(string)nameData; 157 } 158 159 if (chunk.dataSize > 0) 160 { 161 chunk.data = New!(ubyte[])(chunk.dataSize); 162 istrm.fillArray(chunk.data); 163 } 164 165 return chunk; 166 } 167 168 DataChunk chunk; 169 while (chunk.type != ChunkType.END && istrm.readable) 170 { 171 chunk = readChunk(); 172 version(DGLDebug) writefln("----\nChunk:\n%s", chunk); 173 174 if (chunk.type == ChunkType.ENTITY) 175 { 176 Entity e = New!Entity(); 177 e.id = chunk.id; 178 // TODO: duplicate 179 //e.name = chunk.name; 180 auto dataStrm = New!ArrayStream(chunk.data, chunk.data.length); 181 decodeEntity(e, dataStrm, scene); 182 Delete(dataStrm); 183 184 version(DGLDebug) writefln("----\nEntity:\n%s", e); 185 scene.addEntity(chunk.name, e); 186 } 187 else if (chunk.type == ChunkType.MATERIAL) 188 { 189 Material mat = New!Material(); 190 mat.id = chunk.id; 191 // TODO: duplicate 192 //mat.name = chunk.name; 193 auto dataStrm = New!ArrayStream(chunk.data, chunk.data.length); 194 decodeMaterial(mat, dataStrm, scene); 195 Delete(dataStrm); 196 197 version(DGLDebug) writefln("----\nMaterial:\n%s", mat); 198 scene.addMaterial(chunk.name, mat); 199 } 200 else if (chunk.type == ChunkType.TRIMESH) 201 { 202 assert(!(chunk.data.length % DGLTriangle.sizeof)); // Check data integrity 203 size_t numTris = chunk.data.length / DGLTriangle.sizeof; 204 Triangle[] tris = New!(Triangle[])(numTris); 205 auto mtris = cast(DGLTriangle[])chunk.data; 206 uint offset = 0; 207 208 foreach(i, mtri; mtris) 209 { 210 Triangle* tri = &tris[offset]; 211 calcTriangleData(tri, &mtri); 212 offset++; 213 } 214 215 Mesh mesh = New!Mesh(tris); 216 mesh.id = chunk.id; 217 // TODO: duplicate 218 //mesh.name = chunk.name; 219 scene.addMesh(chunk.name, mesh); 220 221 version(DGLDebug) writefln("numTris: %s", numTris); 222 } 223 224 chunk.free(); 225 } 226 227 version(DGLDebug) writeln("end"); 228 } 229 230 void decodeEntity(Entity e, InputStream istrm, Scene scene) 231 { 232 e.type = read!uint(istrm); 233 e.materialId = read!int(istrm); 234 e.meshId = read!int(istrm); 235 236 Vector3f position = read!(Vector3f, true)(istrm); 237 Quaternionf rotation = read!(Quaternionf, true)(istrm); 238 Vector3f scaling = read!(Vector3f, true)(istrm); 239 e.setTransformation(position, rotation, scaling); 240 241 DMLData dml; 242 auto dmlSize = read!uint(istrm); 243 if (dmlSize > 0) 244 { 245 auto dmlBytes = New!(ubyte[])(dmlSize); 246 istrm.fillArray(dmlBytes); 247 string dmlStr = cast(string)dmlBytes; 248 version(DGLDebug) writefln("----\ndmlStr:\n%s", dmlStr); 249 parseDML(dmlStr, &dml); 250 Delete(dmlBytes); 251 } 252 e.props = dml; 253 254 if ("visible" in dml.root.data) 255 e.visible = cast(bool)dml.root.data["visible"].toInt; 256 } 257 258 void decodeMaterial(Material m, InputStream istrm, Scene scene) 259 { 260 DMLData dml; 261 262 auto dmlSize = read!uint(istrm); 263 if (dmlSize > 0) 264 { 265 auto dmlBytes = New!(ubyte[])(dmlSize); 266 istrm.fillArray(dmlBytes); 267 string dmlStr = cast(string)dmlBytes; 268 version(DGLDebug) writefln("----\ndmlStr:\n%s", dmlStr); 269 parseDML(dmlStr, &dml); 270 Delete(dmlBytes); 271 } 272 273 if ("diffuseColor" in dml.root.data) 274 m.diffuseColor = dml.root.data["diffuseColor"].toColor4f; 275 276 if ("specularColor" in dml.root.data) 277 m.specularColor = dml.root.data["specularColor"].toColor4f; 278 279 if ("shadeless" in dml.root.data) 280 m.shadeless = dml.root.data["shadeless"].toBool; 281 282 if ("texturesNum" in dml.root.data) 283 { 284 int numTextures = dml.root.data["texturesNum"].toInt; 285 foreach(i; 0..numTextures) 286 { 287 string texId = format("texture%s", i); 288 if (texId in dml.root.data) 289 { 290 string texStr = dml.root.data[texId].toString; 291 string filename; 292 int blendType; 293 formattedRead(texStr, "[%s, %s]", &filename, &blendType); 294 Texture tex = scene.getTexture(filename); 295 m.textures[i] = tex; 296 } 297 } 298 } 299 300 dml.free(); 301 } 302 303