Chapter 1 Introduction

Basic Introduction

Computer graphics - the art of creating pictures with a computer.

Computer graphics is applications oriented. Examples include:
(1) Paint programs
(2) Word Processing
(3) Desktop Publishing
(4) Business Graphics
(5) CAD - computer aided design
(6) Flight Simulation
(7) Computer Games

"Pure" Computer Graphics - is the science behind the mathematics, algorithms, software, and hardware.

Everything in computer graphics is constructed from 3 basic "atoms" or 3 basic graphics primitives:
(1) pixel - picture element (a point of light on the display screen).
(2) line - a sequence of closely spaced pixels. A vector device draws a line continuously.
(3) polygon - a plane figure of more than 2 sides.

From these three graphics primitives all of the images seen in computer graphics can be constructed.

Of these three primitives, only the pixel is strongly hardware based. Notice that the book uses SetPix(x,y) where x & y specify a location on the display screen.

Introductory Mathematics Review

Coordinate Systems

(a) Two-dimensional - the point (x,y) is at distances x and y from two perpendicular axes.

Remember that quadrants can be broken up into octants which will be very important when discussing line drawing algorithms and circle generating algorithms.

(b) Three-dimensional - the point (x,y,z) is measured from three mutually perpendicular axes.

Many times we need to calculate the distance between two points in either two or three-dimensions. The formulas are as follows:

Many other coordinate systems are possible such as: polar, cylindrical, spherical, ...

Polar coordinates

2D: point (r,theta) is at distance r from the origin and is the angle from a reference axis to the ray. Note: the angle is counter clockwise (ccw).

Analytical Geometry

A curve in the x,y plane can be represented by a relation: y = f(x). If the curve is a straight line, we are interested in four general equation forms:

(a) Two-point: (y-y1)/(x-x1) = (y2-y1)/(x2-x1) , x1<>x2

(b) Point slope: (y-y1)/(x-x1) = m , where m is the slope

(c) Slope-intercept: y = mx + b , where b is the value of y at x = 0.

(d) General: Ax + By + C = 0 , where A and B are not both 0. Remember for B <> 0, the slope m = -A/B and b = -C/B.

How do each of these formulas work and why would we want to use them?

Also, remember:
(1) Two lines that are parallel have the same slope.
(2) Two lines that are perpendicular have m1 = -1/m2.

Other mathematics from chapter 1 that will be covered later include:
(1) Vectors (addition, subtraction, multiplication by a scalar, magnitude, dot product, cross product)
(2) Matrices (addition, subtraction, multiplication by a scalar, special properties)

Feel free to begin reading up on this information from chapter 1 for later use. (pp.15-18)

Assembly Language Revisited

In order to write a graphics library, we need to know several things:
(1) The specifics of the machine we are working with
(2) Tools for controlling the machine we are working with (Assembly/C)
(3) Specific algorithms that implement the primitives in an efficient way
(4) A method of interfacing Assembly and C

We begin by discussing "A method of interfacing Assembly and C"

There are several reasons for wanting to write routines in assembly language:
(1) To increase speed and efficiency of a particular routine
(2) To perform some function that is machine specific and unavailable in the high level language being used
(3) We might want to use some third party routines
(4) Sometimes debugging C source in assembly is easier

It is important to note that no matter how good a compiler is, it will never produce code as fast and efficient as an excellent assembly language programmer.

In order to interface assembly and C, we must know what the calling conventions are. By calling conventions, we are referring to the method that the implementors of the C compiler choose to pass information to and from functions. Typically information is passed one of two ways: (1) by the use of internal registers (2) through the system stack. In general we find that most C compilers use the system stack to pass arguments to functions and registers to hold the return values. In addition to defining what gets passed and how, we must also be careful to preserve certain registers if we want their values unchanged after the assembly routine is executed. More on this later. Since our graphics library will be written using Turbo C/C++, we will discuss these calling conventions. It is important to note that the calling conventions of Turbo C/C++ are not the same as Turbo Pascal. Although the differences are minor, if the conventions are not exact, incorrect results are sure to follow.

Turbo C/C++ passes arguments to functions on the stack. Arguments are pushed onto the stack from right to left, so as an example if we have the following function call: swap(a,b,c) then c is first pushed on the stack followed by b and then a. How many bytes are occupied on the stack by these three variables? The answer lies in what type of variables a,b, and c are. The following table will be useful when solving this question.

