All pastes #633712 Raw Edit

Mine

public text v1 · immutable
#633712 ·published 2007-07-25 22:07 UTC
rendered paste body
module yage.resource.objloader;

import std.string;
import std.file;
import std.path;
import std.stdio;
import std.string;
import std.conv;

import yage.core.matrix;
import yage.core.misc;
import yage.core.vector;
import yage.resource.model;
import yage.resource.material;
import yage.resource.mesh;
import yage.resource.resource;
import yage.system.log;

union point{
	int[3] array;
	struct{
		int vertex;
		int texcoord;
		int normal;
	}
	Vec3i vec;
}

//alias char[] point
alias char[][] face;
//alias point[3] triangle;

struct MTL{}

struct group{
	//MTL mtl;
	point[char[]] points;//used to test if point already exists
	//char[] == lazy man's point reference
	face[] faces; //array of char[] is face, array of faces
	//face[] faces;
	
	void addPoint(char[] word){
		if(!(word in points)){
			point p;
			foreach(int index, inout part; split(word, "/")){
				if(part.length != 0)
					p.array[index] = std.conv.toInt(part);
			}
			
			points[word] = p;
		}
	}
	
	void addFace(char[][] words){
		for(int i = 1; i < words.length; i++){
			addPoint(words[i]);
		}
		faces ~= words[1..$];
	}
}

struct OBJ{
	group[] groups;
	
	Vec3f[] vertices, normals;
	Vec2f[] texcoords;
	
	void load(char[] source){
		char[] file = cast(char[])read(source);
		char[][] lines = splitlines(file);
		delete file;
		
		group g;
		groups ~= g;
		
		foreach(inout line; lines){
			line = strip(line);
			handleLine(line);
		}
	}
	
	//Do not want to make a template or making 2/3 an arg for only two functions
	Vec3f fromWords3(char[][] words){
		Vec3f vertex;
		for(int i; i < 3; i++)
			vertex[i] = std.conv.toFloat(words[i+1]);
		return vertex;
	}
	
	Vec2f fromWords2(char[][] words){
		Vec2f vertex;
		for(int i; i < 2; i++)
			vertex[i] = std.conv.toFloat(words[i+1]);
		return vertex;
	}
	
	void handleLine(char[] line){
		char[][] words = split(line, " ");
		switch(words[0]){
			//Vertex data
			case "v":
				//does not support weight
				vertices ~=  fromWords3(words);
				break;
			case "vt":
				//does not support weight
				texcoords ~=  fromWords2(words);
				break;
			case "vn":
				normals ~=  fromWords3(words);
				break;
			case "vp":
				break;
			case "cstype":
				break;
			case "deg":
				break;
			case "bmat":
				break;
			case "step":
				break;
			//Elements
			case "p":
				break;
			case "l":
				break;
			case "f":
				groups[$-1].addFace(words);
				break;
			case "curv":
				break;
			case "curv2":
				break;
			case "surf":
				break;
			//Free-form curve/surface body statements
			case "parm":
				break;
			case "trim":
				break;
			case "hole":
				break;
			case "scrv":
				break;
			case "sp":
				break;
			case "end":
				break;
			//Connectivity between free-form surfaces
			case "con":
				break;
			//Grouping
			case "g":
				group g;
				groups ~= g;
				break;
			case "s":
				break;
			case "mg":
				break;
			case "o":
				break;
			//Display/render attributes
			case "bevel":
				break;
			case "c_interp":
				break;
			case "d_interp":
				break;
			case "lod":
				break;
			case "usemtl":
				//mesh[$-1].material = 
				break;
			case "mtllib":
				//new Material(words[1]);
				break;
			case "shadow_obj":
				break;
			case "trace_obj":
				break;
			case "ctech":
				break;	
			case "stech":
				break;
			default:
				break;
		}
	}
}

/**
 * Create Models from files and other sources.
 * This is separated and used as a mixin to reduce the length of model.d.*/
