'=========================================================================== ' Subject: WIREFRAME-3D Date: 04-28-93 (00:00) ' Author: Rich Geldreich Code: PDS, VBDOS ' Origin: FidoNet QUIK_BAS Echo Packet: EGAVGA.ABC '=========================================================================== 'WIREF4.BAS By Rich Geldreich 'Last modified April 28, 1993. 'For PDS/VB-DOS only. This program isn't totally completed, and 'doesn't have much documentation, yet. I'd appreciate your 'feedback! ' DEFINT A-Z '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- CONST True = -1, False = 0 CONST MaxObject = 9 CONST MaxPlane = 99 CONST MaxPoint = (MaxPlane + 1) * 3 - 1 CONST MaxLine = (MaxPlane + 1) * 3 - 1 CONST PerspectiveScaler& = 768 CONST RotateScaler = 2048 CONST UserPlane = 75 'Constants for SCREEN 9, the EGA's 640x350x16 two page mode. CONST XScreenRatio = 5, YScreenRatio = 4 CONST MinX = 0, MinY = 0 CONST MaxX = 639, MaxY = 349 CONST MidX = 320, MidY = 175 CONST LineColor = 15 CONST ViewDistance& = 7000& * 7000 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- DEF FNV (A) = ((A MOD 360) + 360) MOD 360 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- TYPE VectType A1 AS INTEGER A2 AS INTEGER A3 AS INTEGER END TYPE TYPE OrgType Ox AS INTEGER Oy AS INTEGER Oz AS INTEGER END TYPE TYPE SineCosType S1 AS LONG C1 AS LONG S2 AS LONG C2 AS LONG S3 AS LONG C3 AS LONG END TYPE TYPE PointType x AS INTEGER y AS INTEGER z AS INTEGER Rx AS INTEGER Ry AS INTEGER Rz AS INTEGER END TYPE TYPE ObjectType Org AS OrgType Direction AS VectType PlaneIndice AS INTEGER PointIndice AS INTEGER MaxPlane AS INTEGER MaxPoint AS INTEGER MaxCord AS INTEGER CullFlag AS INTEGER END TYPE TYPE PlaneType Points(0 TO 3) AS INTEGER MaxPoint AS INTEGER END TYPE TYPE LineType sx AS INTEGER sy AS INTEGER ex AS INTEGER ey AS INTEGER END TYPE '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- 'Number of objects to read. DATA 8 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Objects Follow-- ' To speed things up I recommend that very large, complicated 'objects be split up into numerous smaller objects because objects 'which are totally behind the viewer are ignored. If most of a gaint 'object is visible, then the entire object must be processed. If the 'object is built of smaller objects then less of it will be processed 'when part of it is behind the user. '--Object 0, box. 'Object's starting XYZ coordinates. DATA -60,0,-200 'Object's starting rotatation angles. DATA 0,0,0 ' If this value not zero, then the object can be culled. (Culling 'removes hidden polygons from the object to speed up plotting and 'improve clarity.) For culling to work properly all planes in the 'object must be specified in counter-clockwise order as if you are 'looking directly at it! DATA -1 'Planes ' The first number specifies the number of points in the plane. 'If the plane contains 4 points, then a 3 would appear as the first 'number on the DATA statement(0-3=4 points). Planes with 3 points 'would be proceeded with a 2. The remaining numbers point into the 'point list. A plane may have 2,3, or 4 points. Planes with 2 'points cannot be culled and are treated as single lines. DATA 3,0,1,2,3 DATA 3,1,5,6,2 DATA 3,5,4,7,6 DATA 3,4,0,3,7 DATA 3,4,5,1,0 DATA 3,3,2,6,7 'End the plane list with -32768. DATA -32768 'Points ' Each XYZ point in the object follows. The plane list above 'refers to this list. A point may be shared by more than one plane 'in its object, but points cannot be shared between objects. DATA -100,-100,100 DATA 100,-100,100 DATA 100,100,100 DATA -100,100,100 DATA -100,-100,-100 DATA 100,-100,-100 DATA 100,100,-100 DATA -100,100,-100 'End the point list with -32768,0,0. DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 1, box. DATA 0,0,300, 0,0,0, -1 DATA 3,0,1,2,3, 3,1,5,6,2, 3,5,4,7,6, 3,4,0,3,7, 3,4,5,1,0,3,3,2,6,7 DATA -32768 DATA -100,-100,100, 100,-100,100, 100,100,100, -100,100,100 DATA -100,-100,-100, 100,-100,-100, 100,100,-100, -100,100,-100 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 2, house. DATA 0,0,0, 0,0,0, 0 DATA 3,0,1,2,3, 3,4,5,6,7, 1,1,5, 1,0,4, 1,3,7, 1,2,6 DATA -32768 DATA -1000,-400,1000, 1000,-400,1000, 1000,100,1000,-1000,100,1000 DATA -1000,-400,-1000, 1000,-400,-1000, 1000,100,-1000,-1000,100,-1000 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 3, doorway and sidewalk. DATA 0,0,0, 0,0,0, 0 DATA 1,0,1, 1,2,3, 1,4,5, 1,6,7, 1,8,9 DATA -32768 DATA 150,100,1000, 150,-250,1000, -150,100,1000, -150,-250,1000 DATA -150,-250,1000, 150,-250,1000, -150,100,1000, -150,100,2500 DATA 150,100,1000, 150,100,2500 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 4, first window. DATA 0,0,0, 0,0,0, 0 DATA 3,0,1,2,3 DATA -32768 DATA -500,-100,1000, -300,-100,1000, -300,-250,1000,-500,-250,1000 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 5, second window. DATA 0,0,0, 0,0,0, 0 DATA 3,0,1,2,3 DATA -32768 DATA 500,-100,1000, 300,-100,1000, 300,-250,1000, 500,-250,1000 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- '--Object 6, pyramid. DATA 0,100,3000, 0,0,0, -1 DATA 3,3,2,1,0, 2,4,2,3, 2,4,1,2, 2,4,0,1, 2,4,3,0 DATA -32768 DATA -300,0,-300, 300,0,-300, 300,0,300, -300,0,300, 0,-350,0 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- 'Object 7, roof DATA 0,0,0, 0,0,0, 0 DATA 1,0,4, 1,1,4, 1,2,4, 1,3,4 DATA -32768 DATA 1000,-400,-1000, -1000,-400,-1000 DATA -1000,-400,1000, 1000,-400,1000, 0,-800,0 DATA -32768,0,0 '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- DIM SHARED SineTable(0 TO 359 + 90) AS LONG DIM SHARED Objects(0 TO MaxObject) AS ObjectType DIM SHARED Planes(0 TO MaxPlane) AS PlaneType DIM SHARED Points(0 TO MaxPoint) AS PointType DIM SHARED PlaneIndice, ObjectIndice, PointIndice DIM SHARED WorldOrg AS OrgType DIM SHARED WorldVect AS VectType DIM SHARED WorldSineCos AS SineCosType DIM SHARED WorldSpeed DIM SHARED LinesToErase(0 TO 1, 0 TO MaxLine) AS LineType DIM SHARED MaxLineToErase(0 TO 1) DIM SHARED LowX, LowY, HighX, HighY DIM SHARED VidPage '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=- PrintInstructions InitializeTables ReadObjects InitializeWorld LOCATE , 1 PRINT "Press any key!"; A$ = INPUT$(1) DO A$ = INKEY$ ProcessKey A$ DoFrame LOOP UNTIL A$ = CHR$(27) END 'This function checks a plane to see if it can be seen. There are 'faster ways that don't involve all of this math, but this method is 'very elegant and easy to implement. FUNCTION Check4Cull (BYVAL x0, BYVAL y0, BYVAL x1, BYVAL y1,BYVAL x2, BYVAL y2) Check4Cull = (CLNG(x1 - x0) * (y2 - y0) - CLNG(x2 - x0) *(y1 - y0)) >= 0 END FUNCTION 'This subroutine displays each object in the scene. SUB DisplayObjects DIM ObjectVect AS VectType DIM ObjectSineCos AS SineCosType DIM ObjOrg AS PointType FOR A = 0 TO ObjectIndice ObjOrg.x = Objects(A).Org.Ox - WorldOrg.Ox ObjOrg.y = Objects(A).Org.Oy - WorldOrg.Oy ObjOrg.z = Objects(A).Org.Oz - WorldOrg.Oz RotateOrigPoint ObjOrg, WorldSineCos IF ObjOrg.Rz >= Objects(A).MaxCord THEN IF (CLNG(ObjOrg.x) * ObjOrg.x) + (CLNG(ObjOrg.y) *ObjOrg.y) + (CLNG(ObjOrg.z) * ObjOrg.z) < ViewDistance& THEN ObjectVect = Objects(A).Direction IF ObjectVect.A1 = 0 AND ObjectVect.A2 = 0 AND ObjectVect.A3 = 0 THEN FOR B = Objects(A).PointIndice TO Objects(A).PointIndice + Objects(A).MaxPoint RotateOrigPoint Points(B), WorldSineCos Points(B).Rx = Points(B).Rx + ObjOrg.Rx Points(B).Ry = Points(B).Ry + ObjOrg.Ry Points(B).Rz = Points(B).Rz + ObjOrg.Rz NEXT ELSE LookUpSineCos ObjectVect, ObjectSineCos FOR B = Objects(A).PointIndice TO Objects(A).PointIndice + Objects(A).MaxPoint RotateOrigPoint Points(B), ObjectSineCos Points(B).Rx = Points(B).Rx + ObjOrg.x Points(B).Ry = Points(B).Ry + ObjOrg.y Points(B).Rz = Points(B).Rz + ObjOrg.z RotateNewPoint Points(B), WorldSineCos NEXT END IF I = MaxLineToErase(VidPage) LowX = 32767: LowY = 32767 HighX = -32768: HighY = -32768 IF Objects(A).CullFlag = True THEN FOR B = Objects(A).PlaneIndice TO Objects(A).PlaneIndice + Objects(A).MaxPlane ProjectPlane Planes(B) NEXT ELSE FOR B = Objects(A).PlaneIndice TO Objects(A).PlaneIndice + Objects(A).MaxPlane SELECT CASE Planes(B).MaxPoint CASE 1 ProjectLine Points(Planes(B).Points(0)), Points(Planes(B).Points(1)) CASE 2 ProjectLine Points(Planes(B).Points(0)),Points(Planes(B).Points(1)) ProjectLine Points(Planes(B).Points(1)),Points(Planes(B).Points(2)) ProjectLine Points(Planes(B).Points(2)),Points(Planes(B).Points(0)) CASE ELSE ProjectLine Points(Planes(B).Points(0)),Points(Planes(B).Points(1)) ProjectLine Points(Planes(B).Points(1)),Points(Planes(B).Points(2)) ProjectLine Points(Planes(B).Points(2)),Points(Planes(B).Points(3)) ProjectLine Points(Planes(B).Points(3)),Points(Planes(B).Points(0)) END SELECT NEXT END IF IF (LowX <= MaxX) AND (LowY <= MaxY) AND (HighX >=0) AND (HighY >= 0) THEN FOR B = I + 1 TO MaxLineToErase(VidPage) LINE (LinesToErase(VidPage, B).sx,LinesToErase(VidPage, B).sy)-(LinesToErase(VidPage, B).ex,LinesToErase(VidPage, B).ey), LineColor NEXT ELSE MaxLineToErase(VidPage) = I END IF END IF END IF NEXT END SUB SUB DoFrame UpdateObjects SwitchScreen EraseScreen DisplayObjects END SUB 'This subroutine plots one line to the screen and enters it into the 'current page's erase list. SUB DrawLine (BYVAL x0, BYVAL y0, BYVAL x1, BYVAL y1) DIM LineToPlot AS LineType IF x0 < LowX THEN LowX = x0 IF y0 < LowY THEN LowY = y0 IF x1 < LowX THEN LowX = x1 IF y1 < LowY THEN LowY = y1 IF x0 > HighX THEN HighX = x0 IF y0 > HighY THEN HighY = y0 IF x1 > HighX THEN HighX = x1 IF y1 > HighY THEN HighY = y1 LineToPlot.sx = x0 LineToPlot.sy = y0 LineToPlot.ex = x1 LineToPlot.ey = y1 A = MaxLineToErase(VidPage) + 1 LinesToErase(VidPage, A) = LineToPlot MaxLineToErase(VidPage) = A END SUB 'This subroutine erases all lines previously drawn on the current 'video page. SUB EraseScreen FOR A = 0 TO MaxLineToErase(VidPage) LINE (LinesToErase(VidPage, A).sx, LinesToErase(VidPage,A).sy)-(LinesToErase(VidPage, A).ex, LinesToErase(VidPage,A).ey), 0 NEXT MaxLineToErase(VidPage) = -1 END SUB 'This subroutine initializes the sine & cosine lookup table. Each 'entry is scaled up by a constant to avoid floating point math at 'runtime(in assembly this would already be calculated and stored as 'data.) SUB InitializeTables FOR A = 0 TO 359 SineTable(A) = INT(SIN(A / 57.2957) * RotateScaler + .5) NEXT FOR A = 360 TO 360 + 90 - 1 SineTable(A) = SineTable(A - 360) NEXT END SUB 'This subroutine initializes the variables used to describe the user's 'location and viewing angle. SUB InitializeWorld WorldOrg.Ox = 0 WorldOrg.Oy = -230 WorldOrg.Oz = -600 WorldVect.A1 = 0 WorldVect.A2 = 0 WorldVect.A3 = 0 MaxLineToErase(0) = -1 MaxLineToErase(1) = -1 VidPage = 1 END SUB 'This function limits an integer into an inclusive range. FUNCTION Limit (BYVAL A, BYVAL l, BYVAL H) IF A < l THEN A = l IF A > H THEN A = H Limit = A END FUNCTION FUNCTION LongLimit (BYVAL A&) IF A& >= -32768 AND A& <= 32767 THEN LongLimit = A& ELSE IF A& < 0 THEN LongLimit = -1 ELSE LongLimit = MaxX + 1 END IF END IF END FUNCTION 'This subroutine takes a vector (3 angles) and looks them up in the 'sine & cosine table. SUB LookUpSineCos (V AS VectType, A AS SineCosType) A.S1 = SineTable(V.A1) A.C1 = SineTable(V.A1 + 90) A.S2 = SineTable(V.A2) A.C2 = SineTable(V.A2 + 90) A.S3 = SineTable(V.A3) A.C3 = SineTable(V.A3 + 90) END SUB 'This subroutine prints the instructions to the screen. (duh ) SUB PrintInstructions PRINT "Simple Object Based Wireframe 3-D" PRINT "By Rich Geldreich (Zeek of Renaissance) April, 1993" PRINT "Use these keys to control position: (Turn NUMLOCK on!)" PRINT "4.............Turn Head Left" PRINT "6.............Turn Head Right" PRINT "8.............Go Forward" PRINT "9.............Go Backward" PRINT "5.............Stop motion" PRINT "A.............Total Reset" PRINT "Up Arrow......Turn Head Upward" PRINT "Down Arrow....Turn Head Downward" PRINT "Left Arrow....Tilt Head" PRINT "Right Arrow...Tilt Head" PRINT "U.............Y Coordinate -" PRINT "D.............Y Coordinate +" PRINT "L.............X Coordinate -" PRINT "R.............X Coordinate +" PRINT "ESC...........Quits" PRINT PRINT "Wait a sec!"; END SUB 'This subroutine gets called after each frame. It processes any 'keystrokes from the user and updates the location & viewing 'parameters. SUB ProcessKey (A$) STATIC IF A$ <> "" THEN A = (ASC(RIGHT$(UCASE$(A$), 1))) * ((LEN(A$) > 1) OR 1) SELECT CASE A CASE 85 WorldOrg.Oy = WorldOrg.Oy - 30 CASE 68 WorldOrg.Oy = WorldOrg.Oy + 30 CASE 76 WorldOrg.Ox = WorldOrg.Ox - 30 CASE 82 WorldOrg.Ox = WorldOrg.Ox + 30 CASE 65 WorldSpeed = 0 A1 = 0: A2 = 0: A3 = 0 WorldVect.A1 = 0 WorldVect.A2 = 0 WorldVect.A3 = 0 WorldOrg.Ox = 0 WorldOrg.Oy = -130 WorldOrg.Oz = 0 CASE -72 'up A3 = A3 - 3 CASE -80 'down A3 = A3 + 3 CASE -75 'left A2 = A2 + 3 CASE -77 'right A2 = A2 - 3 CASE 56 '8 WorldSpeed = WorldSpeed - 15 CASE 50 '2 WorldSpeed = WorldSpeed + 15 CASE 53, 32 WorldSpeed = 0 A1 = 0: A2 = 0: A3 = 0 CASE 48 A1 = 0: A2 = 0: A3 = 0 CASE 52 A1 = A1 - 3 CASE 54 A1 = A1 + 3 END SELECT A1 = Limit(A1, -30, 30) A2 = Limit(A2, -30, 30) A3 = Limit(A3, -30, 30) WorldSpeed = Limit(WorldSpeed, -160, 160) END IF WorldVect.A1 = FNV(WorldVect.A1 + A1) WorldVect.A2 = FNV(WorldVect.A2 + A2) WorldVect.A3 = FNV(WorldVect.A3 + A3) END SUB 'This subroutine takes a line in 3-D space and calculates the 'starting and ending points of the line on the viewing screen. If 'the line passes the viewing plane, it is cut so the entire line is 'visible before the perspective calculation is applied. SUB ProjectLine (p1 AS PointType, p2 AS PointType) x1 = p1.Rx y1 = p1.Ry z1 = p1.Rz x2 = p2.Rx y2 = p2.Ry z2 = p2.Rz IF (z1 < UserPlane) OR (z2 < UserPlane) THEN IF (z1 < UserPlane) AND (z2 < UserPlane) THEN EXIT SUB IF z1 < UserPlane THEN SWAP x1, x2 SWAP y1, y2 SWAP z1, z2 END IF Xd& = x2 - x1 Yd& = y2 - y1 Zd& = z2 - z1 z2 = UserPlane x2 = x1 + (Xd& * (UserPlane - z1)) \ Zd& y2 = y1 + (Yd& * (UserPlane - z1)) \ Zd& END IF sx = LongLimit(MidX + XScreenRatio * ((x1 *PerspectiveScaler&) \ z1) \ 10) sy = LongLimit(MidY + YScreenRatio * ((y1 *PerspectiveScaler&) \ z1) \ 10) ex = LongLimit(MidX + XScreenRatio * ((x2 *PerspectiveScaler&) \ z2) \ 10) ey = LongLimit(MidY + YScreenRatio * ((y2 *PerspectiveScaler&) \ z2) \ 10) DrawLine sx, sy, ex, ey END SUB SUB ProjectPlane (Plane AS PlaneType) DIM PointCut(0 TO 3) MP = Plane.MaxPoint IF MP = 1 THEN ProjectLine Points(Plane.Points(0)),Points(Plane.Points(1)) EXIT SUB END IF FOR A = 0 TO MP IF Points(Plane.Points(A)).Rz < UserPlane THEN PointCut(A) = True PointsCut = PointsCut + 1 END IF NEXT IF PointsCut = 0 THEN p0 = Plane.Points(0): p1 = Plane.Points(1) p2 = Plane.Points(2): p3 = Plane.Points(3) SELECT CASE MP CASE 2 ProjectPoint Points(p0), x0, y0 ProjectPoint Points(p1), x1, y1 ProjectPoint Points(p2), x2, y2 CASE 3 ProjectPoint Points(p0), x0, y0 ProjectPoint Points(p1), x1, y1 ProjectPoint Points(p2), x2, y2 ProjectPoint Points(p3), x3, y3 END SELECT IF Check4Cull(x0, y0, x1, y1, x2, y2) = False THEN SELECT CASE MP CASE 2 DrawLine x0, y0, x1, y1 DrawLine x1, y1, x2, y2 DrawLine x2, y2, x0, y0 CASE ELSE DrawLine x0, y0, x1, y1 DrawLine x1, y1, x2, y2 DrawLine x2, y2, x3, y3 DrawLine x3, y3, x0, y0 END SELECT END IF ELSEIF PointsCut - 1 = MP THEN EXIT SUB ELSE FOR A = 0 TO MP IF PointCut(A) = False THEN EXIT FOR NEXT LastP = (A - 1): IF LastP < 0 THEN LastP = MP NextP = (A + 1): IF NextP > MP THEN NextP = 0 A = Plane.Points(A) LastP = Plane.Points(LastP) NextP = Plane.Points(NextP) SplitLine Points(A), Points(LastP), XL, YL SplitLine Points(A), Points(NextP), XN, YN ProjectPoint Points(A), XM, YM IF Check4Cull(XM, YM, XN, YN, XL, YL) = False THEN p0 = Plane.Points(0): p1 = Plane.Points(1) p2 = Plane.Points(2): p3 = Plane.Points(3) SELECT CASE MP CASE 2 ProjectLine Points(p0), Points(p1) ProjectLine Points(p1), Points(p2) ProjectLine Points(p2), Points(p0) CASE ELSE ProjectLine Points(p0), Points(p1) ProjectLine Points(p1), Points(p2) ProjectLine Points(p2), Points(p3) ProjectLine Points(p3), Points(p0) END SELECT END IF END IF END SUB SUB ProjectPoint (P AS PointType, nx, ny) nx = LongLimit(MidX + XScreenRatio * ((P.Rx *PerspectiveScaler&) \ P.Rz) \ 10) ny = LongLimit(MidY + YScreenRatio * ((P.Ry *PerspectiveScaler&) \ P.Rz) \ 10) END SUB SUB ReadObjects RESTORE READ ObjectIndice PlaneIndice = 0 PointIndice = 0 FOR Object = 0 TO ObjectIndice - 1 READ Objects(Object).Org.Ox READ Objects(Object).Org.Oy READ Objects(Object).Org.Oz READ Objects(Object).Direction.A1 READ Objects(Object).Direction.A2 READ Objects(Object).Direction.A3 READ Objects(Object).CullFlag Objects(Object).PlaneIndice = PlaneIndice Objects(Object).PointIndice = PointIndice NumPlanes = 0 DO READ A IF A <> -32768 THEN Planes(PlaneIndice).MaxPoint = A FOR B = 0 TO A READ A Planes(PlaneIndice).Points(B) = A +PointIndice NEXT PlaneIndice = PlaneIndice + 1 NumPlanes = NumPlanes + 1 ELSE EXIT DO END IF LOOP Objects(Object).MaxPlane = NumPlanes - 1 NumPoints = 0 Max = -32768 DO READ A, B, C IF A <> -32768 THEN IF ABS(A) > Max THEN Max = ABS(A) IF ABS(B) > Max THEN Max = ABS(B) IF ABS(C) > Max THEN Max = ABS(C) Points(PointIndice).x = A Points(PointIndice).y = B Points(PointIndice).z = C PointIndice = PointIndice + 1 NumPoints = NumPoints + 1 ELSE EXIT DO END IF LOOP Objects(Object).MaxPoint = NumPoints - 1 Objects(Object).MaxCord = -(Max + 200) NEXT ObjectIndice = ObjectIndice - 1 PlaneIndice = PlaneIndice - 1 PointIndice = PointIndice - 1 END SUB SUB RotateNewPoint (P AS PointType, A AS SineCosType) x1 = (P.Rx * A.C1 - P.Rz * A.S1) \ RotateScaler z1 = (P.Rx * A.S1 + P.Rz * A.C1) \ RotateScaler P.Rz = (z1 * A.C3 - P.Ry * A.S3) \ RotateScaler y2 = (z1 * A.S3 + P.Ry * A.C3) \ RotateScaler P.Rx = (x1 * A.C2 + y2 * A.S2) \ RotateScaler P.Ry = (y2 * A.C2 - x1 * A.S2) \ RotateScaler END SUB SUB RotateOrigPoint (P AS PointType, A AS SineCosType) x1 = (P.x * A.C1 - P.z * A.S1) \ RotateScaler z1 = (P.x * A.S1 + P.z * A.C1) \ RotateScaler P.Rz = (z1 * A.C3 - P.y * A.S3) \ RotateScaler y2 = (z1 * A.S3 + P.y * A.C3) \ RotateScaler P.Rx = (x1 * A.C2 + y2 * A.S2) \ RotateScaler P.Ry = (y2 * A.C2 - x1 * A.S2) \ RotateScaler END SUB SUB SplitLine (p1 AS PointType, p2 AS PointType, x0, y0) x1 = p1.Rx y1 = p1.Ry z1 = p1.Rz x2 = p2.Rx y2 = p2.Ry z2 = p2.Rz IF (z2 < UserPlane) THEN Xd& = x2 - x1 Yd& = y2 - y1 Zd& = z2 - z1 z2 = UserPlane x2 = x1 + (Xd& * (UserPlane - z1)) \ Zd& y2 = y1 + (Yd& * (UserPlane - z1)) \ Zd& END IF x0 = LongLimit(MidX + XScreenRatio * ((x2 *PerspectiveScaler&) \ z2) \ 10) y0 = LongLimit(MidY + YScreenRatio * ((y2 *PerspectiveScaler&) \ z2) \ 10) END SUB SUB SwitchScreen VidPage = 1 - VidPage SCREEN 9, , VidPage, 1 - VidPage WAIT &H3DA, 8, 8 WAIT &H3DA, 8 END SUB SUB UpdateObjects STATIC Init, XMove, ZMove IF Init = False THEN XMove = 6 ZMove = -4 Init = True END IF Objects(1).Direction.A3 = FNV(Objects(1).Direction.A3 + 4) Objects(6).Direction.A1 = FNV(Objects(6).Direction.A1 - 4) x = Objects(1).Org.Ox x = x + XMove IF x < -800 OR x > 800 THEN XMove = -XMove: x = x + XMove Objects(1).Org.Ox = x z = Objects(1).Org.Oz z = z + ZMove IF z < -800 OR z > 800 THEN ZMove = -ZMove: z = z + ZMove Objects(1).Org.Oz = z mx = (WorldSpeed * WorldSineCos.C3) \ RotateScaler my = (WorldSpeed * WorldSineCos.S3) \ RotateScaler Mz = (mx * WorldSineCos.C1) \ RotateScaler mx = (mx * WorldSineCos.S1) \ RotateScaler WorldOrg.Ox = Limit(WorldOrg.Ox - mx, -16000, 16000) WorldOrg.Oy = Limit(WorldOrg.Oy + my, -16000, 16000) WorldOrg.Oz = Limit(WorldOrg.Oz - Mz, -16000, 16000) LookUpSineCos WorldVect, WorldSineCos END SUB ' That's all! Sorry that it only works under PDS or VB/DOS, but I love 'using BYVAL and having arrays in TYPE structures.