For this assignment, we implemented the Hierarchical Modeling System for our graphics program. This involved defining a new module structure which holds other graphics objects in a linked list, then implementing a module_draw() function which iterates through the list and draws each object onto a given image.
Description of the Task
We implemented the Hierarchical Modeling System for our graphics program. The main idea of the Hierarchical Modeling System is to centralize all the pieces of a graphic into one structure, a module structure. The module object is a set of data that describes how to draw a certain graphic. The advantage of modules is that a graphic can be drawn many times without having to recode similar data, reducing coding time and the chance of making an error.
How The Task Was Solved
The first part of the task was to define the new Module object. The module works by storing graphics objects in a linked list, then iterating through the linked list drawing each object as it goes. A graphics object can be anything that is drawn onto a canvas, such as a point or a polygon, or anything that affects how points or polygons are drawn, such as transformation matrices or new colors.
In order to create a linked list of all these different object types, we had to define a new structure, which we named element. This element holds three fields:
- ObjectType type: this tells what type of object this particular element is. Since elements can represent many types of objects (lines, polygons, etc.), it is important to keep track of this information.
- Object obj: this field holds the data of the object associated with this element. In other words, if this element is a line, the obj field is where it stores all the data associated with the line. The object structure is a union of all the possible objects that an element can be, which means it allocates enough data for the largest possible object.
- Void next: this field points to the next element in the linked list.
The functions for adding elements to a module work on a switch, which uses different algorithms to add elements depending on the elements object type. When adding a new element, the data is copied from the source object, so that any changes made to the element will not affect the original object. That way, if an object is used several times in a module, it is always going to be the same initial object, and will not be affected by previous transformations.
The most important function for the module is the draw function. This function iterates through the linked list of elements and draws each one that can be drawn. Some elements can't be drawn, such as various transformation matrices. If the element is a transformation matrix, it updates the LTM, a field of the module that tells it how to draw each element.
Each element that needs to be drawn is first updated by pre-multiplying it be three matrices: the local transformation matrix, the global transformation matrix, and the view transformation matrix. The view transformation matrix and global transformation matrix are passed into the draw function, and the local transformation matrix is a local variable that changes depending on how the module is transformed. These three matrices multiply together to ensure the correct special coordinates and orientation of the element being drawn.
Summary of What We Learned
It was interesting to learn how to use the "Object" union to store data for many types of structures. It was also cool to be able to easily make multiple instances of a graphics object without having to code up each one individually. We also figured out a way to make circles 'operable' within the modules based on the previous code from Professor Maxwell - simply creating the unitcircle polygon and transforming it to get ellipse or circle worked great.
The most classic computer game EVAH remade for our graphics system. Ecku-ecku-ecku! It's eating dots!
(Greg came up with the idea, Bogo animated and took care of making dots edible)