// Copyright (C) 2007 Inland Studios, LLC. // procImport - import doom 3 scene file in maya // Author: Benjamin Quintero // // Description: // Imports all "_area" models and creates a group node for all surfaces // of that area. // // WARNING: // Backup your work; this is a very early BETA utility and is intended // purely as a learning tool. Please do not misuse this source or it // will be removed from the site. // global string $ptmVersion = "0.1"; global string $doomBasePath; global string $doomMapPath; global string $doomParseLog[]; global int $doomParseLogIndex = 0; $doomBasePath = "D:/Program Files/idSoftware/DOOM 3/base/"; $doomMapPath = $doomBasePath + "maps/game/"; proc add_log( string $token ) { global string $doomParseLog[]; global int $doomParseLogIndex; $doomParseLog[$doomParseLogIndex] = $token; $doomParseLogIndex = ($doomParseLogIndex + 1) % 20; } proc show_log() { global string $doomParseLog[]; global int $doomParseLogIndex; print("[procimport log]\n"); for($i = 0; $i < size($doomParseLog); $i++) { int $idx = (($doomParseLogIndex + size($doomParseLog)) - ($i+1)) % size($doomParseLog); print( "|-> " + $doomParseLog[$idx] + "\n" ); } print("[end log]\n"); } proc string remove_quotes( string $token ) { return substituteAllString($token, "\"", ""); } // kind of hack for quake4 format proc ungettoken( string $token ) { global string $doomUngetToken; $doomUngetToken = $token; } proc string gettoken( int $fileId ) { global string $doomUngetToken; string $tmp; string $result; if( $doomUngetToken != "" ) { $result = $doomUngetToken; $doomUngetToken = ""; return $result; } $result = `fgetword $fileId`; // skip C-style comments from the file if( $result == "/*" ) { while( $result != "*/" ) { $result = `fgetword $fileId`; } // recursively get next token in case we have multiple comment blocks in a row return gettoken( $fileId ); } if( `match "\"" $result` != "" ) { // group tokens that are closed in quotes $tmp = $result; $result = remove_quotes( $result ); // we may have both quotes in the same token if( (size($tmp) - size($result)) != 2 ) { //print( "$result: " + $result + "\n"); // find the end of the string $tmp = `fgetword $fileId`; while( `match "\"" $tmp` != "\"" ) { $result = $result + " " + $tmp; $tmp = `fgetword $fileId`; } $result = $result + " " + $tmp; $result = remove_quotes( $result ); } } // debug token parsing add_log( $result ); return $result; } proc expect_token( int $fileId, string $token ) { string $tmp = `gettoken( $fileId )`; if ($tmp != $token) { show_log(); error ("Syntax Error: parsed '" + $tmp + "' while expecting '" + $token + "'\n"); } } proc int next_token( int $fileId, string $token ) { string $tmp; // get the next token and put it back $tmp = `gettoken( $fileId )`; ungettoken( $tmp ); // compare for a match return ($tmp == $token); } proc vector get_vec2_token( int $fileId ) { float $x = `gettoken( $fileId )`; float $y = `gettoken( $fileId )`; return <<$x, $y, 0>>; } proc vector get_vector_token( int $fileId ) { float $x = `gettoken( $fileId )`; float $y = `gettoken( $fileId )`; float $z = `gettoken( $fileId )`; return <<$x, $y, $z>>; } proc string importProcMesh( string $version, string $modelName, int $meshId, int $fileId ) { vector $positions[] ; vector $normals[] ; vector $uv[] ; int $indexes[] ; string $token; string $shaderName; int $numVerts; int $numIndexes; expect_token( $fileId, "{" ); $shaderName = `gettoken( $fileId )`; $numVerts = `gettoken( $fileId )`; $numIndexes = `gettoken( $fileId )`; //print( " |->" + $shaderName + "\n" ); //print( " |->" + $numVerts + "\n" ); //print( " |->" + $numIndexes + "\n" ); // vertex format "( x y z u v nx ny nz )" for($i = 0; $i < $numVerts; $i++) { expect_token( $fileId, "(" ); $positions[$i] = `get_vector_token( $fileId )`; $uv[$i] = `get_vec2_token( $fileId )`; $normals[$i] = `get_vector_token( $fileId )`; // parse vertex colors... if( $version == "4" && !next_token( $fileId, ")" ) ) // quake4 { // RGBA gettoken( $fileId ); gettoken( $fileId ); gettoken( $fileId ); gettoken( $fileId ); } expect_token( $fileId, ")" ); } // indexes are in multiples of 3 since they define triangles for($i = 0; $i < $numIndexes; $i++) { string $tmp = `gettoken( $fileId )`; if( $tmp == "{" || $tmp == "}" ) { error ("procImport ===> importProcMesh() expected an index not '" + $tmp + "'!"); } $indexes[$i] = $tmp; } expect_token( $fileId, "}" ); if( $numVerts == 0 || $numIndexes == 0 ) { error "procImport ===> importProcMesh() Failed to locate valid mesh data!"; return ""; } // ------------------------------------------------------ // output mesh to an .obj file // ------------------------------------------------------ string $meshName = $modelName + "_surface" + string($meshId); global string $doomBasePath; string $objFile = "c:/procImport.obj" ; $objId = `fopen $objFile "w"` ; fprint $objId ( "g " + $meshName ) ; for ($i=0;$i<$numVerts;$i++) { vector $vertex = $positions[$i] ; // orient to face from z-up to y-up (Maya defaults) $vertex = rot($vertex, <<1, 0, 0>>, -90 * 3.141593 / 180); fprint $objId ( "\nv " + $vertex.x + " " + $vertex.y + " " + $vertex.z ) ; } for ($i=0;$i<$numVerts;$i++) { vector $coord = $uv[$i] ; fprint $objId ( "\nvt " + $coord.x + " " + $coord.y ) ; } for ($i=0;$i<$numIndexes;$i+=3) { vector $face = <<$indexes[$i+2], $indexes[$i+1], $indexes[$i+0]>>; fprint $objId ( "\nf " + ($face.x+1) + "/" + ($face.x+1) + " " + ($face.y+1) + "/" + ($face.y+1) + " " + ($face.z+1) + "/" + ($face.z+1) ) ; } fprint $objId ("\n"); // required for maya OBJ importer fclose $objId ; // ------------------------------------------------------ // 3- import the .obj file // ------------------------------------------------------ file -import -type "OBJ" -rpr $meshName -options "mo=1" $objFile ; parent $meshName $modelName; return $meshName; } proc skip_brackets( int $fileId ) { string $token; int $depth = 0; $token = `gettoken( $fileId )`; if ( $token == "{") $depth = 1; while( $token != "" && $depth > 0 ) { //print( "|-> TOKEN: '" + $token + "'\n" ); $token = `gettoken( $fileId )`; if( $token == "{" ) $depth = $depth + 1; else if( $token == "}" ) $depth = $depth - 1; } //print( "|-> END_TOKEN: '" + $token + "'\n" ); } proc importProcFile( string $procFile ) { string $version; string $modelName; string $shaderName; string $token; int $numSurfaces; int $skyId; // Quake4 stuff ?? if ( !`filetest -r $procFile` ) { error "procImport ===> Couldn't find the proc file!"; } // --------------------------- // 2- store the variables // --------------------------- $fileId = `fopen $procFile "r"`; $token = `gettoken( $fileId )`; $version = "3"; if( $token != "mapProcFile003" ) { $version = `gettoken( $fileId )`; if( $token == "PROC" && $version == "4" ) { $token = `gettoken( $fileId )`; // skip CRC.. } else { error ("procImport ===> Unknown file format! '" + $token + "' '" + $version + "'"); } } while ( $token != "" ) { $token = `gettoken( $fileId )`; // get next token if( $token == "model" ) { expect_token( $fileId, "{" ); $modelName = `gettoken( $fileId )`; $numSurfaces = `gettoken( $fileId )`; print( "|-> " + $modelName + "\n" ); //print( " |->" + $numSurfaces + "\n" ); if( substring($modelName, 1, 5) == "_area" ) { if( $version == "4" ) { // skip quake4 sky info $skyId = `gettoken( $fileId )`; } if( $numSurfaces > 0 ) { group -empty -n $modelName; xform -os -piv 0 0 0; } // load each mesh for this model for($i = 0; $i < $numSurfaces; $i++) { importProcMesh( $version, $modelName, $i, $fileId ); } } else { // skip models that require entity information (like translation and rotation) for($i = 0; $i < $numSurfaces; $i++) { skip_brackets( $fileId ); } } expect_token( $fileId, "}" ); } else if( $token != "" ) { // skip non-model data types in the file skip_brackets( $fileId ); } } fclose $fileId; // ------------------------------------------------------- // reorient the skeleton in correct space (Z axis up) // ------------------------------------------------------- } global proc procImport() { global string $doomMapPath; string $procFile; string $dirMask; $dirMask = $doomMapPath + "*.proc"; $procFile = `fileDialog -directoryMask $dirMask`; importProcFile( $procFile ); } // open the window when this file is parsed procImport();