Outils pour utilisateurs

Outils du site


back2root:archives:denthor:part-08

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
Prochaine révisionLes deux révisions suivantes
back2root:archives:denthor:part-08 [2021/09/02 11:28] – [Drawing a 3D point to screen] fraterback2root:archives:denthor:part-08 [2021/09/05 14:04] – [In closing] 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 267: Ligne 267:
 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" is written by Denthor of Asphyxia.  However it  *)
 +(* 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.  -Snowman    *)
 +(*                                                                           *)
 +(* Program Notes : This program presents the basis of 3D.                    *)
 +(*                                                                           *)
 +(* Author        : Grant Smith (Denthor)  - denthor@beastie.cs.und.ac.za     *)
 +(*                                                                           *)
 +(*****************************************************************************)
 +
 +{$X+}
 +USES Crt;
 +
 +CONST VGA = $A000;
 +      MaxLines = 12;
 +      Obj : Array [1..MaxLines,1..2,1..3] of integer =
 +        (
 +        ((-10,-10,-10),(10,-10,-10)),((-10,-10,-10),(-10,10,-10)),
 +        ((-10,10,-10),(10,10,-10)),((10,-10,-10),(10,10,-10)),
 +        ((-10,-10,10),(10,-10,10)),((-10,-10,10),(-10,10,10)),
 +        ((-10,10,10),(10,10,10)),((10,-10,10),(10,10,10)),
 +        ((-10,-10,10),(-10,-10,-10)),((-10,10,10),(-10,10,-10)),
 +        ((10,10,10),(10,10,-10)),((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
 +               x,y,z:real;                { The data on every point we rotate}
 +             END;
 +     Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }
 +     VirtPtr = ^Virtual;                  { Pointer to the virtual screen }
 +
 +
 +VAR Lines : Array [1..MaxLines,1..2] of Point;  { The base object rotated }
 +    Translated : Array [1..MaxLines,1..2] of Point; { The rotated object }
 +    Xoff,Yoff,Zoff:Integer;               { Used for movement of the object }
 +    lookup : Array [0..360,1..2] of real; { Our sin and cos lookup table }
 +    Virscr : VirtPtr;                     { Our first Virtual screen }
 +    Vaddr  : word;                        { The segment of our virtual screen}
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }
 +BEGIN
 +  asm
 +     mov        ax,0013h
 +     int        10h
 +  end;
 +END;
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure SetText;  { This procedure returns you to text mode.  }
 +BEGIN
 +  asm
 +     mov        ax,0003h
 +     int        10h
 +  end;
 +END;
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure Cls (Where:word;Col : Byte);
 +   { This clears the screen to the specified color }
 +BEGIN
 +     asm
 +        push    es
 +        mov     cx, 32000;
 +        mov     es,[where]
 +        xor     di,di
 +        mov     al,[col]
 +        mov     ah,al
 +        rep     stosw
 +        pop     es
 +     End;
 +END;
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure SetUpVirtual;
 +   { This sets up the memory needed for the virtual screen }
 +BEGIN
 +  GetMem (VirScr,64000);
 +  vaddr := seg (virscr^);
 +END;
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure ShutDown;
 +   { This frees the memory used by the virtual screen }
 +BEGIN
 +  FreeMem (VirScr,64000);
 +END;
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +procedure flip(source,dest:Word);
 +  { This copies the entire screen at "source" to destination }
 +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,R,G,B : Byte);
 +  { 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:integer;
 +BEGIN
 +  Xoff:=160;
 +  Yoff:=100;
 +  Zoff:=-256;
 +  For loop1:=0 to 360 do BEGIN
 +    lookup [loop1,1]:=sin (rad (loop1));
 +    lookup [loop1,2]:=cos (rad (loop1));
 +  END;
 +  For loop1:=1 to MaxLines do BEGIN
 +    Lines [loop1,1].x:=Obj [loop1,1,1];
 +    Lines [loop1,1].y:=Obj [loop1,1,2];
 +    Lines [loop1,1].z:=Obj [loop1,1,3];
 +    Lines [loop1,2].x:=Obj [loop1,2,1];
 +    Lines [loop1,2].y:=Obj [loop1,2,2];
 +    Lines [loop1,2].z:=Obj [loop1,2,3];
 +  END;
 +END;
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
 +  { This puts a pixel on the screen by writing directly to memory. }
 +BEGIN
 +  Asm
 +    mov     ax,[where]
 +    mov     es,ax
 +    mov     bx,[X]
 +    mov     dx,[Y]
 +    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,b,c,d:integer;col:byte;where:word);
 +  { This draws a solid line from a,b to c,d in colour col }
 +  function sgn(a:real):integer;
 +  begin
 +       if a>0 then sgn:=+1;
 +       if a<0 then sgn:=-1;
 +       if a=0 then sgn:=0;
 +  end;
 +var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
 +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,b,col,where);
 +          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 'ASPHYXIA' at the top of the screen in little balls }
 +CONST ball : Array [1..5,1..5] of byte =
 +         ((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));
 +
 +VAR Logo : Array [1..5] of String;
 +    loop1,loop2,loop3,loop4:integer;
 +BEGIN
 +  pal (13,0,63,0);
 +  pal (1,0,0,40);
 +  pal (2,0,0,45);
 +  pal (3,0,0,50);
 +  pal (4,0,0,60);
 +  Logo[1]:=' O  OOO OOO O O O O O O OOO  O ';
 +  Logo[2]:='O O O   O O O O O O O O  O  O O';
 +  Logo[3]:='OOO OOO OOO OOO  O      OOO';
 +  Logo[4]:='O O   O O   O O  O  O O  O  O O';
 +  Logo[5]:='O O OOO O   O O  O  O O OOO O O';
 +  For loop1:=1 to 5 do
 +    For loop2:=1 to 31 do
 +      if logo[loop1][loop2]='O' then
 +        For loop3:=1 to 5 do
 +          For loop4:=1 to 5 do
 +            putpixel (loop2*10+loop3,loop1*4+loop4,ball[loop3,loop4],vaddr);
 +END;
 +
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure RotatePoints (X,Y,Z:Integer);
 +  { This rotates object lines by X,Y and Z; then places the result in
 +    TRANSLATED }
 +VAR loop1:integer;
 +    temp:point;
 +BEGIN
 +  For loop1:=1 to maxlines do BEGIN
 +    temp.x:=lines[loop1,1].x;
 +    temp.y:=lookup[x,2]*lines[loop1,1].y - lookup[x,1]*lines[loop1,1].z;
 +    temp.z:=lookup[x,1]*lines[loop1,1].y + lookup[x,2]*lines[loop1,1].z;
 +
 +    translated[loop1,1]:=temp;
 +
 +    If y>0 then BEGIN
 +      temp.x:=lookup[y,2]*translated[loop1,1].x - lookup[y,1]*translated[loop1,1].y;
 +      temp.y:=lookup[y,1]*translated[loop1,1].x + lookup[y,2]*translated[loop1,1].y;
 +      temp.z:=translated[loop1,1].z;
 +      translated[loop1,1]:=temp;
 +    END;
 +
 +    If z>0 then BEGIN
 +      temp.x:=lookup[z,2]*translated[loop1,1].x + lookup[z,1]*translated[loop1,1].z;
 +      temp.y:=translated[loop1,1].y;
 +      temp.z:=-lookup[z,1]*translated[loop1,1].x + lookup[z,2]*translated[loop1,1].z;
 +      translated[loop1,1]:=temp;
 +    END;
 +
 +    temp.x:=lines[loop1,2].x;
 +    temp.y:=cos (rad(X))*lines[loop1,2].y - sin (rad(X))*lines[loop1,2].z;
 +    temp.z:=sin (rad(X))*lines[loop1,2].y + cos (rad(X))*lines[loop1,2].z;
 +
 +    translated[loop1,2]:=temp;
 +
 +    If y>0 then BEGIN
 +      temp.x:=cos (rad(Y))*translated[loop1,2].x - sin (rad(Y))*translated[loop1,2].y;
 +      temp.y:=sin (rad(Y))*translated[loop1,2].x + cos (rad(Y))*translated[loop1,2].y;
 +      temp.z:=translated[loop1,2].z;
 +      translated[loop1,2]:=temp;
 +    END;
 +
 +    If z>0 then BEGIN
 +      temp.x:=cos (rad(Z))*translated[loop1,2].x + sin (rad(Z))*translated[loop1,2].z;
 +      temp.y:=translated[loop1,2].y;
 +      temp.z:=-sin (rad(Z))*translated[loop1,2].x + cos (rad(Z))*translated[loop1,2].z;
 +      translated[loop1,2]:=temp;
 +    END;
 +  END;
 +END;
 +
 +
 +
 +{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
 +Procedure DrawPoints;
 +  { This draws the translated object to the virtual screen }
 +VAR loop1:Integer;
 +    nx,ny,nx2,ny2:integer;
 +    temp:integer;
 +BEGIN
 +  For loop1:=1 to MaxLines do BEGIN
 +    If (translated[loop1,1].z+zoff<0) and (translated[loop1,2].z+zoff<0) then BEGIN
 +      temp:=round (translated[loop1,1].z+zoff);
 +      nx :=round (256*translated[loop1,1].X) div temp+xoff;
 +      ny :=round (256*translated[loop1,1].Y) div temp+yoff;
 +      temp:=round (translated[loop1,2].z+zoff);
 +      nx2:=round (256*translated[loop1,2].X) div temp+xoff;
 +      ny2:=round (256*translated[loop1,2].Y) div temp+yoff;
 +      If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and
 +         (NX2> 0) and (NX2< 320) and (NY2> 25) and (NY2< 200) then
 +           line (nx,ny,nx2,ny2,13,vaddr);
 +    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,0)" }
 +VAR loop1:Integer;
 +    nx,ny,nx2,ny2:Integer;
 +    temp:integer;
 +BEGIN
 +  For loop1:=1 to MaxLines do BEGIN
 +    If (translated[loop1,1].z+zoff<0) and (translated[loop1,2].z+zoff<0) then BEGIN
 +      temp:=round (translated[loop1,1].z+zoff);
 +      nx :=round (256*translated[loop1,1].X) div temp+xoff;
 +      ny :=round (256*translated[loop1,1].Y) div temp+yoff;
 +      temp:=round (translated[loop1,2].z+zoff);
 +      nx2:=round (256*translated[loop1,2].X) div temp+xoff;
 +      ny2:=round (256*translated[loop1,2].Y) div temp+yoff;
 +      If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and
 +         (NX2> 0) and (NX2< 320) and (NY2> 25) and (NY2< 200) then
 +           line (nx,ny,nx2,ny2,0,vaddr);
 +    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,loop1:integer;
 +    ch:char;
 +BEGIN
 +  deg:=0;
 +  ch:=#0;
 +  Cls (vaddr,0);
 +  DrawLogo;
 +  For loop1:=-256 to -40 do BEGIN
 +    zoff:=loop1*2;
 +    RotatePoints (deg,deg,deg);
 +    DrawPoints;
 +    flip (vaddr,vga);
 +    ClearPoints;
 +    deg:=(deg+5) mod 360;
 +  END;
 +
 +  Repeat
 +    if keypressed then BEGIN
 +      ch:=upcase (Readkey);
 +      Case ch of 'A' : zoff:=zoff+5;
 +                 'Z' : zoff:=zoff-5;
 +                 ',' : xoff:=xoff-5;
 +                 '.' : xoff:=xoff+5;
 +                 'S' : yoff:=yoff-5;
 +                 'X' : yoff:=yoff+5;
 +      END;
 +    END;
 +    DrawPoints;
 +    flip (vaddr,vga);
 +    ClearPoints;
 +    RotatePoints (deg,deg,deg);
 +    deg:=(deg+5) mod 360;
 +  Until ch=#27;
 +END;
 +
 +
 +BEGIN
 +  SetUpVirtual;
 +  Writeln ('Greetings and salutations! Hope you had a great Christmas and New');
 +  Writeln ('year! ;-) ... Anyway, this tutorial is on 3-D, so this is what is');
 +  Writeln ('going to happen ... a wireframe square will come towards you.');
 +  Writeln ('When it gets close, you get control. "A" and "Z" control the Z');
 +  Writeln ('movement, "," and "." control the X movement, and "S" and "X"');
 +  Writeln ('control the Y movement. I have not included rotation control, but');
 +  Writeln ('it should be easy enough to put in yourself ... if you have any');
 +  Writeln ('hassles, leave me mail.');
 +  Writeln;
 +  Writeln ('Read the main text file for ideas on improving this code ... and');
 +  Writeln ('welcome to the world of 3-D!');
 +  writeln;
 +  writeln;
 +  Write ('  Hit any key to contine ...');
 +  Readkey;
 +  SetMCGA;
 +  SetUpPoints;
 +  MoveAround;
 +  SetText;
 +  ShutDown;
 +  Writeln ('All done. This concludes the eigth sample program in the ASPHYXIA');
 +  Writeln ('Training series. You may reach DENTHOR under the names of GRANT');
 +  Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid');
 +  Writeln ('Connectix BBS user, and occasionally read RSAProg.');
 +  Writeln ('For discussion purposes, I am also the moderator of the Programming');
 +  Writeln ('newsgroup on the For Your Eyes Only BBS.');
 +  Writeln ('The numbers are available in the main text. You may also write to me at:');
 +  Writeln ('             Grant Smith');
 +  Writeln ('             P.O. Box 270');
 +  Writeln ('             Kloof');
 +  Writeln ('             3640');
 +  Writeln ('I hope to hear from you soon!');
 +  Writeln; Writeln;
 +  Write   ('Hit any key to exit ...');
 +  Readkey;
 +END.
 +</code>
 +
 +=== C ===
 +
 +<code c file:tut8.cpp>
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// TUTPROG8.CPP - VGA Trainer Program 8 (in Turbo C++ 3.0)                 //
 +//                                                                         //
 +// "The VGA Trainer Program" is written by Denthor of Asphyxia. However it //
 +// 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.  If you are        //
 +//                 a 486DX/33 or higher, you may wish to turn turbo off.   //
 +//                                                                         //
 +//                 If you are compiling this program from within the       //
 +//                 Turbo C++ environment, you must go under Options,       //
 +//                 Debugger, and change the "Program Heap Size" to a value //
 +//                 80 or greater.  If you are going to be fooling around   //
 +//                 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.  Remember, use this     //
 +//                 memory model when you have little code (less than 64k)  //
 +//                 and lots of data.                                       //
 +//                                                                         //
 +// Author        : Grant Smith (Denthor) - denthor@beastie.cs.und.ac.za    //
 +// Translator    : Christopher G. Mann   - r3cgm@dax.cc.uakron.edu         //
 +//                                                                         //
 +// Last Modified : January 14, 1995                                        //
 +//                                                                         //
 +/////////////////////////////////////////////////////////////////////////////
 +
 +//               //
 +// INCLUDE FILES //
 +//               //
 +
 +  #include <alloc.h>
 +                           // farcalloc()
 +  #include <conio.h>
 +                           // clrscr(), getch(), kbhit()
 +  #include <dos.h>
 +                           // FP_SEG, geninterrupt()
 +  #include <iostream.h>
 +                           // cout
 +  #include <math.h>
 +                           // sin(), cos()
 +  #include <stdlib.h>
 +                           // exit()
 +  #include "gfx1.cpp"
 +
 +//          //
 +// 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}}, //  0        .-----2----.
 +      {{-10,-10,-10}, {-10, 10,-10}}, //  1       /        /|
 +      {{-10, 10,-10}, { 10, 10,-10}}, //  2      9 |        A |
 +      {{ 10,-10,-10}, { 10, 10,-10}}, //  3     /  |       /  |
 +      {{-10,-10, 10}, { 10,-10, 10}}, //  4    .------6---.   3
 +      {{-10,-10, 10}, {-10, 10, 10}}, //  5    |        |   |
 +      {{-10, 10, 10}, { 10, 10, 10}}, //  6    |        7   |
 +      {{ 10,-10, 10}, { 10, 10, 10}}, //  7    |        |   |
 +      {{-10,-10, 10}, {-10,-10,-10}}, //  8    5   '----0-|---'
 +      {{-10, 10, 10}, {-10, 10,-10}}, //  9    |  /        /
 +      {{ 10, 10, 10}, { 10, 10,-10}}, //  A    | 8        | B
 +      {{ 10,-10, 10}, { 10,-10,-10}}  //  B    |/         |/
 +    };                                //       `-----4----'
 +
 +//                     //
 +// 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;           // Pointer to our virtual screen
 +  word Vaddr;                      // Segment of our virtual screen
 +  float Lookup[360][2];            // Our sin and cos lookup table
 +  int Xoff, Yoff, Zoff;            // Used for movement of the objects
 +  Point Lines[MAXLINES][2];        // The base object rotated
 +  Point Translated[MAXLINES][2];   // The rotated object
 +
 +
 +///////////////////////////////////////////////////////////////////////////////
 +//                                                                           //
 +//                                MAIN FUNCTION                              //
 +//                                                                           //
 +///////////////////////////////////////////////////////////////////////////////
 +
 +void main() {
 +
 +  SetUpVirtual();
 +  clrscr();
 +  cout
 +    << "Greetings and salutations! Hope you had a great Christmas and New\n"
 +    << "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. ""A"" and ""Z"" control the Z\n"
 +    << "movement, "","" and ""."" control the X movement, and ""S"" and ""X""\n"
 +    << "control the Y movement. I have not included rotation control, but\n"
 +    << "it should be easy enough to put in yourself ... if you have any\n"
 +    << "hassles, leave me mail.\n\n";
 +  cout
 +    << "Read the main text file for ideas on improving this code ... and\n"
 +    << "welcome to the world of 3-D!\n\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"
 +    << "Training series. You may reach DENTHOR under the names of GRANT\n"
 +    << "SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid\n"
 +    << "Connectix BBS user, and occasionally read RSAProg.\n"
 +    << "For discussion purposes, I am also the moderator of the Programming\n"
 +    << "newsgroup on the For Your Eyes Only BBS.\n"
 +    << "The numbers are available in the main text. You may also write to me at:\n"
 +    << "             Grant Smith\n"
 +    << "             P.O. Box 270\n"
 +    << "             Kloof\n"
 +    << "             3640\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,1);
 +
 +  // always check to see if enough memory was allocated
 +  if (Virscr == NULL) {
 +    SetText();
 +    cout << "Insufficient memory for virtual screens, exiting...";
 +    exit(1);
 +  }
 +
 +  Vaddr = FP_SEG(Virscr);
 +
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// ShutDown() - This frees the memory used by the virtual screen.          //
 +//                                                                         //
 +/////////////////////////////////////////////////////////////////////////////
 +
 +void ShutDown() {
 +  free(Virscr);
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// DrawLogo() - This draws 'SNOWMAN' at the top of the screen in little    //
 +//              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"},
 +                          {"  O O O O O O O O O O O O O O"},
 +                          {"OOO O O O O O O O O O O OOO O O"},
 +                          {"  O O O O O O O O O O O O O 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 each line...
 +    for (loop2=0; loop2<31; loop2++)       // is it active?
 +      if (Logo[loop1][loop2] == 'O')
 +      for (loop3=0; loop3<5; loop3++)        // y coordinate of the ball
 +        for (loop4=0; loop4<5; loop4++)        // x coordinate of the ball
 +          Putpixel ((loop2+1)*10+loop3, (loop1+1)*4+loop4,
 +                    ball[loop3][loop4],Vaddr);
 +
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// SetUpPoints() - This sets the basic offsets of the object, creates the  //
 +//                 lookup table, and moves the object from a constant to a //
 +//                 variable.                                               //
 +//                                                                         //
 +/////////////////////////////////////////////////////////////////////////////
 +
 +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<361; 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<MAXLINES; 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<MAXLINES; 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<MAXLINES; loop1++) {
 +    if ((Translated[loop1][0].z+Zoff<0) && (Translated[loop1][1].z+Zoff<0)) {
 +
 +      // 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<320) && (ny2>25) && (ny2<200))
 +        Line(nx,ny,nx2,ny2,13,Vaddr);
 +    }
 +  }
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// ClearPoints() - This clears the translated object from the virtual      //
 +//                 screen ... believe it or not, this is faster than a     //
 +//                 straight cls(0,vaddr);                                  //
 +//                                                                         //
 +/////////////////////////////////////////////////////////////////////////////
 +
 +void ClearPoints() {
 +
 +  int loop1, nx, ny, nx2, ny2, temp;
 +
 +  for (loop1=0; loop1<MAXLINES; loop1++) {
 +    if ((Translated[loop1][0].z+Zoff<0) && (Translated[loop1][1].z+Zoff<0)) {
 +
 +      // 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<320) && (ny2>25) && (ny2<200))
 +        Line(nx,ny,nx2,ny2,0,Vaddr);
 +    }
 +  }
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//                                                                         //
 +// MoveAround() - This is the main display function.  First it brings the  //
 +//                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.  If you know
 +  // 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,Vaddr);
 +
 +  DrawLogo();
 +
 +  for (loop1=(-256); loop1<(-39); loop1++) {
 +    Zoff = loop1 * 2;
 +    RotatePoints(deg,deg,deg);
 +    DrawPoints();
 +    Flip(Vaddr,VGA);
 +    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.  We already have 7 include
 +        // files, and its getting a bit rediculous.
 +        case 'A': case 'a': Zoff += 5; break;  // away
 +        case 'Z': case 'z': Zoff -= 5; break;  // toward
 +        case ',':           Xoff -= 5; break;  // left
 +        case '.':           Xoff += 5; break;  // right
 +        case 'S': case 's': Yoff -= 5; break;  // down
 +        case 'X': case 'x': Yoff += 5; break;  // up
 +      }
 +    }
 +    DrawPoints();
 +    Flip(Vaddr,VGA);
 +    ClearPoints();
 +    RotatePoints(deg,deg,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>
  
 <nspages back2root/archives/denthor -simpleList -title -h1 -exclude:start -textPages="Denthor VGA Trainer"> <nspages back2root/archives/denthor -simpleList -title -h1 -exclude:start -textPages="Denthor VGA Trainer">
back2root/archives/denthor/part-08.txt · Dernière modification : 2021/09/18 20:39 de frater