DMX

DMX (Data Model eXchange) stores a Datamodel object, encoded in either binary or ASCII. The internal structure or "format" of a DMX is defined by the user.
==Header==
All DMX files start with this header:
<!-- dmx encoding [encoding name] [encoding version] format [format name] [format version] -->
==Encodings==
===KeyValues2===
This ASCII encoding is the successor to KeyValues. It's good if you have a small DMX and want it hand-editable.
===Binary===
Compared to KeyValues2, binary DMX is:
# Small, especially when storing large ints or accurate floats
# Fast, as values do not have to be converted to or from human-readable characters
# Robust, since it does not have to worry about delimiters, line breaks or unclosed quote blocks
# Inscrutable, because it contains native binary data
Binary is good for large DMXes.
See DMX/Binary for a technical description of the encoding.
==Formats==
These are the formats used by Valve.
===Particle System===
Created by the Particle Editor and read by the engine, usually with the extension pcf. There should be no reason to manipulate these yourself.
===Model===
The DMX model deprecates SMD in and newer. It can be exported by Valve's official Maya plugin (sourcesdk/maya/2009/plug-ins/valveSource/), the Blender Source Tools and from the 3ds Max pipeline tools in Wall Worm Model Tools.
There are some DMX-related tools in the SDK:
* dmxedit
* dmxconvert
===Engine Tools===
DMX is widely used to represent data in engine tools. For example, Source Filmmaker save files are stored as DMX, and materials are converted to DMX by Material Editor in order to be edited.
==Programming==
Handling DMX files has many similarities to handling KeyValues. The big architectural differences are that:
* Where KVs had keys, Datamodel has CDmxElement objects containing CDmxAttribute (which can point to further elements).
* There is support for arrays.
* Attribute values are accessed through a single templated function, not lots of different ones.
* Each element can have multiple parents. Each element has a 128-bit ID to support this.
===Source API===
Source has two DMX APIs: CDmxElement and CDmElement. The former is a lightweight implementation designed for use in game code; the latter is designed around the needs of the engine tools and includes heavyweight features like undo levels and element factories. The mod SDK only supports CDmxElement.
For a full list of attribute types, see the bottom of public\datamodel\dmattributetypes.h.
====Creating====
#include "cbase.h"
#include "dmxloader/dmxloader.h"
#include "dmxloader/dmxelement.h"
CON_COMMAND( dmx_create, "Makes a simple DMX" )
{
	DECLARE_DMX_CONTEXT();
	CDmxElement* DMX = CreateDmxElement("MyElementTypeName");
	DMX->AddAttribute("C++ templates")->SetValue<bool>(true);
	DMX->AddAttribute("Hello")->SetValue("world"); // non-templated shortcut for strings
	DMX->AddAttribute("An_Array")->GetArrayForEdit<float>().AddToTail(3.141);
	CUtlBuffer buf;
	SerializeDMX(buf,DMX);
	FileHandle_t fh = filesystem->Open("test.dmx","w","DEFAULT_WRITE_PATH");
	filesystem->Write(buf.Base(),buf.TellPut(),fh);
	filesystem->Close(fh);
}
====Iterator====
This code will print string, int, float and bool values in the given DMX to the console. 
#include "cbase.h"
#include "dmxloader/dmxloader.h"
#include "dmxloader/dmxelement.h"
void IterateDmxElement(CDmxElement* pRoot)
{
	for (int i=0;i<pRoot->AttributeCount();i++)
	{
		CDmxAttribute* pCur = pRoot->GetAttribute(i);
		CDmxElement* subElem;
		
		Warning( "%s: ",pCur->GetName() );
		switch (pCur->GetType())
		{
		case AT_ELEMENT:
			subElem = pCur->GetValue<CDmxElement*>();
			if (subElem)
				IterateDmxElement(subElem);
			break;
		case AT_STRING:
			Msg( "STRING | %s\n",pCur->GetValue<CUtlString>().Get() );
			break;
		case AT_INT:
			Msg( "INT | %i\n",pCur->GetValue<int>() );
			break;
		case AT_FLOAT:
			Msg( "FLOAT | %f\n",pCur->GetValue<float>() );
			break;
		case AT_BOOL:
			Msg( "BOOL | %s\n",pCur->GetValue<bool>() ? "true" : "false" );
			break;
		
		default:
			Msg("Unknown type %i\n",pCur->GetType());
			break;
		}
	}
}
CON_COMMAND(dmx_iterate, "Prints a DMX file to the console")
{
	DECLARE_DMX_CONTEXT();
	
	CDmxElement* DMX = (CDmxElement*)DMXAlloc( 50000000 );
	if (UnserializeDMX(args[1],"MOD",false,&DMX))
	{
		IterateDmxElement(DMX);
	}
	else
		Warning("Could not read DMX file %s\n",args[1]);
}
====KeyValues2====
dmxloader.lib has several "TextDMX" functions that are not referenced in the SDK's headers. Among them are:
bool UnserializeTextDMX(const char* pFilename,CUtlBuffer & buf,CDmxElement** ppRoot); // fails
bool SerializeTextDMX(const char* pFilename,CUtlBuffer & buf,CDmxElement* pRoot); // produces invalid files
They are both underdeveloped. It's possible that only CDmElement supports KeyValues2.
===Third-party libraries===
There are currently two other Datamodel/DMX libraries:
* Datamodel.NET (CLR/C#)
* datamodel.py (Python)
* Datamodel-rs (Rust)
Category:File formats