1 module dlangui.graphics.scene.objimport; 2 3 public import dlangui.core.config; 4 static if (ENABLE_OPENGL): 5 static if (BACKEND_GUI): 6 7 import dlangui.core.logger; 8 import dlangui.core.math3d; 9 import dlangui.dml.tokenizer; 10 import dlangui.graphics.scene.mesh; 11 12 struct ObjModelImport { 13 alias FaceIndex = int[3]; 14 15 private float[] _vertexData; 16 private float[] _normalData; 17 private float[] _txData; 18 private int _vertexCount; 19 private int _normalCount; 20 private int _triangleCount; 21 private int _txCount; 22 private float[8] _buf; 23 24 MeshRef mesh; 25 26 protected float[] parseFloatList(Token[] tokens, int maxItems = 3, float padding = 0) { 27 int i = 0; 28 int sgn = 1; 29 foreach(t; tokens) { 30 if (i >= maxItems) 31 break; 32 if (t.type == TokenType.floating) { 33 _buf[i++] = cast(float)(t.floatvalue * sgn); 34 sgn = 1; 35 } else if (t.type == TokenType.integer) { 36 _buf[i++] = cast(float)(t.intvalue * sgn); 37 sgn = 1; 38 } else if (t.type == TokenType.minus) { 39 sgn = -1; 40 } 41 } 42 while(i < maxItems) 43 _buf[i++] = padding; 44 if (i > 0) 45 return _buf[0 .. i]; 46 return null; 47 } 48 //# List of geometric vertices, with (x,y,z[,w]) coordinates, w is optional and defaults to 1.0. 49 //v 0.123 0.234 0.345 1.0 50 protected bool parseVertexLine(Token[] tokens) { 51 float[] data = parseFloatList(tokens, 3, 0); 52 if (data.length == 3) { 53 _vertexData ~= data; 54 _vertexCount++; 55 return true; 56 } 57 return false; 58 } 59 //# List of texture coordinates, in (u, v [,w]) coordinates, these will vary between 0 and 1, w is optional and defaults to 0. 60 //vt 0.500 1 [0] 61 protected bool parseVertexTextureLine(Token[] tokens) { 62 float[] data = parseFloatList(tokens, 2, 0); 63 if (data.length == 2) { 64 _txData ~= data; 65 _txCount++; 66 return true; 67 } 68 return false; 69 } 70 //# List of vertex normals in (x,y,z) form; normals might not be unit vectors. 71 //vn 0.707 0.000 0.707 72 protected bool parseVertexNormalsLine(Token[] tokens) { 73 float[] data = parseFloatList(tokens, 3, 0); 74 if (data.length == 3) { 75 _normalData ~= data; 76 _normalCount++; 77 return true; 78 } 79 return false; 80 } 81 82 static protected bool skipToken(ref Token[] tokens) { 83 tokens = tokens.length > 1 ? tokens[1 .. $] : null; 84 return tokens.length > 0; 85 } 86 static protected bool parseIndex(ref Token[] tokens, ref int data) { 87 int sign = 1; 88 if (tokens[0].type == TokenType.minus) { 89 sign = -1; 90 skipToken(tokens); 91 } 92 if (tokens[0].type == TokenType.integer) { 93 data = tokens[0].intvalue * sign; 94 skipToken(tokens); 95 return true; 96 } 97 return false; 98 } 99 static protected bool skip(ref Token[] tokens, TokenType type) { 100 if (tokens.length > 0 && tokens[0].type == type) { 101 skipToken(tokens); 102 return true; 103 } 104 return false; 105 } 106 static protected bool parseFaceIndex(ref Token[] tokens, ref FaceIndex data) { 107 int i = 0; 108 if (tokens.length == 0) 109 return false; 110 if (!parseIndex(tokens, data[0])) 111 return false; 112 if (skip(tokens, TokenType.divide)) { 113 parseIndex(tokens, data[1]); 114 if (skip(tokens, TokenType.divide)) { 115 if (!parseIndex(tokens, data[2])) 116 return false; 117 } 118 } 119 return tokens.length == 0 || skip(tokens, TokenType.whitespace); 120 } 121 //# Parameter space vertices in ( u [,v] [,w] ) form; free form geometry statement ( see below ) 122 //vp 0.310000 3.210000 2.100000 123 protected bool parseParameterSpaceLine(Token[] tokens) { 124 // not supported 125 126 return true; 127 } 128 129 //f 1 2 3 130 //f 3/1 4/2 5/3 131 //f 6/4/1 3/5/3 7/6/5 132 protected bool parseFaceLine(Token[] tokens) { 133 FaceIndex[10] indexes; 134 int i = 0; 135 while(parseFaceIndex(tokens, indexes[i])) { 136 if (++i >= 10) 137 break; 138 } 139 for (int j = 1; j + 1 < i; j++) 140 addTriangle(indexes[0], indexes[j], indexes[j + 1]); 141 return true; 142 } 143 144 vec3 vertexForIndex(int index) { 145 if (index < 0) 146 index = _vertexCount + 1 + index; 147 if (index >= 1 && index <= _vertexCount) { 148 index = (index - 1) * 3; 149 return vec3(&_vertexData[index]); 150 } 151 return vec3.init; 152 } 153 154 vec3 normalForIndex(int index) { 155 if (index < 0) 156 index = _normalCount + 1 + index; 157 if (index >= 1 && index <= _normalCount) { 158 index = (index - 1) * 3; 159 return vec3(&_normalData[index]); 160 } 161 return vec3(0, 0, 1); 162 } 163 164 vec2 txForIndex(int index) { 165 if (index < 0) 166 index = _txCount + 1 + index; 167 if (index >= 1 && index <= _txCount) { 168 index = (index - 1) * 2; 169 return vec2(&_txData[index]); 170 } 171 return vec2.init; 172 } 173 174 bool _meshHasTexture; 175 void createMeshIfNotExist() { 176 if (!mesh.isNull) 177 return; 178 if (_txCount) { 179 mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, /*VertexElementType.COLOR, */ VertexElementType.TEXCOORD0)); 180 _meshHasTexture = true; 181 } else { 182 mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL /*, VertexElementType.COLOR*/)); 183 _meshHasTexture = false; 184 } 185 } 186 protected bool addTriangle(FaceIndex v1, FaceIndex v2, FaceIndex v3) { 187 createMeshIfNotExist(); 188 float[16 * 3] data; 189 const (VertexFormat) * fmt = mesh.vertexFormatPtr; 190 int vfloats = fmt.vertexFloats; 191 vec3 p1 = vertexForIndex(v1[0]); 192 vec3 p2 = vertexForIndex(v2[0]); 193 vec3 p3 = vertexForIndex(v3[0]); 194 fmt.set(data.ptr, VertexElementType.POSITION, p1); 195 fmt.set(data.ptr + vfloats, VertexElementType.POSITION, p2); 196 fmt.set(data.ptr + vfloats * 2, VertexElementType.POSITION, p3); 197 if (fmt.hasElement(VertexElementType.TEXCOORD0)) { 198 fmt.set(data.ptr, VertexElementType.TEXCOORD0, txForIndex(v1[1])); 199 fmt.set(data.ptr + vfloats, VertexElementType.TEXCOORD0, txForIndex(v2[1])); 200 fmt.set(data.ptr + vfloats * 2, VertexElementType.TEXCOORD0, txForIndex(v3[1])); 201 } 202 if (fmt.hasElement(VertexElementType.COLOR)) { 203 const vec4 white = vec4(1, 1, 1, 1); 204 fmt.set(data.ptr, VertexElementType.COLOR, white); 205 fmt.set(data.ptr + vfloats, VertexElementType.COLOR, white); 206 fmt.set(data.ptr + vfloats * 2, VertexElementType.COLOR, white); 207 } 208 if (fmt.hasElement(VertexElementType.NORMAL)) { 209 vec3 normal; 210 if (!v1[2] || !v2[2] || !v3[2]) { 211 // no normal specified, calculate it 212 normal = triangleNormal(p1, p2, p3); 213 } 214 fmt.set(data.ptr, VertexElementType.NORMAL, v1[2] ? normalForIndex(v1[2]) : normal); 215 fmt.set(data.ptr + vfloats, VertexElementType.NORMAL, v2[2] ? normalForIndex(v2[2]) : normal); 216 fmt.set(data.ptr + vfloats * 2, VertexElementType.NORMAL, v3[2] ? normalForIndex(v3[2]) : normal); 217 } 218 int startVertex = mesh.addVertexes(data.ptr[0 .. vfloats * 3]); 219 mesh.addPart(PrimitiveType.triangles, [ 220 cast(ushort)(startVertex + 0), 221 cast(ushort)(startVertex + 1), 222 cast(ushort)(startVertex + 2)]); 223 _triangleCount++; 224 return true; 225 } 226 227 protected bool parseLine(Token[] tokens) { 228 tokens = trimSpaceTokens(tokens); 229 if (tokens.length) { 230 if (tokens[0].type == TokenType.comment) 231 return true; // ignore comment 232 if (tokens[0].type == TokenType.ident) { 233 string ident = tokens[0].text; 234 tokens = trimSpaceTokens(tokens[1 .. $], true, false); 235 if (ident == "v") // vertex 236 return parseVertexLine(tokens); 237 if (ident == "vt") // texture coords 238 return parseVertexTextureLine(tokens); 239 if (ident == "vn") // normals 240 return parseVertexNormalsLine(tokens); 241 if (ident == "vp") // parameter space 242 return parseParameterSpaceLine(tokens); 243 if (ident == "f") // face 244 return parseFaceLine(tokens); 245 } 246 } 247 return true; 248 } 249 bool parse(string source) { 250 import dlangui.dml.tokenizer; 251 try { 252 Token[] tokens = tokenize(source, ["#"]); 253 int start = 0; 254 int i = 0; 255 for ( ; i <= tokens.length; i++) { 256 if (i == tokens.length || tokens[i].type == TokenType.eol) { 257 if (i > start && !parseLine(tokens[start .. i])) 258 return false; 259 start = i + 1; 260 } 261 } 262 } catch (ParserException e) { 263 Log.d("failed to tokenize OBJ source", e); 264 return false; 265 } 266 return true; 267 } 268 269 } 270