Game Development Community

dev|Pro Game Development Curriculum

Rudimentary dts to obj converter

by Thomas -elfprince13- Dickerson · 10/29/2009 (9:19 pm) · 26 comments

This resource adds a console function which statically (as in, no bones or animations) dumps the first mesh of a TSShapeInstance loaded from .dts to an .obj file, should be fairly easy to make it iterate (the function sets up i as an iterator variable to be used in an outer for loop, and then just doesn't have the for loop) and convert the rest of the meshes as well, but this filled my needs so I didn't bother. It should also note that it doesn't bother exporting materials, but it does keep your UV coordinates. This was originally going to conver to Milkshape 3D ASCII format, but there are some incompatibilities in how the normal vectors are handled between the two formats (DTS interpolates to a single normal vector per vertex), so I went with .obj instead.

ConsoleFunction(dumpDTStoObj, void, 3, 3, "(string objfile, string dts)")
{
	Resource<TSShape> shape;
	shape = ResourceManager->load(argv[2]);
	const char * str;
	if(shape.isNull())
		return;
	
	TSShapeInstance *shapeinst = new TSShapeInstance(shape, true);
	if(!shapeinst)
		return;
	
	FileStream stream;
	stream.open(argv[1], FileStream::Write);

	TSShape* mShape = shapeinst->getShape();
	
	Con::printf("Dumping %s to %s", argv[2], argv[1]);
	dumpLine("#obj file rn");
	U32 i;
	/*S32 frameCount = 0;
	for(i = 0; i < mShape->sequences.size(); i++){
		frameCount += mShape->sequences[i].numKeyframes;
	}
	//dumpLine(avar("Frames: %irn", frameCount));
	dumpLine("Frames: 1rn");	//only STATIC meshes for now, kthxbai
	dumpLine("Frame: 1rnrn");
	
	dumpLine(avar("Meshes: %irn", mShape->meshes.size()));*/
	
	// mesh: name, flags, material index
	i = 0; 	//make this loopy eventually
	TSMesh* tsm = mShape->meshes[i];
	
	// number of vertices
	dumpLine(avar("#%irnrn", tsm->verts.size()));
	
	ToolVector<Point2F> uvs;
	tsm->getUVs(TSMesh::tDiffuse, uvs);
	U32 j; // inner loopiness
	for(j = 0; j<tsm->verts.size(); j++){
		Point3F xyz = tsm->verts[j];
		// vertex: flags, x, y, z, u, v, bone index
		dumpLine(avar("v %f %f %frn", xyz.x, xyz.y, xyz.z));
	}
	dumpLine("rn");

	for(j = 0; j<tsm->verts.size(); j++){
		Point2F uv = uvs[j];
		dumpLine(avar("vt %f %frn", uv.x, uv.y));
	}
	dumpLine("rn");
	
	
	// number of normals
	U32 normcount = tsm->getFlags(TSMesh::UseEncodedNormals) ? tsm->encodedNorms.size() : tsm->norms.size();
	dumpLine(avar("#%irnrn", normcount));
	
	const Point3F * norms = tsm->getNormals(0);
	for(j = 0; j<normcount; j++){
		Point3F xyz = norms[j];
		// normal: x, y, z
		dumpLine(avar("vn %f %f %frn", xyz.x, xyz.y, xyz.z));
	}
	
	dumpLine("rn");

	// number of triangles
	U32 tris = 0;
	for(j = 0; j<tsm->primitives.size(); j++)
		tris += tsm->primitives[j].numElements;
		

	dumpLine(avar("# %irnrn",tris));
	
	dumpLine(avar("g Mesh%irnrn",i));
	for(j = 0; j<tsm->primitives.size(); j++){
		TSDrawPrimitive draw = tsm->primitives[j];
		// triangle: flags, vertex index1, vertex index2, vertex index3, normal index1, normal index 2, normal index 3, smoothing group
		if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)
		{
			for (S32 k=0; k<draw.numElements; )
			{
				U32 idx0 = tsm->indices[draw.start + k + 0];
				U32 idx1 =tsm->indices[draw.start + k + 1];
				U32 idx2 = tsm->indices[draw.start + k + 2];
				dumpLine(avar("f %i/%i/%i %i/%i/%i %i/%i/%irn", (idx0+1), (idx0+1), (idx0+1), (idx1+1), (idx1+1), (idx1+1), (idx2+1), (idx2+1), (idx2+1)));
				
				k += 3;
			}
		} else if((draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip){
			U32 idx0 = tsm->indices[draw.start + 0];
			U32 idx1;
			U32 idx2 = tsm->indices[draw.start + 1];
			U32 * nextIdx = &idx1;
			for (S32 k=2; k<draw.numElements; k++)
			{
				*nextIdx = idx2;
				nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
				idx2 = tsm->indices[draw.start + k];
				if (idx0 == idx1 || idx0 == idx2 || idx1 == idx2)
					Con::printf("Warning, vertex redundancy: %i, %i, %i", idx0, idx1, idx2);
					//continue;
				dumpLine(avar("f %i/%i/%i %i/%i/%i %i/%i/%irn", (idx0+1), (idx0+1), (idx0+1), (idx1+1), (idx1+1), (idx1+1), (idx2+1), (idx2+1), (idx2+1)));
			}
			
		} else{
			dumpLine("# oops--don't really know how to handle thisrn");
		}
	}
	
	dumpLine("rn");
	
	stream.close();
	Con::printf("...dump complete");
}

About the author

C.S. PhD student at Brown University. Project lead for FreeBuild. Administrator, Cemetech tech community. Webmaster for the Village2Village Projects and the Vermont Sustainable Heating Initiative.

Page«First 1 2 Next»
#21
11/04/2009 (10:17 am)
ah, StandardMeshType, and company should probably be prefixed with a TSMesh::


and yes.
#22
11/04/2009 (10:45 pm)
Ok, added the new code and now it crashes (CSK Jeep model) with only "#obj file" inside of the jeep.obj...

Hers a debug screen dump:
i566.photobucket.com/albums/ss101/CS_MP/MPGE/Bugs/DTSDumpDebug2.jpg

btw, is this the way this line should look?
Con::printf("Mesh Type:\r\nTSMesh::StMT %i\r\nTSMesh::SkMT %i\r\nTSMesh::DMT %i\r\nTSMesh::SoMT %i\r\nTSMesh::NMT %i\r\nTSMesh::Flags\r\nTSMesh::Billboard %i\r\nTSMesh::HasDetailTexture %i\r\nTSMesh::BillboardZAxis %i\r\nTSMesh::EncodedNorms %i\r\nTSMesh::HasLightTexture %i\r\n",(mt & TSMesh::StandardMeshType),(mt & TSMesh::SkinMeshType),(mt & TSMesh::DecalMeshType),(mt & TSMesh::SortedMeshType),(mt & TSMesh::NullMeshType), (flags & TSMesh::Billboard), (flags & TSMesh::HasDetailTexture), (flags & TSMesh::BillboardZAxis), (flags & TSMesh::UseEncodedNormals), (flags & TSMesh::HasLightTexture));
#23
11/04/2009 (10:57 pm)
Huh, that's really bizarre, and suggests to me that somehow the jeep hasn't been initialized properly. I'll dig around some more. And that's more or less correct. The TSMesh:: inside the quoted string is unecessary since that's just text to explain the values I'm printing. And I forced it to return after the line (if it had actually reached it, which clearly it hasn't if it's crashing at getType()) so that nothing later in the script could cause a crash, and we'd only get the relevant debugging information. Does the CSK Jeep load okay as a TSStatic in game?

I'm honestly not familiar with enough with TSShapeInstance, TSShape, and TSMesh to know what's going wrong here, but if you can at least get me the console output from the models you had converting without crashes that would be great. I'll dig around and see if I can find some code examples that might hint at what I'm doing wrong.
#24
11/10/2009 (4:50 pm)
CSMP, did you ever run the other models through to get the log information?
#25
11/15/2009 (11:35 am)
Ah yes, I've been offline for awhile so I'll try and test those out for you tomorrow and post up the results.
Page«First 1 2 Next»