Simple Pre-Processor for HDi
Hope you all had a good break. I haven't blogged for a while due to travel (both business and pleasure) and laziness… but I thought I'd start off today with simple pre-processor for HDi.
One of the things that is missing from HD DVD is a good pre-processor; anyone familiar with C will know of all the good (and evil) things you can do with a few #define macros. Anyone not familiar with C, well, you don't know what you're missing out on :-)
Anyway, what I am basically talking about is the ability to define macros (symbolic constants; shortcuts; expansions; whatever) that you can use in your markup files and script files to simplify development.
Here's a common problem scenario (at least for me):
- Lay out some simple markup
- Create a button foo with (eg) an x position of 100px
- Write some animation that moves foo from 100px to 200px (this could be in script or markup)
- Realise you need to shift foo to 110px to accommodate a stylistic change
- Now figure out all the places where you need to change 100px to 110px, noting that you can't do a global search-and-replace because 100px could refer to other things as well
Traditionally this kind of problem (known as a "magic number") is solved by using a symbolic constant – we define a placeholder value named (eg) FOO_X and we define it to be 100px. Then everywhere we want to refer to the x location of foo, we use FOO_X rather than 100px. Then if we want to update foo to be at 110px later on, we simply change the definition of FOO_X to be 110px and our work is done.
This is easily done in script (where you have variables) but not so easily done in markup. So, I have written a very simple pre-processor that will take a bunch of macro definitions and replace them in your markup files AND give you a nice script file containing matching declarations to go along with it.
In addition to simple text expansion (FOO_X = 100px) you can also do arithmetic (FOO_X = BAR_X + 100) and indeed perform any kind of processing in your macros because they are all eval-ed at "compile" time. This has made my life a lot easier, especially when I am just testing things out and I need to re-lay-out stuff over and over again.
Attached is a simple project, along with preprocess.js. You run preprocess.js like this:
cscript.exe preprocess.js <defs> <infile> <outfile> [-d]
where:
- <defs> is the name of the definitions file, eg "my_definitions.ini"
- <infile> is the name of the input file, eg "markup_with_symbolic_names.xmu"
- <outfile> is the name of the output file to create, eg "markup.xmu"
- The optional –d switch produces a .JS file with the same base name as <defs> containing JScript declarations for all the macros
The definitions file is a simple text file that contains four types of lines:
- Empty lines or lines beginning with a semi-colon are ignored (eg, use for comments)
- Lines of the format NAME <space> TEXT define NAME to be exactly TEXT
- Lines of the format NAME <space> '=' CODE define NAME to be the evaluation of CODE, which can contain references to functions or other NAMEs
- Lines of the format '#' CODE run CODE directly without creating any new names (it is assumed the function being called adds names implicitly)
If a macro definition looks like a number, the system will automatically create an additional macro with the same name with "_PX" on the end that has the same value with "px" on the end. An example of a simple file:
; Here is a simple file
; These lines are ignored
; This creates two macros
; The first is called "BUTTON_X" and has the value 100
; The second is called "BUTTON_X_PX" and has the value "100px"
BUTTON_X 100
; This also creates two macros by doing simple arithmetic
; Given the definition of BUTTON_X above, this will produce
; both "BUTTON_Y" with a value of 200
; and "BUTTON_Y_PX" with a value of "200px"
BUTTON_Y = BUTTON_X + 100
; This runs the theoretical function DoSomethingCool, which you
; could add to preprocess.js
#DoSomethingCool()
Note that preprocess.js is not necessarily the best code in the world, nor is it a secure application (it will eval arbitrary input code, so DO NOT USE IT on untrusted definition files!). It was something I threw together and have been iterating on in the normal hacker fashion. It was an itch that needed scratching, not a well-designed and thought-out application.
Also note that whilst using the –d switch will output a script file, it is not big-endian as the HD DVD spec requires! This is due to a limitation in the FileSystemObject. You need to open the JS file in Notepad and re-save it with Big Endian encoding. That's why it isn't generated by default…
So, on to the enclosed example HDi program, it is very simple and very ugly. All it shows you is a simple defs file and a simple input markup file. Running the batch file will create the output markup file and then run the result (assuming HdiSim.exe is in your PATH). Clicking on the blue square makes it grow larger.
AMAZING!
But what is "cool" about this is that if you edit the defs.ini file and change (eg) the SMALL_W_ANIMATED value to 500 (to make the blue button grow larger) and re-run the batch file, the red button will automatically shift as well. No need to go and tweak its values to compensate for changes in the blue button.
AMAZING!
Well, not so much, but in more complicated projects this is a real time-saver.
Comments
Anonymous
February 02, 2007
What's to stop one from simply using a DTD with entities to serve the same purpose? Are DTDs not supported in the iHD spec?Anonymous
February 03, 2007
HD DVD allows the use of custom schemas as simple namespace disambiguators, but it does not allow you to reference a DTD / XSD and then validate against it or use any defined entities.