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) return {
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