Ci-dessous, les différences entre deux révisions de la page.
Prochaine révision | Révision précédente | ||
back2root:archives:denthor:part-08 [2021/09/02 11:25] – créée frater | back2root:archives:denthor:part-08 [2024/08/27 09:04] (Version actuelle) – [Drawing a 3D point to screen] frater | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | ===== PART 8 ===== | + | ===== PART 08 : Optimization |
Hello everybody! Christmas is over, the last of the chocolates have been eaten, so it's time to get on with this, the eighth part of the ASPHYXIA Demo Trainer Series. This particular part is primarily about 3-D, but also includes a bit on optimisation. | Hello everybody! Christmas is over, the last of the chocolates have been eaten, so it's time to get on with this, the eighth part of the ASPHYXIA Demo Trainer Series. This particular part is primarily about 3-D, but also includes a bit on optimisation. | ||
Ligne 24: | Ligne 24: | ||
==== Optimisation ==== | ==== Optimisation ==== | ||
- | Before I begin with the note on 3-D, I would like to stress that many of these routines, and probably most of your own, could be sped up quite a bit with a little optimisation. One must realise, however, that you must | + | Before I begin with the note on 3-D, I would like to stress that many of these routines, and probably most of your own, could be sped up quite a bit with a little optimisation. |
- | take a look at WHAT to optimise ... converting a routine that is only called once at startup into a tightly coded assembler routine may show off your merits as a coder, but does absolutely nothing to speed up your program. Something that is called often per frame is something that needs to be as fast as possible. For some, a much used procedure is the PutPixel procedure. Here is the putpixel procedure I gave you last week: | + | |
+ | One must realise, however, that you must take a look at WHAT to optimise ... converting a routine that is only called once at startup into a tightly coded assembler routine may show off your merits as a coder, but does absolutely nothing to speed up your program. | ||
+ | |||
+ | Something that is called often per frame is something that needs to be as fast as possible. For some, a much used procedure is the PutPixel procedure. Here is the putpixel procedure I gave you last week: | ||
<code pascal> | <code pascal> | ||
Ligne 62: | Ligne 65: | ||
Total = 153 clock ticks | Total = 153 clock ticks | ||
| | ||
- | <WRAP center round important | + | <WRAP center round important> |
Don't take my clock ticks as gospel, I probably got one or two wrong. | Don't take my clock ticks as gospel, I probably got one or two wrong. | ||
</ | </ | ||
- | Right, now for some optimising. Firstly, if you have 286 instructions turned on, you may replace the 6 shl,1 with shl,6. Secondly, the Pascal compiler automatically pushes and pops ES, so those two lines may be removed. DS:[SI] is not altered in this procedure, so we may remove those too. Also, instead of moving COL into ah, we move it into AL and call stosb (es: | + | Right, now for some optimising. Firstly, if you have 286 instructions turned on, you may replace the 6 shl,1 with shl, |
+ | |||
+ | Secondly, the Pascal compiler automatically pushes and pops ES, so those two lines may be removed. DS:[SI] is not altered in this procedure, so we may remove those too. Also, instead of moving COL into ah, we move it into AL and call stosb (es: | ||
<code pascal> | <code pascal> | ||
Ligne 92: | Ligne 97: | ||
Total = 95 clock ticks | Total = 95 clock ticks | ||
- | Now, let us move the value of BX directly into DI, thereby removing a costly push and pop. The MOV and the XOR of DX can be replaced by it's equivalent, SHL DX,8 | + | Now, let us move the value of BX directly into DI, thereby removing a costly push and pop. The MOV and the XOR of DX can be replaced by it's equivalent, |
<code pascal> | <code pascal> | ||
Ligne 113: | Ligne 118: | ||
Total = 71 clock ticks | Total = 71 clock ticks | ||
- | As you can see, we have brought the clock ticks down from 153 ticks to 71 ticks ... quite an improvement. (The current ASPHYXIA putpixel takes 48 clock ticks) . As you can see, by going through your routines a few times, you can spot and remove unnecessary instructions, | + | As you can see, we have brought the clock ticks down from 153 ticks to 71 ticks ... quite an improvement. (The current ASPHYXIA putpixel takes 48 clock ticks). |
+ | |||
+ | As you can see, by going through your routines a few times, you can spot and remove unnecessary instructions, | ||
==== Defining a 3-D object ==== | ==== Defining a 3-D object ==== | ||
Ligne 139: | Ligne 146: | ||
==== Rotating a point with matrixes ==== | ==== Rotating a point with matrixes ==== | ||
- | <WRAP center round note 60%> | + | <WRAP center round tip> |
I thought that more then one matix are matrisese (sp), but my spellchecker insists it is matrixes, so I let it have it's way ;-) | I thought that more then one matix are matrisese (sp), but my spellchecker insists it is matrixes, so I let it have it's way ;-) | ||
</ | </ | ||
Ligne 215: | Ligne 222: | ||
Think about it. The larger the number you divide by, the closer to zero, or the horizon, is the result! This means, the bigger the Z, the further away is the object! Here it is in equation form : | Think about it. The larger the number you divide by, the closer to zero, or the horizon, is the result! This means, the bigger the Z, the further away is the object! Here it is in equation form : | ||
- | code pascal> | + | <code pascal> |
nx := 256*x div (z-Zoff)+Xoff | nx := 256*x div (z-Zoff)+Xoff | ||
ny := 256*y div (z-Zoff)+Yoff | ny := 256*y div (z-Zoff)+Yoff | ||
</ | </ | ||
- | <WRAP center round info 60%> | + | <WRAP center round info> |
Zoff is how far away the entire object is, Xoff is the objects X value, and Yoff is the objects Y value. In the sample program, Xoff start off at 160 and Yoff starts off at 100, so that the object is in the middle of the screen. | Zoff is how far away the entire object is, Xoff is the objects X value, and Yoff is the objects Y value. In the sample program, Xoff start off at 160 and Yoff starts off at 100, so that the object is in the middle of the screen. | ||
</ | </ | ||
Ligne 267: | Ligne 274: | ||
File = Available in file base | File = Available in file base | ||
Past = Previous Parts available | Past = Previous Parts available | ||
+ | |||
+ | ==== Code Source ==== | ||
+ | |||
+ | === PASCAL === | ||
+ | |||
+ | <code pascal> | ||
+ | (*****************************************************************************) | ||
+ | (* *) | ||
+ | (* TUT8.PAS - VGA Trainer Program 8 (in Pascal) | ||
+ | (* *) | ||
+ | (* "The VGA Trainer Program" | ||
+ | (* was limited to Pascal only in its first run. All I have done is taken *) | ||
+ | (* his original release, translated it to C++, and touched up a few things. | ||
+ | (* I take absolutely no credit for the concepts presented in this code, and *) | ||
+ | (* am NOT the person to ask for help if you are having trouble. | ||
+ | (* *) | ||
+ | (* Program Notes : This program presents the basis of 3D. *) | ||
+ | (* *) | ||
+ | (* Author | ||
+ | (* *) | ||
+ | (*****************************************************************************) | ||
+ | |||
+ | {$X+} | ||
+ | USES Crt; | ||
+ | |||
+ | CONST VGA = $A000; | ||
+ | MaxLines = 12; | ||
+ | Obj : Array [1..MaxLines, | ||
+ | ( | ||
+ | ((-10, | ||
+ | ((-10, | ||
+ | ((-10, | ||
+ | ((-10, | ||
+ | ((-10, | ||
+ | ((10, | ||
+ | ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } | ||
+ | { (X2,Y2,Z2) ... for the two ends of a line } | ||
+ | |||
+ | |||
+ | Type Point = Record | ||
+ | | ||
+ | END; | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | VAR Lines : Array [1..MaxLines, | ||
+ | Translated : Array [1..MaxLines, | ||
+ | Xoff, | ||
+ | lookup : Array [0..360, | ||
+ | Virscr : VirtPtr; | ||
+ | Vaddr : word; { The segment of our virtual screen} | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure SetMCGA; | ||
+ | BEGIN | ||
+ | asm | ||
+ | | ||
+ | | ||
+ | end; | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure SetText; | ||
+ | BEGIN | ||
+ | asm | ||
+ | | ||
+ | | ||
+ | end; | ||
+ | END; | ||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure Cls (Where: | ||
+ | { This clears the screen to the specified color } | ||
+ | BEGIN | ||
+ | asm | ||
+ | push es | ||
+ | mov cx, 32000; | ||
+ | mov | ||
+ | xor di,di | ||
+ | mov | ||
+ | mov ah,al | ||
+ | rep stosw | ||
+ | pop es | ||
+ | End; | ||
+ | END; | ||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure SetUpVirtual; | ||
+ | { This sets up the memory needed for the virtual screen } | ||
+ | BEGIN | ||
+ | GetMem (VirScr, | ||
+ | vaddr := seg (virscr^); | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure ShutDown; | ||
+ | { This frees the memory used by the virtual screen } | ||
+ | BEGIN | ||
+ | FreeMem (VirScr, | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | procedure flip(source, | ||
+ | { This copies the entire screen at " | ||
+ | begin | ||
+ | asm | ||
+ | push ds | ||
+ | mov ax, [Dest] | ||
+ | mov es, ax | ||
+ | mov ax, [Source] | ||
+ | mov ds, ax | ||
+ | xor si, si | ||
+ | xor di, di | ||
+ | mov cx, 32000 | ||
+ | rep movsw | ||
+ | pop ds | ||
+ | end; | ||
+ | end; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure Pal(Col, | ||
+ | { This sets the Red, Green and Blue values of a certain color } | ||
+ | Begin | ||
+ | asm | ||
+ | mov dx,3c8h | ||
+ | mov al,[col] | ||
+ | out dx,al | ||
+ | inc dx | ||
+ | mov al,[r] | ||
+ | out dx,al | ||
+ | mov al,[g] | ||
+ | out dx,al | ||
+ | mov al,[b] | ||
+ | out dx,al | ||
+ | end; | ||
+ | End; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Function rad (theta : real) : real; | ||
+ | { This calculates the degrees of an angle } | ||
+ | BEGIN | ||
+ | rad := theta * pi / 180 | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure SetUpPoints; | ||
+ | { This sets the basic offsets of the object, creates the lookup table and | ||
+ | moves the object from a constant to a variable } | ||
+ | VAR loop1: | ||
+ | BEGIN | ||
+ | Xoff:=160; | ||
+ | Yoff:=100; | ||
+ | Zoff:=-256; | ||
+ | For loop1:=0 to 360 do BEGIN | ||
+ | lookup [loop1, | ||
+ | lookup [loop1, | ||
+ | END; | ||
+ | For loop1:=1 to MaxLines do BEGIN | ||
+ | Lines [loop1, | ||
+ | Lines [loop1, | ||
+ | Lines [loop1, | ||
+ | Lines [loop1, | ||
+ | Lines [loop1, | ||
+ | Lines [loop1, | ||
+ | END; | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure Putpixel (X,Y : Integer; Col : Byte; where: | ||
+ | { This puts a pixel on the screen by writing directly to memory. } | ||
+ | BEGIN | ||
+ | Asm | ||
+ | mov | ||
+ | mov es,ax | ||
+ | mov | ||
+ | mov | ||
+ | mov di,bx | ||
+ | mov bx, dx {; bx = dx} | ||
+ | shl dx, 8 | ||
+ | shl bx, 6 | ||
+ | add dx, bx {; dx = dx + bx (ie y*320)} | ||
+ | add di, dx {; finalise location} | ||
+ | mov al, [Col] | ||
+ | stosb | ||
+ | End; | ||
+ | END; | ||
+ | |||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure Line(a, | ||
+ | { This draws a solid line from a,b to c,d in colour col } | ||
+ | function sgn(a: | ||
+ | begin | ||
+ | if a>0 then sgn:=+1; | ||
+ | if a<0 then sgn:=-1; | ||
+ | if a=0 then sgn:=0; | ||
+ | end; | ||
+ | var i, | ||
+ | begin | ||
+ | u:= c - a; | ||
+ | v:= d - b; | ||
+ | d1x:= SGN(u); | ||
+ | d1y:= SGN(v); | ||
+ | d2x:= SGN(u); | ||
+ | d2y:= 0; | ||
+ | m:= ABS(u); | ||
+ | n := ABS(v); | ||
+ | IF NOT (M>N) then | ||
+ | BEGIN | ||
+ | d2x := 0 ; | ||
+ | d2y := SGN(v); | ||
+ | m := ABS(v); | ||
+ | n := ABS(u); | ||
+ | END; | ||
+ | s := m shr 1; | ||
+ | FOR i := 0 TO m DO | ||
+ | BEGIN | ||
+ | putpixel(a, | ||
+ | s := s + n; | ||
+ | IF not (s<m) THEN | ||
+ | BEGIN | ||
+ | s := s - m; | ||
+ | a:= a + d1x; | ||
+ | b := b + d1y; | ||
+ | END | ||
+ | ELSE | ||
+ | BEGIN | ||
+ | a := a + d2x; | ||
+ | b := b + d2y; | ||
+ | END; | ||
+ | end; | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure DrawLogo; | ||
+ | { This draws ' | ||
+ | CONST ball : Array [1..5,1..5] of byte = | ||
+ | | ||
+ | (1, | ||
+ | (1, | ||
+ | (1, | ||
+ | (0, | ||
+ | |||
+ | VAR Logo : Array [1..5] of String; | ||
+ | loop1, | ||
+ | BEGIN | ||
+ | pal (13, | ||
+ | pal (1,0,0,40); | ||
+ | pal (2,0,0,45); | ||
+ | pal (3,0,0,50); | ||
+ | pal (4,0,0,60); | ||
+ | Logo[1]: | ||
+ | Logo[2]: | ||
+ | Logo[3]: | ||
+ | Logo[4]: | ||
+ | Logo[5]: | ||
+ | For loop1:=1 to 5 do | ||
+ | For loop2:=1 to 31 do | ||
+ | if logo[loop1][loop2]=' | ||
+ | For loop3:=1 to 5 do | ||
+ | For loop4:=1 to 5 do | ||
+ | putpixel (loop2*10+loop3, | ||
+ | END; | ||
+ | |||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure RotatePoints (X, | ||
+ | { This rotates object lines by X,Y and Z; then places the result in | ||
+ | TRANSLATED } | ||
+ | VAR loop1: | ||
+ | temp:point; | ||
+ | BEGIN | ||
+ | For loop1:=1 to maxlines do BEGIN | ||
+ | temp.x: | ||
+ | temp.y: | ||
+ | temp.z: | ||
+ | |||
+ | translated[loop1, | ||
+ | |||
+ | If y>0 then BEGIN | ||
+ | temp.x: | ||
+ | temp.y: | ||
+ | temp.z: | ||
+ | translated[loop1, | ||
+ | END; | ||
+ | |||
+ | If z>0 then BEGIN | ||
+ | temp.x: | ||
+ | temp.y: | ||
+ | temp.z: | ||
+ | translated[loop1, | ||
+ | END; | ||
+ | |||
+ | temp.x: | ||
+ | temp.y:=cos (rad(X))*lines[loop1, | ||
+ | temp.z:=sin (rad(X))*lines[loop1, | ||
+ | |||
+ | translated[loop1, | ||
+ | |||
+ | If y>0 then BEGIN | ||
+ | temp.x:=cos (rad(Y))*translated[loop1, | ||
+ | temp.y:=sin (rad(Y))*translated[loop1, | ||
+ | temp.z: | ||
+ | translated[loop1, | ||
+ | END; | ||
+ | |||
+ | If z>0 then BEGIN | ||
+ | temp.x:=cos (rad(Z))*translated[loop1, | ||
+ | temp.y: | ||
+ | temp.z: | ||
+ | translated[loop1, | ||
+ | END; | ||
+ | END; | ||
+ | END; | ||
+ | |||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure DrawPoints; | ||
+ | { This draws the translated object to the virtual screen } | ||
+ | VAR loop1: | ||
+ | nx, | ||
+ | temp: | ||
+ | BEGIN | ||
+ | For loop1:=1 to MaxLines do BEGIN | ||
+ | If (translated[loop1, | ||
+ | temp:=round (translated[loop1, | ||
+ | nx :=round (256*translated[loop1, | ||
+ | ny :=round (256*translated[loop1, | ||
+ | temp:=round (translated[loop1, | ||
+ | nx2:=round (256*translated[loop1, | ||
+ | ny2:=round (256*translated[loop1, | ||
+ | If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and | ||
+ | | ||
+ | line (nx, | ||
+ | END; | ||
+ | END; | ||
+ | END; | ||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure ClearPoints; | ||
+ | { This clears the translated object from the virtual screen ... believe it | ||
+ | or not, this is faster then a straight "cls (vaddr, | ||
+ | VAR loop1: | ||
+ | nx, | ||
+ | temp: | ||
+ | BEGIN | ||
+ | For loop1:=1 to MaxLines do BEGIN | ||
+ | If (translated[loop1, | ||
+ | temp:=round (translated[loop1, | ||
+ | nx :=round (256*translated[loop1, | ||
+ | ny :=round (256*translated[loop1, | ||
+ | temp:=round (translated[loop1, | ||
+ | nx2:=round (256*translated[loop1, | ||
+ | ny2:=round (256*translated[loop1, | ||
+ | If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and | ||
+ | | ||
+ | line (nx, | ||
+ | END; | ||
+ | END; | ||
+ | END; | ||
+ | |||
+ | |||
+ | {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} | ||
+ | Procedure MoveAround; | ||
+ | { This is the main display procedure. Firstly it brings the object towards | ||
+ | the viewer by increasing the Zoff, then passes control to the user } | ||
+ | VAR deg, | ||
+ | ch:char; | ||
+ | BEGIN | ||
+ | deg:=0; | ||
+ | ch:=#0; | ||
+ | Cls (vaddr,0); | ||
+ | DrawLogo; | ||
+ | For loop1:=-256 to -40 do BEGIN | ||
+ | zoff: | ||
+ | RotatePoints (deg, | ||
+ | DrawPoints; | ||
+ | flip (vaddr, | ||
+ | ClearPoints; | ||
+ | deg: | ||
+ | END; | ||
+ | |||
+ | Repeat | ||
+ | if keypressed then BEGIN | ||
+ | ch:=upcase (Readkey); | ||
+ | Case ch of ' | ||
+ | ' | ||
+ | ',' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | END; | ||
+ | END; | ||
+ | DrawPoints; | ||
+ | flip (vaddr, | ||
+ | ClearPoints; | ||
+ | RotatePoints (deg, | ||
+ | deg: | ||
+ | Until ch=#27; | ||
+ | END; | ||
+ | |||
+ | |||
+ | BEGIN | ||
+ | SetUpVirtual; | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln ('When it gets close, you get control. " | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln ('it should be easy enough to put in yourself ... if you have any'); | ||
+ | Writeln (' | ||
+ | Writeln; | ||
+ | Writeln ('Read the main text file for ideas on improving this code ... and'); | ||
+ | Writeln (' | ||
+ | writeln; | ||
+ | writeln; | ||
+ | Write (' | ||
+ | Readkey; | ||
+ | SetMCGA; | ||
+ | SetUpPoints; | ||
+ | MoveAround; | ||
+ | SetText; | ||
+ | ShutDown; | ||
+ | Writeln ('All done. This concludes the eigth sample program in the ASPHYXIA' | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln ('For discussion purposes, I am also the moderator of the Programming' | ||
+ | Writeln (' | ||
+ | Writeln ('The numbers are available in the main text. You may also write to me at:'); | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln (' | ||
+ | Writeln ('I hope to hear from you soon!' | ||
+ | Writeln; Writeln; | ||
+ | Write | ||
+ | Readkey; | ||
+ | END. | ||
+ | </ | ||
+ | |||
+ | === C === | ||
+ | |||
+ | <code c file: | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // TUTPROG8.CPP - VGA Trainer Program 8 (in Turbo C++ 3.0) // | ||
+ | // // | ||
+ | // "The VGA Trainer Program" | ||
+ | // was limited to only Pascal in its first run. All I have done is taken // | ||
+ | // his original release, translated it to C++ and touched up a few things. // | ||
+ | // I take absolutely no credit for the concepts presented in this code and // | ||
+ | // am NOT the person to ask for help if you are having trouble. | ||
+ | // // | ||
+ | // Program Notes : This program presents the basics of 3D. Please note // | ||
+ | // that the compiled C++ version of this program runs // | ||
+ | // much faster than the Pascal version. | ||
+ | // a 486DX/33 or higher, you may wish to turn turbo off. // | ||
+ | // // | ||
+ | // If you are compiling this program from within the // | ||
+ | // Turbo C++ environment, | ||
+ | // | ||
+ | // 80 or greater. | ||
+ | // with the code a bit, I suggest raising this to about // | ||
+ | // 100 just to be on the safe side. You don't have to // | ||
+ | // worry about this if you are compiling command line. // | ||
+ | // // | ||
+ | // Just for reference, this is what I use: // | ||
+ | // // | ||
+ | // tcc -mc -a -G -2 -O tut8.cpp | ||
+ | // // | ||
+ | // The way things are set up, there is no need to compile | ||
+ | // or link tut8.cpp and gfx1.cpp seperately. | ||
+ | // // | ||
+ | // The Compact memory model (-mc) seems to provide the // | ||
+ | // best results for this tutorial. | ||
+ | // | ||
+ | // and lots of data. // | ||
+ | // // | ||
+ | // Author | ||
+ | // Translator | ||
+ | // // | ||
+ | // Last Modified : January 14, 1995 // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | // // | ||
+ | // INCLUDE FILES // | ||
+ | // // | ||
+ | |||
+ | #include < | ||
+ | // farcalloc() | ||
+ | #include < | ||
+ | // clrscr(), getch(), kbhit() | ||
+ | #include < | ||
+ | // FP_SEG, geninterrupt() | ||
+ | #include < | ||
+ | // cout | ||
+ | #include < | ||
+ | // sin(), cos() | ||
+ | #include < | ||
+ | // exit() | ||
+ | #include " | ||
+ | |||
+ | // // | ||
+ | // TYPEDEFS // | ||
+ | // // | ||
+ | |||
+ | typedef unsigned char byte; | ||
+ | typedef unsigned int word; | ||
+ | |||
+ | // // | ||
+ | // CONSTANTS // | ||
+ | // // | ||
+ | |||
+ | const MAXLINES = 12; // the number of lines in our cube | ||
+ | |||
+ | // The 3-D coordinates of our object ... stored as {X1,Y1,Z1}, | ||
+ | // {X2,Y2,Z2} ... for the two ends of a line | ||
+ | const int Obj[MAXLINES][2][3] = | ||
+ | { {{-10, | ||
+ | {{-10, | ||
+ | {{-10, 10,-10}, { 10, 10,-10}}, // 2 9 | A | | ||
+ | {{ 10, | ||
+ | {{-10,-10, 10}, { 10,-10, 10}}, // 4 .------6---. | ||
+ | {{-10,-10, 10}, {-10, 10, 10}}, // 5 | | ||
+ | {{-10, 10, 10}, { 10, 10, 10}}, // 6 | | ||
+ | {{ 10,-10, 10}, { 10, 10, 10}}, // 7 | | ||
+ | {{-10,-10, 10}, {-10, | ||
+ | {{-10, 10, 10}, {-10, 10,-10}}, // 9 | / | ||
+ | {{ 10, 10, 10}, { 10, 10,-10}}, // A | 8 | B | ||
+ | {{ 10,-10, 10}, { 10, | ||
+ | }; // | ||
+ | |||
+ | // // | ||
+ | // FUNCTION PROTOTYPES // | ||
+ | // // | ||
+ | |||
+ | // MEMORY ALLOCATION FUNCTIONS | ||
+ | void SetUpVirtual (); | ||
+ | void ShutDown | ||
+ | |||
+ | // LOGO-FUNCTION | ||
+ | void DrawLogo | ||
+ | |||
+ | // 3D POINTS FUNCTIONS | ||
+ | void SetUpPoints | ||
+ | void RotatePoints (int X, int Y, int Z); | ||
+ | void DrawPoints | ||
+ | void ClearPoints | ||
+ | |||
+ | // MID-LEVEL FUNCTION | ||
+ | void MoveAround | ||
+ | |||
+ | // // | ||
+ | // STRUCTURES // | ||
+ | // // | ||
+ | |||
+ | // The data on every point we rotate | ||
+ | struct Point { | ||
+ | float x; | ||
+ | float y; | ||
+ | float z; | ||
+ | }; | ||
+ | |||
+ | // // | ||
+ | // GLOBAL VARIABLE DECLARATIONS // | ||
+ | // // | ||
+ | |||
+ | byte far *Virscr=NULL; | ||
+ | word Vaddr; | ||
+ | float Lookup[360][2]; | ||
+ | int Xoff, Yoff, Zoff; // Used for movement of the objects | ||
+ | Point Lines[MAXLINES][2]; | ||
+ | Point Translated[MAXLINES][2]; | ||
+ | |||
+ | |||
+ | /////////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // MAIN FUNCTION | ||
+ | // // | ||
+ | /////////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void main() { | ||
+ | |||
+ | SetUpVirtual(); | ||
+ | clrscr(); | ||
+ | cout | ||
+ | << " | ||
+ | << "year! ;-) ... Anyway, this tutorial is on 3-D, so this is what is\n" | ||
+ | << "going to happen ... a wireframe square will come towards you.\n" | ||
+ | << "When it gets close, you get control. "" | ||
+ | << " | ||
+ | << " | ||
+ | << "it should be easy enough to put in yourself ... if you have any\n" | ||
+ | << " | ||
+ | cout | ||
+ | << "Read the main text file for ideas on improving this code ... and\n" | ||
+ | << " | ||
+ | cout << "Hit any key to contine ...\n"; | ||
+ | getch(); | ||
+ | |||
+ | SetMCGA(); | ||
+ | |||
+ | SetUpPoints(); | ||
+ | MoveAround(); | ||
+ | |||
+ | ShutDown(); | ||
+ | SetText(); | ||
+ | |||
+ | cout | ||
+ | << "All done. This concludes the eigth sample program in the ASPHYXIA\n" | ||
+ | << " | ||
+ | << " | ||
+ | << " | ||
+ | << "For discussion purposes, I am also the moderator of the Programming\n" | ||
+ | << " | ||
+ | << "The numbers are available in the main text. You may also write to me at:\n" | ||
+ | << " | ||
+ | << " | ||
+ | << " | ||
+ | << " | ||
+ | << "I hope to hear from you soon!\n\n\n"; | ||
+ | cout << "Hit any key to exit ...\n"; | ||
+ | getch(); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // SetUpVirtual() - This sets up the memory needed for the virtual screen. // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void SetUpVirtual() { | ||
+ | |||
+ | Virscr = (byte far *) farcalloc(64000, | ||
+ | |||
+ | // always check to see if enough memory was allocated | ||
+ | if (Virscr == NULL) { | ||
+ | SetText(); | ||
+ | cout << " | ||
+ | exit(1); | ||
+ | } | ||
+ | |||
+ | Vaddr = FP_SEG(Virscr); | ||
+ | |||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // ShutDown() - This frees the memory used by the virtual screen. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void ShutDown() { | ||
+ | free(Virscr); | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // DrawLogo() - This draws ' | ||
+ | // balls. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void DrawLogo() { | ||
+ | |||
+ | const byte ball[5][5] = { 0,1,1,1,0, | ||
+ | 1,4,3,2,1, | ||
+ | 1,3,3,2,1, | ||
+ | 1,2,2,2,1, | ||
+ | 0,1,1,1,0 | ||
+ | }; | ||
+ | |||
+ | const char *Logo[5] = { {"OOO OOO OOO O O O O O OOO OOO"}, | ||
+ | {" | ||
+ | {"OOO O O O O O O O O O O OOO O O"}, | ||
+ | {" | ||
+ | {"OOO O O OOO O O O O O O O O O"} | ||
+ | }; | ||
+ | |||
+ | int loop1, loop2, loop3, loop4; | ||
+ | |||
+ | Pal(13, 0,63, 0); // set the color for the cube lines | ||
+ | Pal( 1, 0, 0,40); // set the colors for the dots | ||
+ | Pal( 2, 0, 0,45); | ||
+ | Pal( 3, 0, 0,50); | ||
+ | Pal( 4, 0, 0,60); | ||
+ | |||
+ | for (loop1=0; loop1<5; loop1++) | ||
+ | for (loop2=0; loop2< | ||
+ | if (Logo[loop1][loop2] == ' | ||
+ | for (loop3=0; loop3<5; loop3++) | ||
+ | for (loop4=0; loop4<5; loop4++) | ||
+ | Putpixel ((loop2+1)*10+loop3, | ||
+ | ball[loop3][loop4], | ||
+ | |||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // SetUpPoints() - This sets the basic offsets of the object, creates the // | ||
+ | // | ||
+ | // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void SetUpPoints() { | ||
+ | |||
+ | int loop1; | ||
+ | |||
+ | // set the starting offsets of the cube | ||
+ | Xoff = 160; | ||
+ | Yoff = 100; | ||
+ | Zoff = -256; | ||
+ | |||
+ | // generate the sin() and cos() tables | ||
+ | for (loop1=0; loop1< | ||
+ | Lookup [loop1][0] = sin(rad(loop1)); | ||
+ | Lookup [loop1][1] = cos(rad(loop1)); | ||
+ | } | ||
+ | |||
+ | // move the Obj constant array into the Lines array | ||
+ | for (loop1=0; loop1< | ||
+ | Lines[loop1][0].x = Obj[loop1][0][0]; | ||
+ | Lines[loop1][0].y = Obj[loop1][0][1]; | ||
+ | Lines[loop1][0].z = Obj[loop1][0][2]; | ||
+ | Lines[loop1][1].x = Obj[loop1][1][0]; | ||
+ | Lines[loop1][1].y = Obj[loop1][1][1]; | ||
+ | Lines[loop1][1].z = Obj[loop1][1][2]; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // RotatePoints() - This rotates object lines by X, Y, and Z. Then it // | ||
+ | // places the result in Translated. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void RotatePoints (int X,int Y,int Z) { | ||
+ | |||
+ | int loop1; | ||
+ | Point temp; | ||
+ | |||
+ | // for each line... | ||
+ | for (loop1=0; loop1< | ||
+ | |||
+ | // start point of line | ||
+ | |||
+ | temp.x = Lines[loop1][0].x; | ||
+ | temp.y = Lookup[X][1]*Lines[loop1][0].y - Lookup[X][0]*Lines[loop1][0].z; | ||
+ | temp.z = Lookup[X][0]*Lines[loop1][0].y + Lookup[X][1]*Lines[loop1][0].z; | ||
+ | Translated[loop1][0] = temp; | ||
+ | |||
+ | if (Y > 0) { | ||
+ | temp.x = Lookup[Y][1]*Translated[loop1][0].x - Lookup[Y][0]*Translated[loop1][0].y; | ||
+ | temp.y = Lookup[Y][0]*Translated[loop1][0].x + Lookup[Y][1]*Translated[loop1][0].y; | ||
+ | temp.z = Translated[loop1][0].z; | ||
+ | Translated[loop1][0] =temp; | ||
+ | } | ||
+ | |||
+ | if (Z > 0) { | ||
+ | temp.x = Lookup[Z][1]*Translated[loop1][0].x + Lookup[Z][0]*Translated[loop1][0].z; | ||
+ | temp.y = Translated[loop1][0].y; | ||
+ | temp.z = (-Lookup[Z][0])*Translated[loop1][0].x + Lookup[Z][1]*Translated[loop1][0].z; | ||
+ | Translated[loop1][0] = temp; | ||
+ | } | ||
+ | |||
+ | // end point of line | ||
+ | |||
+ | temp.x = Lines[loop1][1].x; | ||
+ | temp.y = cos(rad(X))*Lines[loop1][1].y - sin(rad(X))*Lines[loop1][1].z; | ||
+ | temp.z = sin(rad(X))*Lines[loop1][1].y + cos(rad(X))*Lines[loop1][1].z; | ||
+ | Translated[loop1][1] = temp; | ||
+ | |||
+ | if (Y > 0) { | ||
+ | temp.x = cos(rad(X))*Translated[loop1][1].x - sin(rad(Y))*Translated[loop1][1].y; | ||
+ | temp.y = sin(rad(Y))*Translated[loop1][1].x + cos(rad(Y))*Translated[loop1][1].y; | ||
+ | temp.z = Translated[loop1][1].z; | ||
+ | Translated[loop1][1] = temp; | ||
+ | } | ||
+ | |||
+ | if (Z > 0) { | ||
+ | temp.x = cos(rad(Z))*Translated[loop1][1].x + sin(rad(Z))*Translated[loop1][1].z; | ||
+ | temp.y = Translated[loop1][1].y; | ||
+ | temp.z = (-sin(rad(Z)))*Translated[loop1][1].x + cos(rad(Z))*Translated[loop1][1].z; | ||
+ | Translated[loop1][1] = temp; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // DrawPoints() - This draws the translated object to the virtual screen. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void DrawPoints() { | ||
+ | |||
+ | int loop1, nx, ny, nx2, ny2, temp; | ||
+ | |||
+ | for (loop1=0; loop1< | ||
+ | if ((Translated[loop1][0].z+Zoff< | ||
+ | |||
+ | // start point of line | ||
+ | temp = Translated[loop1][0].z + Zoff; | ||
+ | nx = ((256*Translated[loop1][0].x) / temp) + Xoff; | ||
+ | ny = ((256*Translated[loop1][0].y) / temp) + Yoff; | ||
+ | |||
+ | // end point of line | ||
+ | temp = Translated[loop1][1].z + Zoff; | ||
+ | nx2 = ((256*Translated[loop1][1].x) / temp) + Xoff; | ||
+ | ny2 = ((256*Translated[loop1][1].y) / temp) + Yoff; | ||
+ | |||
+ | // check to make sure the line is within bounds | ||
+ | if ((nx >-1) && (nx <320) && (ny >25) && (ny <200) && | ||
+ | (nx2>-1) && (nx2< | ||
+ | Line(nx, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // ClearPoints() - This clears the translated object from the virtual | ||
+ | // | ||
+ | // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void ClearPoints() { | ||
+ | |||
+ | int loop1, nx, ny, nx2, ny2, temp; | ||
+ | |||
+ | for (loop1=0; loop1< | ||
+ | if ((Translated[loop1][0].z+Zoff< | ||
+ | |||
+ | // start point of line | ||
+ | temp = Translated[loop1][0].z + Zoff; | ||
+ | nx = ((256*Translated[loop1][0].x) / temp) + Xoff; | ||
+ | ny = ((256*Translated[loop1][0].y) / temp) + Yoff; | ||
+ | |||
+ | // end point of line | ||
+ | temp = Translated[loop1][1].z + Zoff; | ||
+ | nx2 = ((256*Translated[loop1][1].x) / temp) + Xoff; | ||
+ | ny2 = ((256*Translated[loop1][1].y) / temp) + Yoff; | ||
+ | |||
+ | // check to make sure the line is within bounds | ||
+ | if ((nx >-1) && (nx <320) && (ny >25) && (ny <200) && | ||
+ | (nx2>-1) && (nx2< | ||
+ | Line(nx, | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // MoveAround() - This is the main display function. | ||
+ | // object towards the viewer by increasing the Zoff, then // | ||
+ | // it passes control to the user. // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void MoveAround() { | ||
+ | |||
+ | // For some reason, the values we defined Xoff, Yoff, and Zoff to be in | ||
+ | // the function SetUpPoints() won't hold until this point. | ||
+ | // the reason, please send it to r3cgm@dax.cc.uakron.edu | ||
+ | Xoff = 160; // redefined | ||
+ | Yoff = 100; // redefined | ||
+ | Zoff = -256; // redefined | ||
+ | |||
+ | int deg=0, loop1; | ||
+ | byte ch=1; // assign a dummy value to ch | ||
+ | |||
+ | Cls(0, | ||
+ | |||
+ | DrawLogo(); | ||
+ | |||
+ | for (loop1=(-256); | ||
+ | Zoff = loop1 * 2; | ||
+ | RotatePoints(deg, | ||
+ | DrawPoints(); | ||
+ | Flip(Vaddr, | ||
+ | ClearPoints(); | ||
+ | deg = (deg + 5) % 360; | ||
+ | } | ||
+ | |||
+ | do { | ||
+ | |||
+ | if (kbhit()) { | ||
+ | ch = getch(); | ||
+ | switch (ch) { | ||
+ | // We are not going to use toupper() because if we did, we'd have | ||
+ | // to include the whole ctype.h file. This might take a little more | ||
+ | // time, but the program will be smaller. | ||
+ | // files, and its getting a bit rediculous. | ||
+ | case ' | ||
+ | case ' | ||
+ | case ',': | ||
+ | case ' | ||
+ | case ' | ||
+ | case ' | ||
+ | } | ||
+ | } | ||
+ | DrawPoints(); | ||
+ | Flip(Vaddr, | ||
+ | ClearPoints(); | ||
+ | RotatePoints(deg, | ||
+ | deg = (deg + 5) % 360; | ||
+ | |||
+ | // if the key pressed above was 0 (i.e. a control character) then | ||
+ | // read the character code | ||
+ | if (ch == 0) ch = getch(); | ||
+ | |||
+ | } while (ch != 27); // if the escape code was 27 (escape key) then exit | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code c file: | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // GFX1.CPP - VGA Trainer Program secondary module containing graphics | ||
+ | // functions. | ||
+ | // programming practices. | ||
+ | // VGA tutorial series. | ||
+ | // module with a different source file, some modifications may // | ||
+ | // be necessary. | ||
+ | // // | ||
+ | // Author | ||
+ | // Translator | ||
+ | // // | ||
+ | // Last Modified : January 13, 1995 // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | // // | ||
+ | // INCLUDE FILES // | ||
+ | // // | ||
+ | |||
+ | #include < | ||
+ | // geninterrupt() | ||
+ | #include < | ||
+ | // abs() | ||
+ | |||
+ | // // | ||
+ | // DEFINES // | ||
+ | // // | ||
+ | |||
+ | #if !defined(PI) | ||
+ | #define PI 3.1415927 | ||
+ | #endif | ||
+ | |||
+ | #if !defined(VGA) | ||
+ | #define VGA 0xA000 | ||
+ | #endif | ||
+ | |||
+ | // // | ||
+ | // TYPEDEFS // | ||
+ | // // | ||
+ | |||
+ | typedef unsigned char byte; | ||
+ | typedef unsigned int word; | ||
+ | |||
+ | // // | ||
+ | // FUNCTION PROTOTYPES // | ||
+ | // // | ||
+ | |||
+ | // MODE SETTING FUNCTIONS | ||
+ | void SetMCGA | ||
+ | void SetText | ||
+ | |||
+ | // PALLETTE FUNCTIONS | ||
+ | void Pal (byte Col, byte R, byte G, byte B); | ||
+ | void GetPal | ||
+ | |||
+ | // MATH-LIKE FUNCTIONS | ||
+ | float rad | ||
+ | int | ||
+ | |||
+ | // DRAWING FUNCTIONS | ||
+ | void Putpixel | ||
+ | void Line (int a, int b, int c, int d, int col, word Where); | ||
+ | |||
+ | // VIDEO MEMORY FUNCTIONS | ||
+ | void Cls (byte Col, word Where); | ||
+ | void Flip (word source, word dest); | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // SetMCGA() - This function gets you into 320x200x256 mode. // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void SetMCGA() { | ||
+ | _AX = 0x0013; | ||
+ | geninterrupt (0x10); | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // SetText() - This function gets you into text mode. // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void SetText() { | ||
+ | _AX = 0x0003; | ||
+ | geninterrupt (0x10); | ||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // Pal() - This sets the Red, Green, and Blue values of a certain color. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void Pal (byte Col, byte R, byte G, byte B) { | ||
+ | asm { | ||
+ | mov dx, 0x3C8 // load DX with 3C8 (write pallette function) | ||
+ | mov al, [Col] // move color to AL | ||
+ | out dx, al // write DX to the VGA (tell VGA that we want to | ||
+ | // | ||
+ | inc | ||
+ | mov al, [R] // move Red to AL | ||
+ | out dx, al // write DX to VGA (tell VGA that we want to use | ||
+ | // | ||
+ | mov al, [G] // move Green to AL | ||
+ | out dx, al // write DX to VGA | ||
+ | mov al, [B] // move Blue to AL | ||
+ | out dx, al // write DX to VGA | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // GetPal() - This reads the values of the Red, Green, and Blue values of // | ||
+ | // a certain color. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void GetPal (byte Col, byte &R, byte &G, byte &B) { | ||
+ | |||
+ | byte rr,gg,bb; | ||
+ | |||
+ | asm { | ||
+ | mov dx, 0x03C7 | ||
+ | mov al, [Col] // move color to AL | ||
+ | out dx, al // write DX to the VGA (tell VGA that we want to | ||
+ | // | ||
+ | add dx, 2 // load DX with 3C9 (read RGB colors) | ||
+ | in al, dx // read Red to AL | ||
+ | mov | ||
+ | in al, dx // read Green to AL | ||
+ | mov | ||
+ | in al, dx // read Blue to AL | ||
+ | mov | ||
+ | } | ||
+ | |||
+ | R = rr; | ||
+ | G = gg; | ||
+ | B = bb; | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // rad() - This calculates the degrees of an angle. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | float rad(float theta) { | ||
+ | return ((theta * PI)/180); | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // sgn() - This checks the sign of an integer and returns a 1, -1, or 0. // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | int sgn (int a) { | ||
+ | |||
+ | if (a > 0) return +1; | ||
+ | if (a < 0) return -1; | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // Putpixel() - This puts a pixel on the screen by writing directly to // | ||
+ | // memory. | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void Putpixel (word X, word Y, byte Col, word Where) { | ||
+ | asm { | ||
+ | push ds // save DS | ||
+ | push es // save ES | ||
+ | mov ax, [Where] | ||
+ | mov es, ax // set ES to segment of Where | ||
+ | mov bx, [X] // set BX to X | ||
+ | mov dx, [Y] // set DX to Y | ||
+ | push bx // save BX (our X value) | ||
+ | mov bx, dx // now BX and DX are equal to Y | ||
+ | mov dh, dl // copy DL to DH (multiply Y by 256) | ||
+ | xor dl, dl // zero out DL | ||
+ | shl bx, 6 // shift BX left 6 places (multiply Y by 64). | ||
+ | add dx, bx // add BX to DX (Y*64 + Y*256 = Y*320) | ||
+ | pop | ||
+ | add bx, dx // add BX to DX (Y*320 + X). this gives you | ||
+ | // | ||
+ | mov di, bx // move the offset to DI | ||
+ | xor al, al // zero out AL | ||
+ | mov ah, [Col] // move value of Col into AH | ||
+ | mov | ||
+ | pop | ||
+ | pop | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // Line() - This draws a line from a,b to c,d of color col on screne Where // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void Line(int a, int b, int c, int d, int col, word Where) { | ||
+ | |||
+ | int i, | ||
+ | |||
+ | u = c-a; // x2-x1 | ||
+ | v = d-b; // y2-y1 | ||
+ | d1x = sgn(u); | ||
+ | d1y = sgn(v); | ||
+ | d2x = sgn(u); | ||
+ | d2y = 0; | ||
+ | m = abs(u); | ||
+ | n = abs(v); | ||
+ | |||
+ | if (m<=n) { // if the x distance is greater than the y distance | ||
+ | d2x = 0; | ||
+ | d2y = sgn(v); // d2y is the sign of v (x2-x1) (VALUE -1,0,1) | ||
+ | m = abs(v); // m is the distance between y1 and y2 | ||
+ | n = abs(u); // n is the distance between x1 and x2 | ||
+ | } | ||
+ | |||
+ | s = m / 2; // s is the m distance (either x or y) divided by 2 | ||
+ | |||
+ | for (i=0; | ||
+ | // is = to m (y or x distance) | ||
+ | Putpixel(a, | ||
+ | s += n; // add n (dis of x or y) to s (dis of x of y) | ||
+ | if (s >= m) { // if s is >= m (distance between y1 and y2) | ||
+ | s -= m; | ||
+ | a += d1x; | ||
+ | b += d1y; | ||
+ | } | ||
+ | else { | ||
+ | a += d2x; | ||
+ | b += d2y; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // Cls() - This clears the screen at location Where to color Col // | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void Cls(byte Col, word Where) { | ||
+ | asm { | ||
+ | push es // save ES | ||
+ | mov cx, 32000 // this is our loop counter. | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | mov es, [Where] | ||
+ | xor di, di // zero out DI | ||
+ | mov al, [Col] // move color to AL | ||
+ | mov ah, al // move color to AH (Remember, will be moving | ||
+ | // | ||
+ | rep | ||
+ | // | ||
+ | pop | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | // // | ||
+ | // Flip() - This copies the entire screen at " | ||
+ | // // | ||
+ | ///////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | void Flip(word source, word dest) { | ||
+ | asm { | ||
+ | push ds // save DS | ||
+ | mov ax, [dest] | ||
+ | mov es, ax // set ES to point to destination | ||
+ | mov ax, [source] // copy segment of source to AX | ||
+ | mov ds, ax // set DS to point to source | ||
+ | xor si, si // zero out SI | ||
+ | xor di, di // zero out DI | ||
+ | mov cx, 32000 // set our counter to 32000 | ||
+ | rep | ||
+ | // | ||
+ | pop | ||
+ | } | ||
+ | } | ||
+ | </ | ||
<nspages back2root/ | <nspages back2root/ |