VERC: .MAP to .DXF Conversion Last edited 21 years ago2002-10-09 21:11:00 UTC

You are viewing an older revision of this wiki page. The current revision may be more detailed and up-to-date. Click here to see the current revision of this page.

This article was recovered from an archive and needs to be reviewed

  1. The formatting may be incorrect as it was automatically converted to WikiCode from HTML, it needs to be revised and reformatted
  2. Some information may be out of date as it was written before Half-Life was available on Steam
  3. After the article is re-formatted and updated for Steam HL, remove this notice
  4. Please do not remove the archive notice from the bottom of the article.
  5. Some archive articles are no longer useful, or they duplicate information from other tutorials and entity guides. In this case, delete the page after merging any relevant information into other pages. Contact an admin to delete a page.
The code below, sent to me by David Speyrer, is the part of the Hammer code that converts a map from standard .map format to .dxf format. It may be of use to anyone writing .map conversion programs.

struct DXFEXPINFO
{
structint nObject;
BOOL bVisOnly;
CMapWorld *pWorld;
FILE *fp;
};

void CMapDoc::OnFileExporttodxf( void )
{
static CString str;

if (str.IsEmpty())
{
int nDot;

// Replace the extension with DXF.
str = GetPathName();
if ((nDot = str.ReverseFind('.')) != -1)
{
str = str.Left(nDot);
}
str += ".dxf";
}

CExportDlg dlg(str, "dxf", "DXF files (.dxf)|.dxf||");
if (dlg.DoModal() == IDCANCEL)
return ;

str = dlg.GetPathName();
if (str.ReverseFind('.') == -1)
str += ".dxf";

FILE *fp = fopen(str, "wb");

pWorld->CalcBounds(TRUE);
BoundBox box;
box.UpdateBounds(pWorld);

fprintf(fp,"9 n$ACADVER n1 nAC1008 n");
fprintf(fp,"9 n$UCSORG n10 n0.0 n20 n0.0 n30 n0.0 n");
fprintf(fp,"9 n$UCSXDIR n10 n1.0 n20 n0.0 n30 n0.0 n");
fprintf(fp,"9 n$TILEMODE n70 n1 n");
fprintf(fp,"9 n$UCSYDIR n10 n0.0 n20 n1.0 n30 n0.0 n");
fprintf(fp,"9 n$EXTMIN n10 n%f n20 n%f n30 n%f n",
box.bmins[0], box.bmins[1], box.bmins[2]);
fprintf(fp,"9 n$EXTMAX n10 n%f n20 n%f n30 n%f n",
box.bmaxs[0], box.bmaxs[1], box.bmaxs[2]);
fprintf(fp,"0 nENDSEC n");

* Tables section *
fprintf(fp,"0 nSECTION n2 nTABLES n");
* Continuous line type *
fprintf(fp,"0 nTABLE n2 nLTYPE n70 n1 n0 nLTYPE n2 nCONTINUOUS"
" n70 n64 n3 nSolid line n72 n65 n73 n0 n40 n0.0 n");
fprintf(fp,"0 nENDTAB n");

* Object names for layers *
fprintf(fp,"0 nTABLE n2 nLAYER n70 n%d n",1);
fprintf(fp,"0 nLAYER n2 n0 n70 n0 n62 n7 n6 nCONTINUOUS n");
fprintf(fp,"0 nENDTAB n");
fprintf(fp,"0 nTABLE n2 nSTYLE n70 n1 n0 nSTYLE n2 nSTANDARD n70 n0 n"
"40 n0.0 n41 n1.0 n50 n0.0 n71 n0 n42 n0.2 n3 ntxt n4 n n0 n"
"ENDTAB n");

* Default View? *

* UCS *
fprintf(fp,"0 nTABLE n2 nUCS n70 n0 n0 nENDTAB n");
fprintf(fp,"0 nENDSEC n");

* Entities section *
fprintf(fp,"0 nSECTION n2 nENTITIES n");

// export solids
BeginWaitCursor();

DXFEXPINFO info;
info.bVisOnly = dlg.bVisibles;
info.nObject = 0;
info.pWorld = pWorld;
info.fp = fp;

// Enumerate all the solids in the world, calling the callback.
pWorld->EnumChildren(ENUMMAPCHILDRENPROC(SaveDXF),
DWORD(&info), MAPCLASS_TYPE(CMapSolid));

EndWaitCursor();

fprintf(fp,"0 nENDSEC n0 nEOF n");
fclose(fp);
}

