3d Wire Frame Object Editor Developer's Notes Index: 1) Overview 2) Data Structures 3) Using Intuition 4) General Program Flow 1) Overview This program is useful for creating and editing 3 dimensional wire frame objects. The program uses a mouse-based multiple-window interface to communicate with the user. The user interacts with the program through the selection of gadgets and menu items. Gadgets are small icons appearing within a window which may be selected by pointing to them with the mouse pointer and pressing the left mouse button. Menu items are elements of drop down menus which may be selected using the right mouse button. Often used commands are accessible through the gadgets, which are located in a common "Control Panel" window. Less used commands are accessed through the menu system. When the program starts, it creates its own custom screen on top of the workbench screen. This screen is in 640x400 mode, with 3 bit planes. In addition to the Control Panel, another "Object Window" will display a perspective view of the object currently being edited. To learn how the user interacts with the system, see the User's Document. Alternatives to using the gadgets may be to use the keyboard, lightpen, or joystick. All of these are supported by the hardware, but I don't know how to use them yet. The Rom Kernal manual explaining how to access other features of the system should be out 'real soon now', according to its publisher. 2) Data Structures The major structures in this program are those that hold the vertex and edge information of the current object. The vertex list is a linked list of vertex structures. Each vertex structure has fields for both NDC and physical device coordinates, as well as fields used as group flags and for simplifying saving and loading of objects. The type of each of these elements is a float in the intial version, although it may be changed to binary fractions or integers to speed up arithmetic operations. In Aztec C, all float operations are performed in 32 bit Motorola FFP format, although 64 bits are reserved in memory to accomodate a future floating point processor. The edge table is implemented as a one-way linked list to conserve memory and simplify updating the table. Each element of the list will hold two numbers representing addresses in the vertex list corresponding to the endpoints of that edge. Groupings are kept track of by setting a signal field in vertices which belong to a group. Groupings are saved on disk using the same format in which objects themselves are stored. When a grouping is saved to or loaded from disk, its entries in the edge table must be adjusted to point to their respective vertices. Transformations will initially be done using full 4x4 matrix operations. Some operations may be speeded up by bypassing the matrices. 3) Using Intuition A program running under intuition can be divided into two parts: the initial initialization phase and the main loop execution phase. In the initialization phase, one must: 1) open all dynamic runtime libraries. 2) open up any screens and windows. 3) initialize the menu and gadget structures. To open up a runtime library, one issues a call of the form = (ptr_type *)OpenLibrary(".library",0L), which loads the library from disk (if it is not already in memory) and returns a pointer to its start. To open up a screen or a window, one initializes a NewScreen or NewWindow structure and passes it to the OS through the OpenScreen or OpenWindow function, which returns a pointer to a Screen or Window structure. The NewWindow structure holds information about the size of the window, what default gadgets are attached to it, and what types of messages it is allowed to generate. Initializing the menu and gadget structures is extremely difficult, since they generally consist of multidimensional linked lists with many components. For instance, the menu is represented as a linked list of menu headers, each of which is a linked list of menu items. The routines used in this program initialize some of the structures at compile time, such as the menu headers, but initialize the more repetitive structures (such as the menu items) in a loop, using structure assignment from a generic structure and filling in any special fields seperately. The main body of an intuition program is a loop. At the top of the loop one gets any new messages from the operating system using the GetMsg or WaitPort function. GetMsg is a non-blocking call, while WaitPort suspends the task until a message is available, and is thus more preferable in a multi- tasking environment. Following this function is a switch statement which decides a course of action based upon the received message. The control then proceeds back to the top of the loop to wait for another message. In pseudo-code, this looks like: for (;;) { message = GetMsg(Window->UserPort); class = message->Class; switch(class) { case A: { do some stuff for case A } case B: { do some stuff for case B } } } 4) General Program Flow After setting up the windows and gadgets and such, the program enters its main switch loop. Within this loop, the user can enter any command at any time and in any sequence; in this sense the use of the system is completely modeless. For example, one may add and delete vertices, rotate or otherwise transform the object, or do any of a number of operations even if one has only placed half of an edge line. This greatly simplifies using the program, although it is important in writing the program to watch out for special cases. For instance, what happens if one has placed the first half of an edge, and then deletes the vertex to which that edge is attached? In the program, many of these problems are solved by making the marker a vertex which occupies its own position in the vertex array. Thus, a half formed edge is just a regular edge which has the marker as one of its endpoints. The modules which handle editing and those that handle the transformations and display are completely seperate, and need not know about each other. The editing routines make additions to and deletions from the vertex and edge tables. The transform routines multiply the vertex table by the current transform matrix. Finally, the display routines use a perspective matrix to transform the vertex table to x,y coordinates. This final step may be done by using the edge table as an index into the vertex table, and transforming each vertex 'on the fly'. A more efficient method would be do all perspective transforms on the vertex table at once, copying the results to a seperate matrix. The display routine would then use the edge table as an index into this matrix. Typically, each subroutine called by the switch statement will perform