DMDX Help.


Bitmap notes.

    A rather cool thing is the ability to make the background of a bitmap transparent using a feature of DirectX called Color Keying. A graphic frame with the <ColorKey> switch set will examine the color of the top left pixel of the bitmap and when adding that graphic to the displayed frame all pixels of that color will not be copied. Especially handy if you have changed the background color or your bitmaps do not have a white background.

    If you are importing large numbers of .IMG files from DMTG using IMG2BMP.EXE you will not need to stretch the images using some other image manipulation program, DMDX can do it with the
<DefaultBMPMultipliers> switch, typical values for stretching EGA images being <dbm 1.0,1.371>.


Stretch Blt modes.

    For the longest time whenever you wanted to scale a bitmap smaller with the bitmap multipliers you could get some fairly ugly artifacts until I stumbled across the win32 SetStrechBltMode function and nowadays you put something like <dbm 1 HALFTONE> in your item file and down scaled bitmaps are just fine.  Up scaled bitmaps have always been more or less fine (beyond the obvious fuzziness issues that are inherent in magnifying data).  Why is this important?  If you want to build an item file that runs on a number of machines that uses bitmaps and you want a fairly consistent experience from one machine to the next you'll want to provide higher resolution bitmaps that you scale down using a fraction of the screen's dimensions otherwise depending on the screen resolution on the machine the sizes of the bitmaps will change (assuming you're using <vm desktop> and these days you really should be using it, the days of being able to run everything at a fixed display resolution are all but past because when you run a flat screen LCD monitor at a resolution other than it's native one the monitor then takes extra time to render what it's being sent to it into it's native resolution).