template ObjLoader(){
	/**
	 * Load a model from a Milkshape3D model file.
	 * All materials, etc. referenced by this model are loaded through the Resource
	 * manager to avoid duplicates.  Meshes without a material are assigned a default material.
	 * Uploading vertex data to video memory must be done manually by calling Upload(). */
	
	protected void loadObj(char[] filename){
		Vec3f[] vertices, normals;
		Vec2f[] texcoords;
		
		source = Resource.resolvePath(filename);
		char[] path = source[0 .. rfind(source, "/") + 1]; // path stripped of filename
		
		OBJ obj;
		obj.load(source);
		
		//Vertices
		//vertices.length  = ms3d.vertices.length;
		//texcoords.length = ms3d.vertices.length;
		//normals.length   = ms3d.vertices.length;
		
		//for (int v; v<ms3d.vertices.length; v++)
		//{	vertices[v].x = ms3d.vertices[v].vertex[0];
		//	vertices[v].y = ms3d.vertices[v].vertex[1];
		//	vertices[v].z = ms3d.vertices[v].vertex[2];
		//}
		foreach(inout g; obj.groups){ //makes new vertices for different normals or tex
			foreach(inout p; g.points){
				vertices ~= obj.vertices[p.vertex - 1];
				p.vertex = vertices.length - 1;
				
				if(p.normal == 0)
					normals.length = normals.length + 1;
				else{
					normals ~= obj.normals[p.normal - 1];
					p.normal = normals.length - 1;
				}
				
				if(p.texcoord == 0)
					texcoords.length = texcoords.length + 1;
				else{
					texcoords ~= obj.texcoords[p.texcoord -1];
					p.texcoord = texcoords.length - 1;
				}
			}
		}
		
		writefln("vertices length is ", vertices.length);
		writefln("normals length is ", normals.length);
		writefln("texcoords length is ", texcoords.length);
		
		/*
		// Meshes
		meshes.length = obj.groups.length;
		for (int m; m<meshes.length; m++)
		*/
		foreach(g; obj.groups[1..$]){
			meshes ~= new Mesh();
			int m = meshes.length - 1;
			Vec3i[] triangles = meshes[m].getTriangles();
			/*
			//triangles.length = ms3d.groups[m].numtriangles;

// 			// Material
			if (ms3d.groups[m].materialIndex != -1)
			{	// The filename exists in the system?

				char[] name = ms3d.materials[ms3d.groups[m].materialIndex].name;
				if (exists(path~name))
					meshes[m].setMaterial(path~name);
				else // create new material
				{	Material matl = new Material();
					matl.addLayer(new Layer());

					int midx = ms3d.groups[m].materialIndex;
					memcpy(&matl.getLayers()[0].ambient, ms3d.materials[midx].ambient.ptr, 16);
					memcpy(&matl.getLayers()[0].diffuse, ms3d.materials[midx].diffuse.ptr, 16);
					memcpy(&matl.getLayers()[0].specular, ms3d.materials[midx].specular.ptr, 16);
					memcpy(&matl.getLayers()[0].emissive, ms3d.materials[midx].emissive.ptr, 16);
					matl.getLayers()[0].specularity = ms3d.materials[midx].shininess;
					meshes[m].setMaterial(matl);

					// Load textures
					// Ms3d stores a texture map and an alpha map for every material
					char[] texfile = .toString(ms3d.materials[midx].texture.ptr);
					if (texfile.length)
					{	if (icmp(texfile[0..2], ".\\")==0) // linux fails with .\ in a path.
							texfile = texfile[2..length];
						meshes[m].getMaterial().getLayers()[0].addTexture(Resource.texture(path ~ texfile));
					}
					if (ms3d.materials[midx].alphamap[0])
						meshes[m].getMaterial().getLayers()[0].addTexture(Resource.texture(path ~ ms3d.materials[midx].alphamap));
				}
			}
			*/
			// Triangles
			foreach(f; g.faces){
				//f is char[][]
				//change to use yage.core.array
				//this will fan polygons
				while(f.length != 2){
					writefln(vertices[g.points[f[0]].vertex]);
					writefln(vertices[g.points[f[1]].vertex]);
					writefln(vertices[g.points[f[2]].vertex]);
					writefln();
					triangles ~= Vec3i(g.points[f[0]].vertex, g.points[f[1]].vertex, g.points[f[2]].vertex);
				
					for (size_t i = 1; i<f.length - 1; i++)
						f[i] = f[i+1];
					f.length = f.length - 1;
				}
			}
			
			writefln("triangles length is ", triangles.length);
			/*
			for (int t; t<triangles.length; t++)
			{
				//printf( "%d\n", ms3d.groups[m].triangleIndices[t]);
				triangles[t].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexIndices[0];
				triangles[t].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexIndices[1];
				triangles[t].z = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexIndices[2];

				// Tex coords
				texcoords[triangles[t].x].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].s[0];
				texcoords[triangles[t].y].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].s[1];
				texcoords[triangles[t].z].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].s[2];
				texcoords[triangles[t].x].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].t[0];
				texcoords[triangles[t].y].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].t[1];
				texcoords[triangles[t].z].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].t[2];

				// Normals
				normals[triangles[t].x].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[0];
				normals[triangles[t].x].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[1];
				normals[triangles[t].x].z = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[2];
				normals[triangles[t].y].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[3];
				normals[triangles[t].y].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[4];
				normals[triangles[t].y].z = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[5];
				normals[triangles[t].z].x = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[6];
				normals[triangles[t].z].y = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[7];
				normals[triangles[t].z].z = ms3d.triangles[ms3d.groups[m].triangleIndices[t]].vertexNormals[8];
			}


			// In the MS3D format, texture coordinate and normal data is stored per triangle, while the vertex
			// position is stored per vertex.  This allows two triangles that reference the same vertex to have
			// different texture and normal coordinates, but is incompatible with the OpenGL vertex format.
			// This loop finds such instances, and creates new vertices to correct the problem.
			for (int t; t<triangles.length; t++)
			{
				// Index of the triangle we're dealing with.
				int tindex = ms3d.groups[m].triangleIndices[t];

				// Triangle index a
				if ((texcoords[triangles[t].x].x != ms3d.triangles[tindex].s[0]) ||
					(texcoords[triangles[t].x].y != ms3d.triangles[tindex].t[0]))
				{
					// Duplicate vertex from original and copy new texutre and normal coordinates into it.
					vertices.length = texcoords.length = normals.length = vertices.length+1;
					memcpy(&vertices[length-1], &vertices[ms3d.triangles[tindex].vertexIndices[0]], 12);
					memcpy(&normals[length-1], &ms3d.triangles[tindex].vertexNormals[0], 12);
					texcoords[length-1].x = ms3d.triangles[tindex].s[0];
					texcoords[length-1].y = ms3d.triangles[tindex].t[0];
					// Assign this new vertex to the triangle
					triangles[t].x = vertices.length-1;
				}

				// Triangle index b
				if ((texcoords[triangles[t].y].x != ms3d.triangles[tindex].s[1]) ||
					(texcoords[triangles[t].y].y != ms3d.triangles[tindex].t[1]))
				{
					// Duplicate vertex from original and copy new texutre and normal coordinates into it.
					vertices.length = texcoords.length = normals.length = vertices.length+1;
					memcpy(&vertices[length-1], &vertices[ms3d.triangles[tindex].vertexIndices[1]], 12);
					memcpy(&normals[length-1], &ms3d.triangles[tindex].vertexNormals[3], 12);
					texcoords[length-1].x = ms3d.triangles[tindex].s[1];
					texcoords[length-1].y = ms3d.triangles[tindex].t[1];
					// Assign this new vertex to the triangle
					triangles[t].y = vertices.length-1;
				}

				// Triangle index b
				if ((texcoords[triangles[t].z].x != ms3d.triangles[tindex].s[2]) ||
					(texcoords[triangles[t].z].y != ms3d.triangles[tindex].t[2]))
				{
					// Duplicate vertex from original and copy new texutre and normal coordinates into it.
					vertices.length = texcoords.length = normals.length = vertices.length+1;
					memcpy(&vertices[length-1], &vertices[ms3d.triangles[tindex].vertexIndices[2]], 12);
					memcpy(&normals[length-1], &ms3d.triangles[tindex].vertexNormals[6], 12);
					texcoords[length-1].x = ms3d.triangles[tindex].s[2];
					texcoords[length-1].y = ms3d.triangles[tindex].t[2];
					// Assign this new vertex to the triangle
					triangles[t].z = vertices.length-1;
				}
			}

			// Find meshes with material of -1 (no material) and assign them the default material
			if (ms3d.groups[m].materialIndex==-1)
			*/
			//{	meshes[m].setMaterial(new Material());
			//	meshes[m].getMaterial().addLayer(new Layer());	// should be init'd to defaults
			//}
			meshes[m].setTriangles(triangles);
		}
		
		/*
		delete ms3d.vertices;
		delete ms3d.triangles;
		delete ms3d.groups;
		delete ms3d.materials;
		*/
		setAttribute("gl_Vertex", vertices);
		setAttribute("gl_TexCoord", texcoords);
		setAttribute("gl_Normal", normals);
	}
}