static BOOL SaveDXF(CMapSolid *pSolid, DXFEXPINFO *pInfo)
{
if (pInfo->bVisOnly)
{
if (!pSolid->IsVisible(pInfo->pWorld, pInfo->pWorld->dwFilterFlags))
return TRUE;
}

CSSolid *pStrucSolid = new CSSolid;
pStrucSolid->Attach(pSolid);
pStrucSolid->Convert();
pStrucSolid->SerializeDXF(pInfo->fp, pInfo->nObject++);
delete pStrucSolid;

return TRUE;
}

void CSSolid::SerializeDXF(FILE *stream, int nObject)
{
char szName[128];
sprintf(szName, "OBJECT%03d", nObject);

// count number of triangulated faces
int nTriFaces = 0;
for ( int i = 0; i < m_nFaces; i++)
{
CSSFace &face = m_Faces[i];
nTriFaces += face.nEdges-2;
}

fprintf(stream,"0 nPOLYLINE n8 n%s n66 n1 n70 n64 n71 n%u n72 n%u n",
szName, m_nVertices, nTriFaces);

fprintf(stream,"62 n50 n");

for (i = 0; i < m_nVertices; i++)
{
float *pos = m_Vertices[i].pos;
fprintf(stream, "0 nVERTEX n8 n%s n10 n%.6f n20 n%.6f n30 n%.6f n70 n192 n",
szName, pos[0], pos[1], pos[2]);
}

// triangulate each face and write
for (i = 0; i < m_nFaces; i++)
{
CSSFace &face = m_Faces[i];
PINT pVerts = CreatePointIndexList(face);

for ( int v = 0; v < face.nEdges; v++)
pVerts[v]++;

for (v = 0; v < face.nEdges-2; v++)
{
fprintf(stream, "0 nVERTEX n8 n%s n10 n0 n20 n0 n30 n"
"0 n70 n128 n71 n%d n72 n%d n73 n%d n", szName,
v == 0 ? pVerts[0] : -pVerts[0],
pVerts[v+1],
v == (face.nEdges-3) ? pVerts[v+2] : -pVerts[v+2]
);
}
}

fprintf(stream, "0 nSEQEND n8 n%s n", szName);
}

User Questions

From the hlcoders mail list, Cortex writes: I'm trying to create a map to dxf converter using the code that Valve gave but I don't understand the last loop.

// triangulate each face and write
for (i = 0; i < m_nFaces; i++)
{
CSSFace &face = m_Faces;
PINT pVerts = CreatePointIndexList(face);

for ( int v = 0; v < face.nEdges; v++)
pVerts[v]++;

for (v = 0; v < face.nEdges-2; v++)
{
fprintf(stream, "0 nVERTEX n8 n%s n10 n0 n20 n0 n30 n"
"0 n70 n128 n71 n%d n72 n%d n73 n%d n", szName,
v == 0 ? pVerts[0] : -pVerts[0],
pVerts[v+1],
v == (face.nEdges-3) ? pVerts[v+2] : -pVerts[v+2]
);
}
}
[i]I only need more informations about the CSSFace class (the members), the CreatePointIndexList and the calculation of the "nEdges" member of CSSFace. Then I'll be able to understand what gets done and be able to merge it to my code.


David Speyrer responds: This code assumes that every vertex in the solid can be referred to by a unique index, so a rectangular solid would have 8 verts with indices from 0 to 7. CreatePointIndexList fills out an array with the indices of verts on the given face in clockwise winding order. GetConnectionVertex returns the vertex between the two given edges. The code for CreatePointIndexList is below.

Hope this helps!


// Create point list, but return indices instead of vertices.//
PINT CSSolid::CreatePointIndexList(CSSFace &face, PINT piPoints)
{
PINT pts;
int nPts = 0;

if (piPoints)
pts = piPoints;
else
pts = new int [face.nEdges];

SSHANDLEINFO hi;

for ( int i = 0; i < face.nEdges; i++)
{
// calc next edge so we can see which is the next clockwise
point
int iNextEdge = i+1;
if (iNextEdge == face.nEdges)
iNextEdge = 0;

CSSEdge edgeCur = (CSSEdge) GetHandleData(face.Edges[i]);
CSSEdge edgeNext = (CSSEdge)
GetHandleData(face.Edges[iNextEdge]);

SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
ASSERT(hVertex);

GetHandleInfo(&hi, hVertex);
pts[i] = hi.iIndex;
}

return pts;
}
This article was originally published on the Valve Editing Resource Collective (VERC).
TWHL only archives articles from defunct websites. For more information on TWHL's archiving efforts, please visit the TWHL Archiving Project page.

Comments

You must log in to post a comment. You can login or register a new account.