DMX: Difference between revisions
TomEdwards (talk | contribs) (hunted down vsdmxio...the truth is out there!) |
TomEdwards (talk | contribs) (→Programming: iterator) |
||
Line 28: | Line 28: | ||
== Programming == | == Programming == | ||
Handling DMX files has many similarities to handling [[KeyValues]]. The two big architectural differences are that: | |||
* <code>CDmxElement</code> objects contain either <code>CDmxAttribute</code> objects, which hold actual data, or more <code>CDmxElement</code>s. Arrays are possible in both cases. | |||
* Values are accessed through a single [[W:Template (programming)|templated]] function, not lots of different ones. | |||
For a full list of attributes, see the bottom of <code>public\datamodel\dmattributetypes.h</code>. | |||
{{note|[[String]]s are <code>[[CUtlString]]</code> objects, not <code>[[char]]</code>!}} | |||
=== Iterator === | |||
This code will print string, int, float and bool values in the given DMX to the console. {{todo|Elegant solution to arrays.}} | |||
<source lang=cpp> | <source lang=cpp> | ||
Line 34: | Line 47: | ||
#include "dmxloader/dmxelement.h" | #include "dmxloader/dmxelement.h" | ||
CON_COMMAND( | 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(); | DECLARE_DMX_CONTEXT(); | ||
CDmxElement* DMX = (CDmxElement*)DMXAlloc( 50000000 ); | CDmxElement* DMX = (CDmxElement*)DMXAlloc( 50000000 ); | ||
if (UnserializeDMX(args[1],"MOD",false,&DMX)) | if (UnserializeDMX(args[1],"MOD",false,&DMX)) | ||
{ | { | ||
IterateDmxElement(DMX); | |||
} | } | ||
else | else |
Revision as of 12:58, 10 December 2010
DMX (Data Model eXtensible?) is a binary file format used in newer Valve technologies. It appears to be a generic replacement for ASCII formats like SMD or VDF. Currently it has two known uses: Particle systems (.pcf
) and model source data (.dmx
).
DMX has several advantages over VDF. It is:
- Efficient, especially when storing large ints or accurate floats
- Generic, and able to store most memory structures
- Robust, since it does not have to worry about delimiters, line breaks or unclosed quote blocks
Using DMX
With DMX being a binary format, it is not practical either to infer how a given file works from reading it, or to alter one by hand. When the tools for reading/writing them aren't publicly available, this is a problem!
Models
DMX model source files are generated by vsdmxio
, which only available publicly as a Maya plugin (sourcesdk/maya/2009/plug-ins/valveSource/
). Some editing options are available with the Source 2009 SDK tool dmxedit
however, including export to OBJ (unweighted, no animations).
To use dmxedit:
- Create an empty file called
vs.lua
in the SDK binaries folder. This is probably meant to contain commands that are executed every time you run the tool. - You must then create a LUA file containing the actions you want to perform. Here is a simple example that exports to OBJ:
Load( "<path_to_dmx>" )
Save("<export_path>.obj")
- Perform
dmxedit myfile.lua
to run the script.
If export a mesh DMX to OBJ you will get a single file. If you export a morph DMX you will get one OBJ for each flex animation that was in the file. If you chose an animation you will get nothing; it seems that dmxedit doesn't support animations.
Programming
Handling DMX files has many similarities to handling KeyValues. The two big architectural differences are that:
CDmxElement
objects contain eitherCDmxAttribute
objects, which hold actual data, or moreCDmxElement
s. Arrays are possible in both cases.- Values are accessed through a single templated function, not lots of different ones.
For a full list of attributes, see the bottom of public\datamodel\dmattributetypes.h
.

CUtlString
objects, not char
!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]);
}