Type (# of bytes)
char (2)
short (2)
signed char (2)
signed short (2)
unsigned char (2)
unsigned short (2)
int (2)
signed int (2)
unsigned int (2)
long (4)
unsigned long (4)
float (4)
double (8)
long double (10)
near pointer (2)
far pointer (4)

Some questions of interest:
(1) Why is a near pointer two bytes?
(2) Why is a far pointer four bytes?
(3) What are the range of values for an int?
(4) What are the range of values for and unsigned long?
(5) What are the range of values for a short?
(6) Why is a char passed as two bytes?
(7) How would a string be passed and why?

When entering an assembly language routine:
(1) The contents of the BP are saved on the stack
(2) Current value of the SP is place into the BP
(3) The registers CS, DS, and SS are many times preserved along with SI and DI if used

As for return values, structures that are 1 or 2 bytes in length are returned in the AX register while structures that are 4 bytes in length are returned in the DX:AX register pair. For a far pointer the offset is returned in the AX and the segment is in the DX.

The easiest way to learn about interfacing C and assembly is to see how Turbo C/C++ generates assembly routines. Consider the following C program test.c:


int add(int a, int b);
int sum;
main(void)
{
sum = add(10,20);
return 0;
}
add(int a, int b)
{
int t;
t = a + b;
return t;
}

Using the command line version of Turbo, we execute the following command: "tcc -S test.c". The -S option generates assembly language source code. The resulting code follows:

ifndef ??version
?debug macro
endm
$comm macro name,dist,size,count
comm dist name:BYTE:count*size
endm
else
$comm macro name,dist,size,count
comm dist name[size]:BYTE:count
endm
endif
?debug S "test1.c"
?debug C E98B83EA1E0774657374312E63
_TEXT segment byte public 'CODE'
_TEXT ends
DGROUP group _DATA,_BSS
assume cs:_TEXT,ds:DGROUP
_DATA segment word public 'DATA'
d@ label byte
d@w label word
_DATA ends
_BSS segment word public 'BSS'
b@ label byte
b@w label word
_BSS ends
_TEXT segment byte public 'CODE'
;
; main(void)
;
assume cs:_TEXT
_main proc near
push bp
mov bp,sp
;
; {
; sum = add(10,20);
;
mov ax,20
push ax
mov ax,10
push ax
call near ptr _add
pop cx
pop cx
mov word ptr DGROUP:_sum,ax
;
; return 0;
;
xor ax,ax
jmp short @1@50
@1@50:
;
; }
;
pop bp
ret
_main endp
;
; add(int a, int b)
;
assume cs:_TEXT
_add proc near
push bp
mov bp,sp
push si
;
; {
; int t;
; t = a + b;
;
mov ax,word ptr [bp+4]
add ax,word ptr [bp+6]
mov si,ax
;
; return t;
;
mov ax,si
jmp short @2@50
@2@50:
;
; }
;
pop si
pop bp
ret
_add endp
_TEXT ends
_BSS segment word public 'BSS'
_sum label word
db 2 dup (?)
?debug C E9
_BSS ends
_DATA segment word public 'DATA'
s@ label byte
_DATA ends
_TEXT segment byte public 'CODE'
_TEXT ends
public _sum
public _main
public _add
end


From here we could take the assembled code in the file "test.asm" and run this through the assembler MASM producing "test.obj". Finally, we could use TLINK (Turbo Linker) to link the object module "test.obj" and the file "c0s.obj" which contains startup and DOS header information. The command line would be: "tlink \tc\lib\c0s test, test.exe,,\tc\lib\cs". The library cs.lib (cs in this case) is Turbo standard small model library.

NOTE: You need to read up on memory models as this will be very important as your graphics library begins to grow.

I would strongly encourage you to duplicate the above example to make sure you follow the details. To make the example more meaningful, you might want to place a printf in the main program which prints out the value returned from the function add. This means that the executable should print out the value 30 if successfully completed.

The problem with the above example is that all of the source code exists in C and is then translated to assembly using tcc. In this day and age most of the code will be written in C with several specific routines written in assembly. Therefore, we have libraries of C routines and libraries of assembly routines, so the problem we face is how do we interface the C libraries with the assembly libraries.

Problem: Assume that we have written the following C program that calls a function mul which simply multiplies two integer values together and returns the result to be printed. The C code is written but the mul routine is not and needs to be written in assembly language. Questions that need to be answered:
(1) What is the best way to proceed in writing the assembly language routine(s)?
(2) How do we hook all of this information together?
(3) What is the best way to test this program?
(4) Pictorially, what does the stack and various stack frames look like during program execution?

/* C source code to multiply 2 times 5 */
#include <stdio.h>
int mul(int a,int b);
main(void)
{
  printf("%d",mul(2,5));
  return 0;
}

As far as answering question (1), we could proceed in one of two ways. Having complete command of the assembly language environment in which we are working, we could simply write the assembly routine from our knowledge base and proceed to step (2) We could let the environment create the shell of the routine(s) we would like to write and then fill in the holes. In essence, for the above example, we could write the following code:

int mul(int a, int b)
{
}

From here, we simply compile this code using the command "tcc -S file.c" and the shell of the assembly routine is created. From here we proceed by filling in the holes.

Think about questions (2), (3), and (4) as they will be answered in class.

This completes the assembly review portion of the class. I would direct your attention to one of the references in the lab called:
Turbo C/C++ the Complete Reference 2nd Edition by Herbert Schildt. There is an abundance of information in this book. Please do not remove it from the lab at any time.


©1995 Douglas J. Ryan
Douglas J. Ryan/ryand@tardis.pacificu.edu