Scaling bitmaps across machines.

    Speaking of making an item file running on multiple machines with scaling bitmaps you'd probably also want to know the aspect ratio of the screen your item file is running.  Maybe you can get away with assuming a 16:9 widescreen device regardless of it's resolution and scale those bitmaps down to a fraction of the screen width nicely using the <bmp> options (say <bmp 0,0,1,1> for full screen bitmaps or <bmp 0.25,0.25,0.75,0.75> for half screen centered bitmaps) but if not in the past you'd have been stymied pretty good, however these days you can actually detect the aspect ratio using the expression tokens VideoModeX and VideoModeY (see the <SetCounter> help).  You've got two choices here, one (as long as the aspect ratio of all your images is the same, if not see the second option) is to detect the aspect ratio like the <Instruction> help does and then passing one of two macros (one for 4:3 screens and another for 16:9) to all your <bmp> keywords that determines the upper left and lower right corners for your bitmaps.  The other option involves knowing the size of each bitmap which is perhaps more labor intensive (unless of course they're all the same) but is less prone to accidentally distorting an image as it involves using the bitmap multipliers that carefully preserve image aspect ratios.  Using DMDX 6.5.0.0 or later you set up a couple of macros that have the scaling factor for that that image and because DMDX has no floating point stuff available we'll fudge it with with 4 digit fixed point calculations using the fixed point set option FXPSET in the macro keyword and then display it using the macro in a <bm> keyword.  In the following example the bitmap being displayed is 2048 pixels high and we're aiming to display it as five sevenths of the screen height:

+101 <macro fxpset 4 f = (videomodey * 10000 / 2048) * 5 / 7> <bm `f halftone> <bmp> "image" * ;

    This method is demoed in the graphics portion of the features test demo FEATURES.RTF in this archive:  https://psy1.psych.arizona.edu/~jforster/dmdx/demos.zip

    Note that if hardcoding your image size into the item file isn't a good option because all your images are different sizes and you don't have an undergrad hanging around to do all that work for you you can in fact make DMDX determine the size of the images automatically (if not inelegantly) by first displaying the image for zero ticks with <StoreCoords> storing the resulting image size in a pair of macros (two of the four of them anyway).  Of course those sizes come back as fractional coordinates (so "0.654321" for instance) and not pixel values so we have to strip the "0." off them with a bit of macro popping and now we've got values between zero and one million so we have to do a bit of gerfingerpoken mathematically to make sure we don't get an arithmetic overflow by first dividing by 100 before normalizing to the screen height and then getting the remaining factor of 10000 but then we can plug them into something closely resembling the above:

0 <md .l.++> <md .t.++> <md .r.++> <md .b.++> <set c1=0> <bmp> "golftp" <sc .l., .t., .r., .b.> %0 / c;

0 <macro pop .b., c1> <macro pop .t., c1> <macro pop .b., c1> <macro pop .t., c1> <set c.ht. = ((`.b. - `.t.) / 100 * videomodey / 10000)))> <macro fxpset 4 .f. = (videomodey * 10000 / c.ht.) * 5 / 7> <bm `.f. halftone> <bmp> "golftp" ;

    Of course that's only going to work if your source images are smaller than the display, if your images are larger then I suppose you can put a <bm 0.5> in the <sc> frame and then multiply c.ht. by two once it's been determined (or <bm 0.25> and four if they're much larger).  And <md .l.++> <md .t.++> <md .r.++> <md .b.++> <set c1=0> only has to occur once, no need to include it for every item.  Also note you could stick  a <delay 2> in the first frame of one of those items as you'll be encountering the default delay of a half second or so for both of them.  And they do have to be two items, the macros with the bitmap dimensions in them won't be usable till that frame is rendered and rendering doesn't happen till after an item is parsed.  And technically that popping operation really should continue popping leading zeroes off at least the top value as any constant with a leading 0 is interpreted as octal by DMDX's expression evaluator.  Personally, if your source images are around 4/5ths of your screen size or larger you should probably be using the <bm 0.5> solution above or just display the %0 bitmap at the top of the screen -- assuming your source bitmaps are more than 1/5th of the screen as octal zero is the same as decimal zero...



Click logging in scaled bitmaps.


    With the addition of relativeclicklogging in the <2Did> keyword a good opportunity arose to demo scaled bitmaps and the ability to click on a specific region, or at least to ask a subject to do so and see if they got it right.  Because we're using the normalizedata <2Did> option this item file works across multiple display sizes (essential if you're going to be using it for remote testing).  The bitmaps here are found in the demos archive mentioned above.  The key thing about this demo is using <sc> to store the coordinates that the bitmap was rendered to and then using <sbr> to set the rectangle for the button defined in the <2Did> statement to those stored coordinates so different aspect ratio bitmaps will all be handled correctly -- however in order to do that we have to actually display the text before we can change the button rect.  Unlike other uses of <sc> and <sbr> (say <expireif>) we can't just present the bitmap in the same color as the background before testing the subject so we just present it for zero ticks beforehand followed by a blank frame gathering the coordinates of it's display and then present the item that gathers the response click.  Other interesting points here include the fact that bitmaps are smaller than the requested display size (a third of the width of the screen) in most cases so we're scaling them up (most of the time anyway) with the halftone scaling method.  Also of interest is presenting them with an <inst> keyword with the explicatory text in the right half of the screen (we do have to use the framebyframe option because <inst> spacing is going to freak if it uses centered positioning):

<ep>
<!branchdiagnostics>
<fd 30> <cr> <id #keyboard> <!ntl> <t 100000> <nfb>
<2Did mouse relativeclicklogging,100
    bitmap,.1,.2,.3,.4
    normalizedata>
<xyjustification framebyframe> <inst hardmargin>
<eop>

~1 ml++ mt++ mr++ mb++ <mpr +bitmap>;

! <! GOLFTP is 350 px wide>;
1 <xyjustification center> <macro fxpset 4 f = (videomodex * 10000 / 350) / 3> <dbm `f halftone STAT>  <xy .25,.5> <bmp> "GOLFTP" <sc l, t, r, b> %0 / c;
+101 <delay 2> <inst .5,.3,.9> <xyjustification framebyframe> <sbr bitmap, `l, `t, `r, `b> <xy .25,.5> <bmp> "GOLFTP" <inst esc>, <xyjustification leftbottom>
"In ", "this ", "experiment ", "click ", "on ", "the ", "flag ", "in ", "the ", "image ", "on ", "the ", "left" * ;

    Having just crafted that new example I see that it's almost as convoluted as the old method that presents the image for two ticks prior to gathering the response so here's the old way (it uses tildes for macro expansion, not much different seeing as the definition is in a different item anyway):


~1 <macro fxpset 4 f = (videomodex * 10000 / 320) / 3> <! WINLOGO is 320 px wide>;
1 <xyjustification center> <xy .25,.5> <dbm ~f halftone STAT> <bmp> "WINLOGO" <sc l, t, r, b>;
+102 <delay 2> <inst .5,.3,.9> <sbr bitmap,~l, ~t, ~r, ~b> <noerase> <xyjustification leftbottom>
"In ", "this ", "experiment ", "click ", "on ", "the ", "flag ", "in ", "the ", "image ", "on ", "the ", "left" * ;

    If we use clicklogging instead of relativeclicklogging we can use the data logging macros and add a line after items 101 and 102 to display a character over where they clicked:

0 ! "X" <xyjustification center> <xy ~.dataloggingx.,~.dataloggingy.>;


Alpha Blending.

    Another cool thing is the ability to alpha blend two (or more) frames together -- although this looks busted these days and is explicitly unavailable when using the Direct3D renderer. An alpha blend adds two frames together as transparencies, a succession of frames with alpha values changing from 1.0 to 0.0 in small increments will fade from one frame to the next. As with all DMDX color things a 16 bpp (bit per pixel, 65535) color mode is nearly essential. It works with all types of frames with the likely exception of Digital Video frames regardless of how many colors or what was used to make the frame. It is fairly CPU intensive to prepare (I have not written a very efficient algorithm, it does however work with everything), check your preparation times if you intend to use REQSHED or the D parameter. To blend from the word "first" to the word "second" in 6 steps the following item would be used:

0 "first" <as> / <ab .8> "second" / <ab .6> "second" / <ab .4> "second" / <ab .2> "second" / "second";

    The first frame's switch <as> (or <AlphaSource> if you like) causes it to be stored as the alpha source for all following blends in that item, after that it is discarded, you can't blend across items. The next four frames will be a combination of the words first and second and the last frame is only the word second, <ab 0> being equivalent to no blending. Each frame is generated in the normal fashion and then blended with the surface that was stored with the most recent <as> switch -- they are not blended with the previous frame (and if you put non-erase switches in very odd things would happen). An interesting thing to note with only four steps in the blend is that this could be displayed by a 256 color display as the default windows palette contains four shades of gray -- however four steps is a pretty crude blend, a much better instance that requires a 16 bpp display is:

0 "first" <as> / <ab .95> "second" / <ab .9> "second" / <ab .85> "second" / <ab .8> "second" / <ab .75> "second" / <ab .7> "second" / <ab .65> "second" / <ab .6> "second" / <ab .55> "second" / <ab .5> "second" / <ab .45> "second" / <ab .4> "second" / <ab .35> "second" / <ab .3> "second" / <ab .25> "second" / <ab .2> "second" / <ab .15> "second" / <ab .1> "second" / <ab .05> "second" / "second";

    An interesting thing to note is that you can store a new alpha source in any frame leading to the ability to blend a bit to one word and then change to a new word (whether anyone would ever want to do this is another thing).
   

Image Loading time issues.

    In the ancient past (no modern hardware is slow enough to require this degree of chicanery) if people required the fastest possible loading of bitmap displays for low ISIs (usually because they are using continuous running with an FMRI image sequence) they should convert their bitmaps to 256 color .BMP files, however they should still use a 16 bit display, or possibly a 24 bit display. Because the image is displayed on an RGB surface the fact that it's encoded as a 256 color palletized surface doesn't matter, no changing of colors to match a system palette occurs (some changing does occur as a 16 bit surface is 5 bits of red, 6 of green and 5 of blue whereas a 256 color palette has 6 of everything but that's trivial or if it does matter use a 24 bit display mode) and because each image is encoded separately the palette for the image can be super fudged by the conversion program to match the colors in the image and it's impressive what a bit of dithering will achieve. 800x600 8 bit .BMPs load in 50ms on my test bed (preparation A times) vs. 150ms for 24 bit .BMPs vs. 300ms to 600ms for .JPGs. All have a preparation B time of about 40ms (the time to make a DMDX frame out of them once loaded into memory).
   
   



DMDX Index.