Browse Source

Move .obj parser to c

luboslenco 2 years ago
parent
commit
b79cc6060c

+ 2 - 0
armorlab/kincflags.js

@@ -8,6 +8,8 @@ flags.with_tinydir = true;
 flags.with_zlib = true;
 flags.with_zlib = true;
 flags.with_stb_image_write = true;
 flags.with_stb_image_write = true;
 flags.with_onnx = true;
 flags.with_onnx = true;
+flags.with_g2 = true;
+flags.with_iron = true;
 
 
 flags.on_project_created = async function(project) {
 flags.on_project_created = async function(project) {
 	project.addDefine('IDLE_SLEEP');
 	project.addDefine('IDLE_SLEEP');

+ 2 - 0
armorpaint/kincflags.js

@@ -7,6 +7,8 @@ flags.with_nfd = true;
 flags.with_tinydir = true;
 flags.with_tinydir = true;
 flags.with_zlib = true;
 flags.with_zlib = true;
 flags.with_stb_image_write = true;
 flags.with_stb_image_write = true;
+flags.with_g2 = true;
+flags.with_iron = true;
 
 
 flags.on_project_created = async function(project) {
 flags.on_project_created = async function(project) {
 	project.addDefine('IDLE_SLEEP');
 	project.addDefine('IDLE_SLEEP');

+ 0 - 507
base/Sources/arm/format/ObjParser.hx

@@ -1,507 +0,0 @@
-package arm.format;
-
-class ObjParser {
-
-	public static var splitCode = "o".code; // Object split, "g" for groups, "u"semtl for materials
-	public var posa: kha.arrays.Int16Array = null;
-	public var nora: kha.arrays.Int16Array = null;
-	public var texa: kha.arrays.Int16Array = null;
-	public var inda: kha.arrays.Uint32Array = null;
-	public var udims: Array<kha.arrays.Uint32Array> = null; // Indices split per udim tile
-	public var udimsU = 1; // Number of horizontal udim tiles
-	public var scalePos = 1.0;
-	public var scaleTex = 1.0;
-	public var name = "";
-	public var hasNext = false; // File contains multiple objects
-	public var pos = 0;
-	var posTemp: Array<Float>;
-	var uvTemp: Array<Float>;
-	var norTemp: Array<Float>;
-	var va: kha.arrays.Uint32Array;
-	var ua: kha.arrays.Uint32Array;
-	var na: kha.arrays.Uint32Array;
-	var vi = 0;
-	var ui = 0;
-	var ni = 0;
-	var buf: haxe.io.UInt8Array = null;
-
-	static var vindOff = 0;
-	static var tindOff = 0;
-	static var nindOff = 0;
-	static var bytes: haxe.io.Bytes = null;
-	static var posFirst: Array<Float>;
-	static var uvFirst: Array<Float>;
-	static var norFirst: Array<Float>;
-
-	public function new(blob: kha.Blob, startPos = 0, udim = false) {
-		pos = startPos;
-		var posIndices: Array<Int> = [];
-		var uvIndices: Array<Int> = [];
-		var norIndices: Array<Int> = [];
-		var readingFaces = false;
-		var readingObject = false;
-		var fullAttrib = false;
-		bytes = blob.bytes;
-
-		posTemp = [];
-		uvTemp = [];
-		norTemp = [];
-		va = new kha.arrays.Uint32Array(60);
-		ua = new kha.arrays.Uint32Array(60);
-		na = new kha.arrays.Uint32Array(60);
-		buf = new haxe.io.UInt8Array(64);
-		if (startPos == 0) vindOff = tindOff = nindOff = 0;
-
-		if (splitCode == "u".code && startPos > 0) {
-			posTemp = posFirst;
-			norTemp = norFirst;
-			uvTemp = uvFirst;
-		}
-
-		while (true) {
-			if (pos >= bytes.length) break;
-
-			var c0 = bytes.get(pos++);
-			if (readingObject && readingFaces && (c0 == "v".code || c0 == splitCode)) {
-				pos--;
-				hasNext = true;
-				break;
-			}
-
-			if (c0 == "v".code) {
-				var c1 = bytes.get(pos++);
-				if (c1 == " ".code) {
-					if (bytes.get(pos) == " ".code) pos++; // Some exporters put additional space directly after "v"
-					posTemp.push(readFloat());
-					pos++; // Space
-					posTemp.push(readFloat());
-					pos++; // Space
-					posTemp.push(readFloat());
-				}
-				else if (c1 == "t".code) {
-					pos++; // Space
-					uvTemp.push(readFloat());
-					pos++; // Space
-					uvTemp.push(readFloat());
-					if (norTemp.length > 0) fullAttrib = true;
-				}
-				else if (c1 == "n".code) {
-					pos++; // Space
-					norTemp.push(readFloat());
-					pos++; // Space
-					norTemp.push(readFloat());
-					pos++; // Space
-					norTemp.push(readFloat());
-					if (uvTemp.length > 0) fullAttrib = true;
-				}
-			}
-			else if (c0 == "f".code) {
-				pos++; // Space
-				if (bytes.get(pos) == " ".code) pos++; // Some exporters put additional space directly after "f"
-				readingFaces = true;
-				vi = ui = ni = 0;
-				fullAttrib ? readFaceFast() : readFace();
-
-				if (vi <= 4) { // Convex, fan triangulation
-					posIndices.push(va[0]);
-					posIndices.push(va[1]);
-					posIndices.push(va[2]);
-					for (i in 3...vi) {
-						posIndices.push(va[0]);
-						posIndices.push(va[i - 1]);
-						posIndices.push(va[i]);
-					}
-					if (uvTemp.length > 0) {
-						uvIndices.push(ua[0]);
-						uvIndices.push(ua[1]);
-						uvIndices.push(ua[2]);
-						for (i in 3...ui) {
-							uvIndices.push(ua[0]);
-							uvIndices.push(ua[i - 1]);
-							uvIndices.push(ua[i]);
-						}
-					}
-					if (norTemp.length > 0) {
-						norIndices.push(na[0]);
-						norIndices.push(na[1]);
-						norIndices.push(na[2]);
-						for (i in 3...ni) {
-							norIndices.push(na[0]);
-							norIndices.push(na[i - 1]);
-							norIndices.push(na[i]);
-						}
-					}
-				}
-				else { // Convex or concave, ear clipping
-					var vindOff = splitCode == "u".code ? 0 : vindOff;
-					var nindOff = splitCode == "u".code ? 0 : nindOff;
-					var nx = 0.0;
-					var ny = 0.0;
-					var nz = 0.0;
-					if (norTemp.length > 0) {
-						nx = norTemp[(na[0] - nindOff) * 3    ];
-						ny = norTemp[(na[0] - nindOff) * 3 + 1];
-						nz = norTemp[(na[0] - nindOff) * 3 + 2];
-					}
-					else {
-						var n = arm.util.MeshUtil.calcNormal(
-							new iron.math.Vec4(posTemp[(va[0] - vindOff) * 3], posTemp[(va[0] - vindOff) * 3 + 1], posTemp[(va[0] - vindOff) * 3 + 2]),
-							new iron.math.Vec4(posTemp[(va[1] - vindOff) * 3], posTemp[(va[1] - vindOff) * 3 + 1], posTemp[(va[1] - vindOff) * 3 + 2]),
-							new iron.math.Vec4(posTemp[(va[2] - vindOff) * 3], posTemp[(va[2] - vindOff) * 3 + 1], posTemp[(va[2] - vindOff) * 3 + 2])
-						);
-						nx = n.x;
-						ny = n.y;
-						nz = n.z;
-					}
-					var nxabs = Math.abs(nx);
-					var nyabs = Math.abs(ny);
-					var nzabs = Math.abs(nz);
-					var flip = nx + ny + nz > 0;
-					var axis = nxabs > nyabs && nxabs > nzabs ? 0 : nyabs > nxabs && nyabs > nzabs ? 1 : 2;
-					var axis0 = axis == 0 ? (flip ? 2 : 1) : axis == 1 ? (flip ? 0 : 2) : (flip ? 1 : 0);
-					var axis1 = axis == 0 ? (flip ? 1 : 2) : axis == 1 ? (flip ? 2 : 0) : (flip ? 0 : 1);
-
-					var loops = 0;
-					var i = -1;
-					while (vi > 3 && loops++ < vi) {
-						i = (i + 1) % vi;
-						var i1 = (i + 1) % vi;
-						var i2 = (i + 2) % vi;
-						var vi0 = (va[i ] - vindOff) * 3;
-						var vi1 = (va[i1] - vindOff) * 3;
-						var vi2 = (va[i2] - vindOff) * 3;
-						var v0x = posTemp[vi0 + axis0];
-						var v0y = posTemp[vi0 + axis1];
-						var v1x = posTemp[vi1 + axis0];
-						var v1y = posTemp[vi1 + axis1];
-						var v2x = posTemp[vi2 + axis0];
-						var v2y = posTemp[vi2 + axis1];
-
-						var e0x = v0x - v1x; // Not an interior vertex
-						var e0y = v0y - v1y;
-						var e1x = v2x - v1x;
-						var e1y = v2y - v1y;
-						var cross = e0x * e1y - e0y * e1x;
-						if (cross <= 0) continue;
-
-						var overlap = false; // Other vertex found inside this triangle
-						for (j in 0...vi - 3) {
-							var j0 = (va[(i + 3 + j) % vi] - vindOff) * 3;
-							var px = posTemp[j0 + axis0];
-							var py = posTemp[j0 + axis1];
-							if (arm.util.MeshUtil.pnpoly(v0x, v0y, v1x, v1y, v2x, v2y, px, py)) {
-								overlap = true;
-								break;
-							}
-						}
-						if (overlap) continue;
-
-						posIndices.push(va[i ]); // Found ear
-						posIndices.push(va[i1]);
-						posIndices.push(va[i2]);
-						if (uvTemp.length > 0) {
-							uvIndices.push(ua[i ]);
-							uvIndices.push(ua[i1]);
-							uvIndices.push(ua[i2]);
-						}
-						if (norTemp.length > 0) {
-							norIndices.push(na[i ]);
-							norIndices.push(na[i1]);
-							norIndices.push(na[i2]);
-						}
-
-						for (j in ((i + 1) % vi)...vi - 1) { // Consume vertex
-							va[j] = va[j + 1];
-							ua[j] = ua[j + 1];
-							na[j] = na[j + 1];
-						}
-						vi--;
-						i--;
-						loops = 0;
-					}
-					posIndices.push(va[0]); // Last one
-					posIndices.push(va[1]);
-					posIndices.push(va[2]);
-					if (uvTemp.length > 0) {
-						uvIndices.push(ua[0]);
-						uvIndices.push(ua[1]);
-						uvIndices.push(ua[2]);
-					}
-					if (norTemp.length > 0) {
-						norIndices.push(na[0]);
-						norIndices.push(na[1]);
-						norIndices.push(na[2]);
-					}
-				}
-			}
-			else if (c0 == splitCode) {
-				if (splitCode == "u".code) pos += 5; // "u"semtl
-				pos++; // Space
-				if (!udim) readingObject = true;
-				name = readString();
-			}
-			nextLine();
-		}
-
-		if (startPos > 0) {
-			if (splitCode != "u".code) {
-				for (i in 0...posIndices.length) posIndices[i] -= vindOff;
-				for (i in 0...uvIndices.length) uvIndices[i] -= tindOff;
-				for (i in 0...norIndices.length) norIndices[i] -= nindOff;
-			}
-		}
-		else {
-			if (splitCode == "u".code) {
-				posFirst = posTemp;
-				norFirst = norTemp;
-				uvFirst = uvTemp;
-			}
-		}
-		vindOff += Std.int(posTemp.length / 3); // Assumes separate vertex data per object
-		tindOff += Std.int(uvTemp.length / 2);
-		nindOff += Std.int(norTemp.length / 3);
-
-		// Pack positions to (-1, 1) range
-		scalePos = 0.0;
-		for (i in 0...posTemp.length) {
-			var f = Math.abs(posTemp[i]);
-			if (scalePos < f) scalePos = f;
-		}
-		var inv = 32767 * (1 / scalePos);
-
-		posa = new kha.arrays.Int16Array(posIndices.length * 4);
-		inda = new kha.arrays.Uint32Array(posIndices.length);
-		for (i in 0...posIndices.length) {
-			posa[i * 4    ] = Std.int( posTemp[posIndices[i] * 3    ] * inv);
-			posa[i * 4 + 1] = Std.int(-posTemp[posIndices[i] * 3 + 2] * inv);
-			posa[i * 4 + 2] = Std.int( posTemp[posIndices[i] * 3 + 1] * inv);
-			inda[i] = i;
-		}
-
-		if (norIndices.length > 0) {
-			nora = new kha.arrays.Int16Array(norIndices.length * 2);
-			for (i in 0...posIndices.length) {
-				nora[i * 2    ] = Std.int( norTemp[norIndices[i] * 3    ] * 32767);
-				nora[i * 2 + 1] = Std.int(-norTemp[norIndices[i] * 3 + 2] * 32767);
-				posa[i * 4 + 3] = Std.int( norTemp[norIndices[i] * 3 + 1] * 32767);
-			}
-		}
-		else {
-			// Calc normals
-			nora = new kha.arrays.Int16Array(inda.length * 2);
-			var va = new iron.math.Vec4();
-			var vb = new iron.math.Vec4();
-			var vc = new iron.math.Vec4();
-			var cb = new iron.math.Vec4();
-			var ab = new iron.math.Vec4();
-			for (i in 0...Std.int(inda.length / 3)) {
-				var i1 = inda[i * 3    ];
-				var i2 = inda[i * 3 + 1];
-				var i3 = inda[i * 3 + 2];
-				va.set(posa[i1 * 4], posa[i1 * 4 + 1], posa[i1 * 4 + 2]);
-				vb.set(posa[i2 * 4], posa[i2 * 4 + 1], posa[i2 * 4 + 2]);
-				vc.set(posa[i3 * 4], posa[i3 * 4 + 1], posa[i3 * 4 + 2]);
-				cb.subvecs(vc, vb);
-				ab.subvecs(va, vb);
-				cb.cross(ab);
-				cb.normalize();
-				nora[i1 * 2    ] = Std.int(cb.x * 32767);
-				nora[i1 * 2 + 1] = Std.int(cb.y * 32767);
-				posa[i1 * 4 + 3] = Std.int(cb.z * 32767);
-				nora[i2 * 2    ] = Std.int(cb.x * 32767);
-				nora[i2 * 2 + 1] = Std.int(cb.y * 32767);
-				posa[i2 * 4 + 3] = Std.int(cb.z * 32767);
-				nora[i3 * 2    ] = Std.int(cb.x * 32767);
-				nora[i3 * 2 + 1] = Std.int(cb.y * 32767);
-				posa[i3 * 4 + 3] = Std.int(cb.z * 32767);
-			}
-		}
-
-		if (uvIndices.length > 0) {
-			if (udim) {
-				// Find number of tiles
-				var tilesU = 1;
-				var tilesV = 1;
-				for (i in 0...Std.int(uvTemp.length / 2)) {
-					while (uvTemp[i * 2    ] > tilesU) tilesU++;
-					while (uvTemp[i * 2 + 1] > tilesV) tilesV++;
-				}
-
-				function getTile(i1: Int, i2: Int, i3: Int): Int {
-					var u1 = uvTemp[uvIndices[i1] * 2    ];
-					var v1 = uvTemp[uvIndices[i1] * 2 + 1];
-					var u2 = uvTemp[uvIndices[i2] * 2    ];
-					var v2 = uvTemp[uvIndices[i2] * 2 + 1];
-					var u3 = uvTemp[uvIndices[i3] * 2    ];
-					var v3 = uvTemp[uvIndices[i3] * 2 + 1];
-					var tileU = Std.int((u1 + u2 + u3) / 3);
-					var tileV = Std.int((v1 + v2 + v3) / 3);
-					return tileU + tileV * tilesU;
-				}
-
-				// Amount of indices pre tile
-				var num = new kha.arrays.Uint32Array(tilesU * tilesV);
-				for (i in 0...Std.int(inda.length / 3)) {
-					var tile = getTile(inda[i * 3], inda[i * 3 + 1], inda[i * 3 + 2]);
-					num[tile] += 3;
-				}
-
-				// Split indices per tile
-				udims = [];
-				udimsU = tilesU;
-				for (i in 0...tilesU * tilesV) {
-					udims.push(new kha.arrays.Uint32Array(num[i]));
-					num[i] = 0;
-				}
-
-				for (i in 0...Std.int(inda.length / 3)) {
-					var i1 = inda[i * 3    ];
-					var i2 = inda[i * 3 + 1];
-					var i3 = inda[i * 3 + 2];
-					var tile = getTile(i1, i2, i3);
-					udims[tile][num[tile]++] = i1;
-					udims[tile][num[tile]++] = i2;
-					udims[tile][num[tile]++] = i3;
-				}
-
-				// Normalize uvs to 0-1 range
-				var uvtiles = new kha.arrays.Int16Array(uvTemp.length);
-				for (i in 0...Std.int(inda.length / 3)) { // TODO: merge loops
-					var i1 = inda[i * 3    ];
-					var i2 = inda[i * 3 + 1];
-					var i3 = inda[i * 3 + 2];
-					var tile = getTile(i1, i2, i3);
-					var tileU = tile % tilesU;
-					var tileV = Std.int(tile / tilesU);
-					uvtiles[uvIndices[i1] * 2    ] = tileU;
-					uvtiles[uvIndices[i1] * 2 + 1] = tileV;
-					uvtiles[uvIndices[i2] * 2    ] = tileU;
-					uvtiles[uvIndices[i2] * 2 + 1] = tileV;
-					uvtiles[uvIndices[i3] * 2    ] = tileU;
-					uvtiles[uvIndices[i3] * 2 + 1] = tileV;
-				}
-				for (i in 0...uvtiles.length) uvTemp[i] -= uvtiles[i];
-			}
-
-			texa = new kha.arrays.Int16Array(uvIndices.length * 2);
-			for (i in 0...posIndices.length) {
-				var uvx = uvTemp[uvIndices[i] * 2];
-				if (uvx > 1.0) uvx = uvx - Std.int(uvx);
-				var uvy = uvTemp[uvIndices[i] * 2 + 1];
-				if (uvy > 1.0) uvy = uvy - Std.int(uvy);
-				texa[i * 2    ] = Std.int(       uvx  * 32767);
-				texa[i * 2 + 1] = Std.int((1.0 - uvy) * 32767);
-			}
-		}
-		bytes = null;
-		if (!hasNext) {
-			posFirst = norFirst = uvFirst = null;
-		}
-	}
-
-	function readFaceFast() {
-		while (true) {
-			va[vi++] = readInt() - 1;
-			pos++; // "/"
-			ua[ui++] = readInt() - 1;
-			pos++; // "/"
-			na[ni++] = readInt() - 1;
-			if (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code) break;
-			pos++; // " "
-			// Some exporters put space at the end of "f" line
-			if (vi >= 3 && (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code)) break;
-		}
-	}
-
-	function readFace() {
-		while (true) {
-			va[vi++] = readInt() - 1;
-			if (uvTemp.length > 0 || norTemp.length > 0) {
-				pos++; // "/"
-			}
-			if (uvTemp.length > 0) {
-				ua[ui++] = readInt() - 1;
-			}
-			if (norTemp.length > 0) {
-				pos++; // "/"
-				na[ni++] = readInt() - 1;
-			}
-			if (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code) break;
-			pos++; // " "
-			// Some exporters put space at the end of "f" line
-			if (vi >= 3 && (bytes.get(pos) == "\n".code || bytes.get(pos) == "\r".code)) break;
-		}
-	}
-
-	function readFloat(): Float {
-		var bi = 0;
-		while (true) { // Read into buffer
-			var c = bytes.get(pos);
-			if (c == " ".code || c == "\n".code || c == "\r".code) break;
-			if (c == "E".code || c == "e".code) {
-				pos++;
-				var first = buf[0] == "-".code ? -(buf[1] - 48) : buf[0] - 48;
-				var exp = readInt();
-				var dec = 1;
-				var loop = exp > 0 ? exp : -exp;
-				for (i in 0...loop) dec *= 10;
-				return exp > 0 ? first * dec : first / dec;
-			}
-			pos++;
-			buf[bi++] = c;
-		}
-		var res = 0.0; // Parse buffer into float
-		var dot = 1;
-		var dec = 1;
-		var off = buf[0] == "-".code ? 1 : 0;
-		var len = bi - 1;
-		for (i in 0...bi - off) {
-			var c = buf[len - i];
-			if (c == ".".code) {
-				dot = dec;
-				continue;
-			}
-			res += (c - 48) * dec;
-			dec *= 10;
-		}
-		off > 0 ? res /= -dot : res /= dot;
-		return res;
-	}
-
-	function readInt(): Int {
-		var bi = 0;
-		while (true) { // Read into buffer
-			var c = bytes.get(pos);
-			if (c == "/".code || c == "\n".code || c == "\r".code || c == " ".code) break;
-			pos++;
-			buf[bi++] = c;
-		}
-		var res = 0; // Parse buffer into int
-		var dec = 1;
-		var off = buf[0] == "-".code ? 1 : 0;
-		var len = bi - 1;
-		for (i in 0...bi - off) {
-			res += (buf[len - i] - 48) * dec;
-			dec *= 10;
-		}
-		if (off > 0) res *= -1;
-		return res;
-	}
-
-	function readString(): String {
-		var begin = pos;
-		while (true) {
-			var c = bytes.get(pos);
-			if (c == "\n".code || c == "\r".code || c == " ".code) break;
-			pos++;
-		}
-		return bytes.getString(begin, pos - begin);
-	}
-
-	function nextLine() {
-		while (true) {
-			var c = bytes.get(pos++);
-			if (c == "\n".code || pos >= bytes.length) break; // \n, \r\n
-		}
-	}
-}

+ 18 - 17
base/Sources/arm/io/ImportObj.hx

@@ -2,37 +2,38 @@ package arm.io;
 
 
 import kha.Blob;
 import kha.Blob;
 import iron.data.Data;
 import iron.data.Data;
-import arm.format.ObjParser;
 
 
 class ImportObj {
 class ImportObj {
 
 
 	public static function run(path: String, replaceExisting = true) {
 	public static function run(path: String, replaceExisting = true) {
 		var i = Context.raw.splitBy;
 		var i = Context.raw.splitBy;
 		var isUdim = i == SplitUdim;
 		var isUdim = i == SplitUdim;
-		ObjParser.splitCode =
+		var splitCode =
 			(i == SplitObject || isUdim) ? "o".code :
 			(i == SplitObject || isUdim) ? "o".code :
 			 i == SplitGroup 			 ? "g".code :
 			 i == SplitGroup 			 ? "g".code :
 			 				 			   "u".code; // usemtl
 			 				 			   "u".code; // usemtl
+
 		Data.getBlob(path, function(b: Blob) {
 		Data.getBlob(path, function(b: Blob) {
+
 			if (isUdim) {
 			if (isUdim) {
-				var obj = new ObjParser(b, 0, isUdim);
-				var name = obj.name;
-				for (i in 0...obj.udims.length) {
-					if (obj.udims[i].length == 0) continue;
-					var u = i % obj.udimsU;
-					var v = Std.int(i / obj.udimsU);
-					obj.name = name + "." + (1000 + v * 10 + u + 1);
-					obj.inda = obj.udims[i];
-					i == 0 ? (replaceExisting ? ImportMesh.makeMesh(obj, path) : ImportMesh.addMesh(obj)) : ImportMesh.addMesh(obj);
+				var part = Krom.io_obj_parse(b.bytes.getData(), splitCode, 0, isUdim);
+				var name = part.name;
+				for (i in 0...part.udims.length) {
+					if (part.udims[i].length == 0) continue;
+					var u = i % part.udims_u;
+					var v = Std.int(i / part.udims_u);
+					part.name = name + "." + (1000 + v * 10 + u + 1);
+					part.inda = part.udims[i];
+					i == 0 ? (replaceExisting ? ImportMesh.makeMesh(part, path) : ImportMesh.addMesh(part)) : ImportMesh.addMesh(part);
 				}
 				}
 			}
 			}
 			else {
 			else {
-				var parts: Array<ObjParser> = [];
-				var obj = new ObjParser(b);
-				parts.push(obj);
-				while (obj.hasNext) {
-					obj = new ObjParser(b, obj.pos);
-					parts.push(obj);
+				var parts: Array<Dynamic> = [];
+				var part = Krom.io_obj_parse(b.bytes.getData(), splitCode, 0, false);
+				parts.push(part);
+				while (part.has_next) {
+					part = Krom.io_obj_parse(b.bytes.getData(), splitCode, part.pos, false);
+					parts.push(part);
 				}
 				}
 				if (Context.raw.splitBy == SplitMaterial) {
 				if (Context.raw.splitBy == SplitMaterial) {
 					var posa0;
 					var posa0;