C for Yourself - part 51

Steve Mumford takes a look at the DrawFile module in action

Towards the end of last month's column, I mentioned the DrawFile module that's supplied as part of the later versions of RISC OS - it provides a simple, one-step method of plotting Draw files to the screen. This time round, I'll show you how to make use of it in your own applications. If you're using the Acorn C/C++ compilers, all you need to do to enable DrawFile is add the line:

#include "drawfile.h"

to your code and link it with the appropriate renderlib library from the toolbox. The version available from Acorn's FTP site has been built with the OSLib package in mind, but that's available for download there too.

The quickest method of invoking the DrawFile module is to use the *Render command that it provides. At its simplest, the command takes a Draw file and displays it on screen, but extra control is provided for those who need it. It's worth experimenting to get a feel for how the command operates - the parameters that *Render accepts are almost identical to the ones taken by the DrawFile_Render SWI. In order to position a Draw file on screen, *Render makes use of the six values held in the transformation matrix discussed in last month's column, and it's a particularly quick method of trying different scaling factors to see how they operate without having to continually recompile chunks of C.

As well as a star command, DrawFile provides three SWI calls that cater for rendering Draw objects, calculating bounding boxes and declaring fonts used in such a file prior to printing. We'll be using these to provide support for clip art from within our application, as these SWIs let you plot files directly from memory - allowing us to store them in line and so make the final data format a bit neater. DrawFlIe_Render is the first we'll look at, and the code fragments shown below should give you an idea as to how to proceed.

The first step in plotting a Draw file is to load the data itself into memory, and this can be done by using OS_File. The best policy would be to check the file size before loading it in, so that memory could be allocated on the fly as it is required. However, for simplicity, I'm assuming we've set aside a suitably large area of memory already. We still need to determine the file size as DrawFile_Render needs to know how much data to expect; however, OS_File provides that information upon successfully loading a file, so we don't have to go out of our way to get the values we're looking for.

#define MAX_FILE_SIZE 51200
char *filename[] = "Test\0";
char *buffer;
_kernel_swi_regs regs;
_kernel_oserror *error;

buffer = calloc(MAX_FILE_SIZE, sizeof(char));
regs.r[0] = 16;
regs.r[1] = (int) filename;
regs.r[2] = (int) buffer;
regs.r[3] = 0;
error = _kernel_swi(OS_File, &regs, &regs);
filesize = regs.r[4];

The value of 16 in RO tells OS_File to use the string pointed to by R1 as the full file name; the address at which to load the file is stored in R2, and R3 is set to zero. If all goes well, the data is loaded into memory and the length of the file is stored in R4. Once the Draw file is safely in RAM, it's just a matter of setting up the transformation matrix (held as a 3 by 2 integer array) with the values to represent scale factor and location on screen before calling the SWI:

int transform[3][2];
int flags = 0;

transform[0][0] = 1 << 16;
transform[0][1] = 0;
transform[1][0] = 0;
transf6rm[1][1] = 1 << 16;
transform[2][0] = x * 256;
transform[2][1] = y * 256;
drawfile_render(flags, (void *) buffer, filesize, &transform, 0, 0);

The flags parameter allows you to modify the way draw objects are plotted; in normal use this will be set to zero, but if bits 0, 1 and 2 are set, DrawFile will either plot bounding boxes round the objects, suppress plotting of the objects themselves or allow you to change the default 'flatness' of the draw paths in conjunction with the sixth parameter.

Following that, the location of the Draw file in memory is supplied as a void pointer, along with the file size stored as an integer, and the address of the six-word transformation block. That's enough to get a Draw object to appear on screen, but the fifth parameter can be used to apply clipping to the objects before they're drawn, particularly useful when plotting to windows in the standard WIMP redrawing loop. In this case, the fifth parameter should point to a BBox structure that holds four integers storing the minimum and maximum x and y values for the area to be displayed in OS units. Any objects that lie within this region, either partially or completely, are drawn on screen.

Source: Acorn User - 195 - June 1998
Publication: Acorn User
Contributor: Steve Mumford