📄 qmapexp.cpp
字号:
if ( obj != (Object*)tri) // delete work object if needed
tri->DeleteThis() ;
return FALSE ;
} ;
int qmap_save(const TCHAR *filename, ExpInterface *ei, Interface *gi, QMapExport *exp)
{
// Put up the options dialog to find out how they want the file written!
int result = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EXPORTOPTIONS),
gi->GetMAXHWnd(), ExportOptionsDlgProc, (LPARAM)exp);
if(result <= 0)
return 0;
// Make sure there are nodes we're interested in!
// Ask the scene to enumerate all its nodes so we can determine if there are any we can use
MySceneEnumProc myScene(ei->theScene, gi->GetTime(), gi);
// Any useful nodes?
if(!myScene.Count())
{
Alert(IDS_TH_NODATATOEXPORT);
return 1;
} ;
// init flags
BOOL playerStartFound = FALSE ; // remember if theres a player start entity
errorBrushes = 0 ; // remember how many brushes have errors
// Output the file as text
WorkFile theFile(filename,_T("w"));
FILE *stream = theFile.Stream();
if(!stream)
{
Alert(IDS_TH_CANTCREATE);
return -1; // Didn't open!
}
// Build a bounding box for the objects we're exporting
Box3 bbox = myScene.Bound();
// Let's get busy!
int ox;
TSTR layername;
// Write header stuff
if (fprintf(stream,"// Quake Map file exported from 3DS MAX by QMAPEXP v1.04\n")<0)
goto wrterr ; // well if Tom Hudson can use labels....
// write the worldspawn entity that holds all the non-linked brushes
if (fprintf(stream,"{\n"
"\"classname\" \"worldspawn\"\n"
"\"wad\" \"%s\"\n"
"\"message\" \"%s\"\n"
"\"worldtype\" \"%d\"\n"
"\"sounds\" \"1\"\n",
exp->WADName,
exp->MapName,
exp->WorldType
)<0)
goto wrterr ;
// first loop looking for all suitable Quake brushes
for (ox = 0 ; ox<myScene.Count(); ++ox )
{
MySceneEntry* sEntry ;
sEntry = myScene[ox] ;
int objType ;
objType = myScene[ox]->type ;
if (objType == OBTYPE_MESH ) // found a mesh
{
// check Hierarchy
BOOL globalMesh = TRUE ; // assume its not attched to an entity
INode* parent = sEntry->node->GetParentNode() ; // find parent
if (!parent->IsRootNode()) // parent is a real object
{
Object* parentObj = parent->GetObjectRef() ; // determine parent type
if ( (parentObj->SuperClassID() == HELPER_CLASS_ID ) &&
(parentObj->ClassID() == QENTHELP_CLASS_ID)) // brush is linked to entity
globalMesh = FALSE ;
} ;
if (globalMesh) // if not attached to entity
{
if (WriteMesh(sEntry, gi, stream))
goto wrterr ;
} ;
} ;
} ; // for
if (fprintf(stream,"}\n")<0)
goto wrterr ;
// next loop looking for all suitable Quake entities
for (ox = 0 ; ox<myScene.Count(); ++ox )
{
MySceneEntry* sEntry ;
sEntry = myScene[ox] ;
if ( sEntry->type == OBTYPE_OMNILIGHT ) // if MAX omni light
{
// derive the light parameters
INode* node = sEntry->node;
Object* obj = sEntry->obj;
LightObject* lt= (LightObject *)obj;
GenLight* gl = (GenLight *)obj;
LightState ls;
Interval valid;
lt->EvalLightState(myScene.time, valid, &ls);
Matrix3 mat = node->GetNodeTM(myScene.time);
Point3 pos = mat.GetRow(3);
// issue quake light
if (fprintf(stream, "{\n"
"// %s\n"
"\"classname\" \"light\"\n"
"\"origin\" \"%ld %ld %ld\"\n"
"\"light\" \"%d\"\n"
"}\n"
,node->GetName()
,(int)pos.x,(int)pos.y,(int)pos.z
,(int)ls.attenEnd // MAX attenuation end controls Quake intensity
)<0)
goto wrterr ;
}
else
{
if ( sEntry->type == OBTYPE_QENTITY ) // quake entity helper object
{
INode* node = sEntry->node ;
QEntHelpObject* ent = (QEntHelpObject*)sEntry->obj ;
Matrix3 mat = node->GetNodeTM(myScene.time);
Point3 pos = mat.GetRow(3);
// check if its part of a tree
int numChild = node->NumberOfChildren() ;
if ( numChild == 0 ) // if unatttached, standard entity
{
// issue standard quake entity
if (fprintf(stream, "{\n"
"// %s\n"
"\"classname\" \"%s\"\n"
"\"origin\" \"%ld %ld %ld\"\n"
,node->GetName()
,ent->QClassName
,(int)pos.x,(int)pos.y,(int)pos.z
)<0)
goto wrterr ;
// issue map params
DecodeMapParams(ent->Data.MapParams,stream) ;
// check if its the player start entity
if ( strcmp(ent->QClassName,"info_player_start") == 0)
playerStartFound = TRUE ;
if (fprintf(stream,"}\n") <0)
goto wrterr ;
}
else // its an entity linked to a brush
{
if ( strcmp(ent->QClassName,"func_door") == 0 ) // its a door
{
// write entity
if (fprintf(stream, "{\n"
"// %s\n"
"\"classname\" \"%s\"\n"
"\"angle\" \"%ld\"\n"
"\"speed\" \"%ld\"\n"
"\"sounds\" \"%ld\"\n"
"\"wait\" \"%ld\"\n"
"\"lip\" \"%ld\"\n"
"\"dmg\" \"%ld\"\n"
,node->GetName()
,ent->QClassName
,ent->Data.Angle
,ent->Data.Speed
,ent->Data.Sounds
,ent->Data.Wait
,ent->Data.Lip
,ent->Data.Dmg
)<0)
goto wrterr ;
if (strlen(ent->Data.TargetName) != 0)
{
if (fprintf(stream, "\"targetname\" \"%s\"\n"
,ent->Data.TargetName
)<0)
goto wrterr ;
} ;
if (strlen(ent->Data.Message) != 0)
{
if (fprintf(stream, "\"message\" \"%s\"\n"
,ent->Data.Message
)<0)
goto wrterr ;
} ;
if ( ent->Data.Health != 0)
{
if (fprintf(stream, "\"health\" \"%ld\"\n"
,ent->Data.Health
)<0)
goto wrterr ;
} ;
if ( ent->Data.Toggle)
{
if (fprintf(stream, "\"toggle\"\n")<0)
goto wrterr ;
} ;
if ( ent->Data.StartOpen)
{
if (fprintf(stream, "\"start_open\"\n")<0)
goto wrterr ;
} ;
if ( ent->Data.DoorDontLink)
{
if (fprintf(stream, "\"door_dont_link\"\n")<0)
goto wrterr ;
} ;
if ( ent->Data.GoldKey)
{
if (fprintf(stream, "\"gold_key\"\n")<0)
goto wrterr ;
} ;
if ( ent->Data.SilverKey)
{
if (fprintf(stream, "\"silver_key\"\n")<0)
goto wrterr ;
} ;
// issue map params
DecodeMapParams(ent->Data.MapParams,stream) ;
int childNum = 0;
while ( childNum < numChild )
{
INode* childNode = node->GetChildNode(childNum) ;
Object* childObj = childNode->GetObjectRef() ;
if( childObj->CanConvertToType(triObjectClassID) )
{
// dummy up a temp scene object
MySceneEntry ent(childNode,childObj,OBTYPE_MESH) ;
// write child brush
if (WriteMesh(&ent, gi, stream))
goto wrterr ;
}
else
{
char errStr [ 80 ] ;
sprintf(errStr,"Error: Entity '%s' linked to non-mesh object",ent->QClassName) ;
MessageBox(GetActiveWindow(),errStr,"QMAPEXP", MB_OK) ;
}
childNum ++ ;
} ;
if (fprintf(stream,"}\n")<0)
goto wrterr ;
}
else // unknown link - just issue params
{
if (fprintf(stream, "{\n"
"// %s\n"
"\"classname\" \"%s\"\n"
,node->GetName()
,ent->QClassName
)<0)
goto wrterr ;
// issue map params
DecodeMapParams(ent->Data.MapParams,stream) ;
// issue linked brushes
int childNum = 0;
while ( childNum < numChild )
{
INode* childNode = node->GetChildNode(childNum) ;
Object* childObj = childNode->GetObjectRef() ;
// check if its a meshable object
if( childObj->CanConvertToType(triObjectClassID) )
{
// dummy up a temp scene object
MySceneEntry ent(childNode,childObj,OBTYPE_MESH) ;
// write child brush
if (WriteMesh(&ent, gi, stream))
goto wrterr ;
}
else
{
char errStr [ 80 ] ;
sprintf(errStr,"Error: Entity '%s' linked to non-mesh object",ent->QClassName) ;
MessageBox(GetActiveWindow(),errStr,"QMAPEXP", MB_OK) ;
}
childNum ++ ;
} ;
if (fprintf(stream,"}\n")<0)
goto wrterr ;
} ;
} ;
} ;
} ;
} ;
// finish off file
if (!playerStartFound) // all maps must have a player start
{
MessageBox(GetActiveWindow(),"Map has no player start entity. Default start added at 10,10,10","QMAPEXP", MB_OK) ;
if (fprintf(stream, "{\n"
"\"classname\" \"info_player_start\"\n"
"\"origin\" \"10 10 10\"\n"
"}\n"
) <0 )
goto wrterr ;
} ;
// all done, close MAP file
if(theFile.Close())
goto wrterr;
// check for bad brushes
if ( errorBrushes != 0 )
{
char errStr[80] ;
sprintf(errStr,"Warning: %d brushes have errors, see MAP file.",errorBrushes) ;
MessageBox(GetActiveWindow(),errStr,"QMAPEXP", MB_OK) ;
} ;
return 1;
wrterr:
Alert(IDS_TH_WRITEERROR) ;
theFile.Close() ;
remove(filename) ;
return 0 ;
} ;
int QMapExport::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi)
{
int status;
status=qmap_save(filename, ei, gi, this);
if(status == 0)
return 1; // Dialog cancelled
if(status > 0) {
#ifdef DBGQMAP
DebugPrint("QMAP status OK!\n");
#endif
}
#ifdef DBGQMAP
else
if(status < 0)
DebugPrint("Error somewhere in QMAP!\n");
#endif
return(status);
} ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -