'''Vector article supplement '''Playing with colors!!! '''Gouraud+Phong in 16 color gradient '''Cube by SCM '''Torus by Biskbart '''All others by Relsoft '''SetVideoSeg by Plasma357 '''Tritexture modified from CGI Joe's code. '''PhongPal by Bobby3999 '''Rel.betterwebber.com DECLARE SUB SetPhong16Grad () DECLARE SUB GouraudTri (ox1%, oy1%, oc1%, ox2%, oy2%, oc2%, ox3%, oy3%, oc3%) DECLARE SUB LoadTorus (Rings%, Bands%, RINGRADIUS%, BandRadius%, Model() AS ANY, Poly() AS ANY) DECLARE SUB SetPolyBaseColor (Poly() AS ANY) DECLARE SUB Rotnormals (V() AS ANY, v2() AS ANY, M AS ANY) DECLARE SUB RotateAndProject (Model() AS ANY, M AS ANY) DECLARE SUB CalcNormals (Model() AS ANY, ModelConnect() AS ANY, V() AS ANY, v2() AS ANY) DECLARE SUB RotMatrix (M AS ANY, anglex%, angley%, anglez%) DECLARE SUB DrawModelGour (Model() AS ANY, Poly() AS ANY, VtxNormal() AS ANY) DECLARE SUB SortPolys (Model() AS ANY, Poly() AS ANY) DECLARE SUB ShellSort (Poly() AS ANY, Min%, Max%) DECLARE SUB LoadCube (Model() AS ANY, Poly() AS ANY, radius%) DECLARE SUB LoadPlane (Model() AS ANY, Poly() AS ANY, radius%) DECLARE SUB SetVideoSeg (Segment%) DECLARE SUB LoadCylinder (Model() AS ANY, Poly() AS ANY, radius%, Slices%, Bands%, zdist%) DECLARE SUB LoadSphere (Model() AS ANY, Poly() AS ANY, radius%, Slices%, Bands%) DECLARE SUB PhongPal (Ra!, Rd!, Rs!, Ga!, Gd!, Gs!, Ba!, Bd!, Bs!, N%, col1%, col2%) DEFINT A-Z REM $DYNAMIC TYPE Point3d x AS SINGLE 'our 3d point y AS SINGLE z AS SINGLE xr AS SINGLE 'Rotated 3d point yr AS SINGLE 'not needed really Zr AS SINGLE ScrX AS INTEGER 'projected x/y coords ScrY AS INTEGER 'for display on screen END TYPE TYPE PolyType p1 AS INTEGER 'vertex 1 of our triangle p2 AS INTEGER 'huh? p3 AS INTEGER Clr AS INTEGER 'color for flat shading u1 AS INTEGER 'Texture U and V v1 AS INTEGER u2 AS INTEGER v2 AS INTEGER u3 AS INTEGER v3 AS INTEGER zcenter AS INTEGER 'everage z coord of a poly idx AS INTEGER 'index used for sorting END TYPE TYPE VectorType x AS SINGLE y AS SINGLE z AS SINGLE END TYPE TYPE MatrixType xx AS SINGLE xy AS SINGLE xz AS SINGLE yx AS SINGLE yy AS SINGLE yz AS SINGLE zx AS SINGLE zy AS SINGLE zz AS SINGLE END TYPE CONST FALSE = 0, TRUE = NOT FALSE CONST LENS = 256 'our multiplier CONST XCENTER = 160 'mid x and y of screen 13 CONST YCENTER = 100 CONST PI = 3.14151693# CONST TORNUMRINGS = 16 'Number of Rings outside TORUS CONST TORNUMBANDS = 10 'Number of PIXEL per RING CONST TORRINGRADIUS = 65 'Radius of the Ring CONST TORBANDRADIUS = 20 'Radius of the BAND REDIM SHARED Vpage(32009) AS INTEGER 'out buffer DIM SHARED Lcos(359) AS SINGLE 'LUTS for fast rotation DIM SHARED Lsin(359) AS SINGLE REDIM SHARED Model(1) AS Point3d 'our 3d object REDIM SHARED Tri(1) AS PolyType 'its polygons REDIM SHARED Normal(1) AS VectorType '"Normal" normal REDIM SHARED Normal2(1) AS VectorType 'Rotated face normal REDIM SHARED VertexNormal(1) AS VectorType 'Vertex normal REDIM SHARED VertexNormal2(1) AS VectorType 'rotated DIM SHARED Thetax, Thetay, Thetaz 'angle of rotation DIM SHARED TextSeg%, Textoff%, ImgSize% 'easy reference DIM SHARED camz%, camy%, camx% 'our cartesian camera DIM SHARED Matrix AS MatrixType DIM SHARED LightNormal AS VectorType RANDOMIZE TIMER FOR i = 0 TO 359 'prefcalc our Lookup tables a! = i * PI / 180 Lcos(i) = COS(a!) Lsin(i) = SIN(a!) NEXT i LightNormal.x = 0 'Light is from the camera LightNormal.y = -.1 LightNormal.z = -.7 'Normalize Mag! = SQR(LightNormal.x ^ 2 + LightNormal.y ^ 2 + LightNormal.z ^ 2) IF Mag! <> 0 THEN LightNormal.x = LightNormal.x / Mag! LightNormal.y = LightNormal.y / Mag! LightNormal.z = LightNormal.z / Mag! END IF CLS SCREEN 0 WIDTH 80 LOCATE 1, 1 'get input PRINT "Choose Model:" PRINT "1. Cube" PRINT "2. Cylinder" PRINT "3. Sphere" PRINT "4. Torus[Default]" DO K$ = INKEY$ LOOP UNTIL K$ <> "" Cull = TRUE 'if backface culing enabled SELECT CASE ASC(K$) CASE 49 LoadCube Model(), Tri(), 45 CASE 50 LoadCylinder Model(), Tri(), 50, 8, 8, 20 CASE 51 LoadSphere Model(), Tri(), 70, 10, 10 CASE 52 LoadTorus TORNUMRINGS, TORNUMBANDS, TORRINGRADIUS, TORBANDRADIUS, Model(), Tri() CASE ELSE LoadTorus TORNUMRINGS, TORNUMBANDS, TORRINGRADIUS, TORBANDRADIUS, Model(), Tri() END SELECT ''Set up new normals REDIM Normal(0 TO UBOUND(Tri)) AS VectorType REDIM Normal2(0 TO UBOUND(Tri)) AS VectorType REDIM VertexNormal(0 TO UBOUND(Model)) AS VectorType REDIM VertexNormal2(0 TO UBOUND(Model)) AS VectorType 'Set base colors for polygons SetPolyBaseColor Tri() 'init rotation just in case, for use with calc normals RotMatrix Matrix, 0, 0, 0 RotateAndProject Model(), Matrix CalcNormals Model(), Tri(), Normal(), VertexNormal() CLS SCREEN 13 'Set up nice phong pal SetPhong16Grad Thetax = INT(RND * 360) 'random starting angles Thetay = INT(RND * 360) Thetaz = INT(RND * 360) REDIM Vpage(32009) AS INTEGER 'Clear offscreen buffer Vpage(6) = 2560 'Width 320*8 Vpage(7) = 200 'Height LAYER = VARSEG(Vpage(0)) + 1 'Buffer Seg(Ask Plasma) SetVideoSeg LAYER 'Set Draw to Buffer T# = TIMER frame& = 0 'frame counter for FPS DO K$ = INKEY$ 'user control of camera SELECT CASE UCASE$(K$) CASE "A" camz% = camz% + 1 CASE "Z" camz% = camz% - 1 CASE "S" camy% = camy% + 1 CASE "X" camy% = camy% - 1 CASE "D" camx% = camx% + 1 CASE "C" camx% = camx% - 1 CASE ELSE END SELECT frame& = frame& + 1 SetVideoSeg LAYER 'Set Draw to Buffer LINE (0, 0)-(319, 199), 0, BF 'cls Thetax = (Thetax + 1) MOD 360 'increase angles of rotation Thetay = (Thetay + 1) MOD 360 Thetaz = (Thetaz + 1) MOD 360 '''rotate object RotMatrix Matrix, Thetax, Thetay, Thetaz RotateAndProject Model(), Matrix Rotnormals VertexNormal(), VertexNormal2(), Matrix ''sort em by distance SortPolys Model(), Tri() ''draw our textured model DrawModelGour Model(), Tri(), VertexNormal2() SetVideoSeg &HA000 'set draw tfo screen WAIT &H3DA, 8 'vsynch PUT (0, 0), Vpage(6), PSET 'BitBlit LOOP UNTIL K$ = CHR$(27) 'escape"? DEF SEG 'restore current seg CLS SCREEN 0 WIDTH 80 PRINT "Fps:"; frame& / (TIMER - T#) 'print FPS C$ = INPUT$(1) 'wait for keypress... END '''Cube polygon connecting poifnts in Quad form CUBECONNECT: DATA 0, 1, 2, 3 DATA 1, 5, 6, 2 DATA 5, 4, 7, 6 DATA 4, 0, 3, 7 DATA 4, 5, 1, 0 DATA 3, 2, 6, 7 REM $STATIC SUB CalcNormals (Model() AS Point3d, ModelConnect() AS PolyType, V() AS VectorType, v2() AS VectorType) FOR i = 0 TO UBOUND(V) p1 = ModelConnect(i).p1 p2 = ModelConnect(i).p2 p3 = ModelConnect(i).p3 x1 = Model(p1).x x2 = Model(p2).x x3 = Model(p3).x y1 = Model(p1).y y2 = Model(p2).y y3 = Model(p3).y z1 = Model(p1).z z2 = Model(p2).z Z3 = Model(p3).z ax! = x2 - x1 bx! = x3 - x2 ay! = y2 - y1 by! = y3 - y2 az! = z2 - z1 bz! = Z3 - z2 'Cross product xnormal! = ay! * bz! - az! * by! ynormal! = az! * bx! - ax! * bz! znormal! = ax! * by! - ay! * bx! 'Normalize Mag! = SQR(xnormal! ^ 2 + ynormal! ^ 2 + znormal! ^ 2) IF Mag! <> 0 THEN xnormal! = xnormal! / Mag! ynormal! = ynormal! / Mag! znormal! = znormal! / Mag! END IF V(i).x = xnormal! V(i).y = ynormal! V(i).z = znormal! NEXT i 'VertexNormal FOR i = 0 TO UBOUND(Model) - 1 nx! = 0 ny! = 0 nz! = 0 count = 0 FOR j = 0 TO UBOUND(ModelConnect) IF ModelConnect(j).p1 = i OR ModelConnect(j).p2 = i OR ModelConnect(j).p3 = i THEN nx! = nx! + V(j).x ny! = ny! + V(j).y nz! = nz! + V(j).z count = count + 1 END IF NEXT j nx! = nx! / count ny! = ny! / count nz! = nz! / count 'Normalize Mag! = SQR(xnormal! ^ 2 + ynormal! ^ 2 + znormal! ^ 2) IF Mag! <> 0 THEN xnormal! = xnormal! / Mag! ynormal! = ynormal! / Mag! znormal! = znormal! / Mag! END IF v2(i).x = nx! v2(i).y = ny! v2(i).z = nz! NEXT i END SUB SUB DrawModelGour (Model() AS Point3d, Poly() AS PolyType, VtxNormal() AS VectorType) STATIC FOR j = 0 TO UBOUND(Poly) i = Poly(j).idx x1 = Model(Poly(i).p1).ScrX 'Get triangles from "projected" x2 = Model(Poly(i).p2).ScrX 'X and Y coords since Znormal x3 = Model(Poly(i).p3).ScrX 'Does not require a Z coord y1 = Model(Poly(i).p1).ScrY 'V1= Point1 connected to V2 then y2 = Model(Poly(i).p2).ScrY 'V2 to V3 and so on... y3 = Model(Poly(i).p3).ScrY 'Use the Znormal,the Ray perpendicular(Orthogonal) to the XY plane 'Defined by the Triangle (X1,Y1,X2,Y2,X3,Y3) 'if Less(<) 0 then its facing in the opposite direction so 'don't plot. If =>0 then its facing towards you so Plot. znormal = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3) IF znormal < 0 THEN nx1! = VtxNormal(Poly(i).p1).x ny1! = VtxNormal(Poly(i).p1).y nz1! = VtxNormal(Poly(i).p1).z nx2! = VtxNormal(Poly(i).p2).x ny2! = VtxNormal(Poly(i).p2).y nz2! = VtxNormal(Poly(i).p2).z nx3! = VtxNormal(Poly(i).p3).x ny3! = VtxNormal(Poly(i).p3).y nz3! = VtxNormal(Poly(i).p3).z Lx! = LightNormal.x Ly! = LightNormal.y lz! = LightNormal.z Dot1! = (nx1! * Lx!) + (ny1! * Ly!) + (nz1! * lz!) IF Dot1! < 0 THEN Dot1! = 0 ELSEIF Dot1! > 1 THEN Dot1! = 1 END IF Dot2! = (nx2! * Lx!) + (ny2! * Ly!) + (nz2! * lz!) IF Dot2! < 0 THEN Dot2! = 0 ELSEIF Dot2! > 1 THEN Dot2! = 1 END IF Dot3! = (nx3! * Lx!) + (ny3! * Ly!) + (nz3! * lz!) IF Dot3! < 0 THEN Dot3! = 0 ELSEIF Dot3! > 1 THEN Dot3! = 1 END IF Clr1 = (Dot1! * 15) Clr1 = Clr1 + Poly(i).Clr Clr2 = (Dot2! * 15) Clr2 = Clr2 + Poly(i).Clr Clr3 = (Dot3! * 15) Clr3 = Clr3 + Poly(i).Clr GouraudTri x1, y1, Clr1, x2, y2, Clr2, x3, y3, Clr3 END IF NEXT j END SUB SUB GouraudTri (ox1%, oy1%, oc1%, ox2%, oy2%, oc2%, ox3%, oy3%, oc3%) ' ' ' / ' d1 / | ' / | ' \ | ' \ |d3 ' d2 \ | ' \ | ' \| 'This implementation of the Gouraud triangle routine is 'the the fast FIXPOINT point version. 'Almost the same as a Flat Triangle routine with an added interpolation 'of the color gradients. Note the comments with '***. It means 'Addition from the Flat filler code to make it a gouraud filler code. CONST FIXPOINT = 65536 DIM x1 AS INTEGER, y1 AS INTEGER DIM x2 AS INTEGER, y2 AS INTEGER DIM x3 AS INTEGER, y3 AS INTEGER DIM c1 AS INTEGER '***colors DIM c2 AS INTEGER DIM c3 AS INTEGER DIM dx1 AS INTEGER, dy1 AS INTEGER, dc1 AS INTEGER '*** DIM dx2 AS INTEGER, dy2 AS INTEGER, dc2 AS INTEGER '*** DIM dx3 AS INTEGER, dy3 AS INTEGER, dc3 AS INTEGER '*** DIM delta1&, delta2&, delta3& DIM CDelta1&, CDelta2&, CDelta3& '*** DIM Lx&, Rx& DIM Lc&, Rc& '*** x1 = ox1% y1 = oy1% c1 = oc1% '*** x2 = ox2% y2 = oy2% c2 = oc2% '*** x3 = ox3% y3 = oy3% c3 = oc3% '*** IF y2 < y1 THEN SWAP y1, y2 SWAP x1, x2 SWAP c1, c2 '*** END IF IF y3 < y1 THEN SWAP y3, y1 SWAP x3, x1 SWAP c3, c1 '*** END IF IF y3 < y2 THEN SWAP y3, y2 SWAP x3, x2 SWAP c3, c2 '*** END IF dx1 = x2 - x1 dy1 = y2 - y1 dc1 = c2 - c1 '*** IF dy1 <> 0 THEN delta1& = dx1 * FIXPOINT \ dy1 CDelta1& = dc1 * FIXPOINT \ dy1 '*** ELSE delta1& = 0 CDelta1& = 0 '*** END IF dx2 = x3 - x2 dy2 = y3 - y2 dc2 = c3 - c2 '*** IF dy2 <> 0 THEN delta2& = dx2 * FIXPOINT \ dy2 CDelta2& = dc2 * FIXPOINT \ dy2 '*** ELSE delta2& = 0 CDelta2& = 0 '*** END IF dx3 = x1 - x3 dy3 = y1 - y3 dc3 = c1 - c3 '*** IF dy3 <> 0 THEN delta3& = dx3 * FIXPOINT \ dy3 CDelta3& = dc3 * FIXPOINT \ dy3 '*** ELSE delta3& = 0 CDelta3& = 0 '*** END IF 'Flat bottom 'Tup part of triangle Lx& = x1 * FIXPOINT Rx& = Lx& Lc& = c1 * FIXPOINT '***Left color Rc& = Lc& '***Right Color FOR y% = y1 TO y2 - 1 Tx1% = Lx& \ FIXPOINT '\ '*** Tx2% = Rx& \ FIXPOINT ' \ Parameters for GourHline subroutine col1& = Lc& ' / '*** col2& = Rc& '/ '*** GOSUB GourHline '*** Lx& = Lx& + delta1& Rx& = Rx& + delta3& Lc& = Lc& + CDelta1& '*** DDA the color grad Rc& = Rc& + CDelta3& '*** NEXT y% 'Flat top 'Lower part of triangle Lx& = x2 * FIXPOINT Lc& = c2 * FIXPOINT '*** FOR y% = y2 TO y3 Tx1% = Lx& \ FIXPOINT '*** Tx2% = Rx& \ FIXPOINT '*** col1& = Lc& '*** col2& = Rc& '*** GOSUB GourHline '*** Lx& = Lx& + delta2& Rx& = Rx& + delta3& Lc& = Lc& + CDelta2& '*** Rc& = Rc& + CDelta3& '*** NEXT y% EXIT SUB '************************************************************************** 'Draws a color gradiated horizontal line interpolated from col1 to col2 'Needed variables. ' Tx1% = integer x1 coordinate ' Tx2% = integer x2 coordinate ' y% = integer y coordinate ' Col1& = Long int of color1 *Fixpoint. In this case 2^16 ' Col2& = Ditto. '************************************************************************** GourHline: Gx1% = Tx1% 'Save values to be safe Gx2% = Tx2% yy% = y% Clr1& = col1& Clr2& = col2& IF Gx1% > Gx2% THEN 'Sort values SWAP Gx1%, Gx2% SWAP Clr1&, Clr2& END IF Gdx% = (Gx2% - Gx1%) + 1 'Get Xdelta(+1) for the Div by 0 error Cdx& = Clr2& - Clr1& 'Color delta deltac& = Cdx& \ Gdx% 'Interpolate col& = Clr1& 'save orig color to be safe FOR l% = Gx1% TO Gx2% 'Rasterizer loop PSET (l%, yy%), col& \ FIXPOINT 'Use poke for speed col& = col& + deltac& 'DDA NEXT l% RETURN END SUB SUB LoadCube (Model() AS Point3d, Poly() AS PolyType, radius) 'Generation code by: 'by Steve McCarthy(SCM) 'Tesselation by me. :*) REDIM Model(7) AS Point3d Theta! = PI / 4 dTheta! = PI / 2 FOR P = 0 TO 7 Model(P).x = radius * SGN(COS(Theta!)) ' x Model(P).y = radius * SGN(SIN(Theta!)) ' y Model(P).z = radius - (radius * 2) * (P \ 4) ' z Theta! = Theta! + dTheta! NEXT P 'Tesselate REDIM Poly(11) AS PolyType RESTORE CUBECONNECT j = 0 FOR i = 0 TO 5 READ p1, p2, p3, p4 Poly(j).p1 = p4 Poly(j).p2 = p2 Poly(j).p3 = p1 j = j + 1 Poly(j).p1 = p4 Poly(j).p2 = p3 Poly(j).p3 = p2 j = j + 1 NEXT i 'calculate vertex coords centering it FOR j = 0 TO UBOUND(Poly) u1 = 0 v1 = 0 u2 = TSIZEM1% v2 = TSIZEM1% u3 = TSIZEM1% v3 = 0 Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j j = j + 1 u1 = 0 v1 = 0 u2 = 0 v2 = TSIZEM1% u3 = TSIZEM1% v3 = TSIZEM1% Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j NEXT j END SUB SUB LoadCylinder (Model() AS Point3d, Poly() AS PolyType, radius, Slices, Bands, zdist) 'Generation code by: 'by Relsoft=me .;*) 'I. Cylindrical to cartesian '/// x = COS(theta) '/// y = SIN(theta) '/// z = z REDIM Model((Slices * Bands) - 1) AS Point3d i = 0 z! = -zdist * Slices / 2 FOR Slice = 0 TO Slices - 1 FOR Band = 0 TO Bands - 1 Theta! = (2 * PI / Bands) * Band Model(i).x = radius * COS(Theta!) Model(i).y = radius * SIN(Theta!) Model(i).z = z! i = i + 1 NEXT Band z! = z! + zdist NEXT Slice i = 0 MaxPoly = 0 FOR Slice = 0 TO Slices - 1 FOR Band = 0 TO Bands - 1 i = i + 2 MaxPoly = MaxPoly + 2 NEXT Band NEXT Slice REDIM Poly(MaxPoly) AS PolyType MaxVertex = (Slices * Bands) i = 0 FOR Slice = 0 TO Slices - 1 FOR Band = 0 TO Bands - 1 Poly(i).p1 = (Slice * Slices + Band + Slices) MOD MaxVertex Poly(i).p2 = Slice * Slices + (Band + 1) MOD Slices Poly(i).p3 = Slice * Slices + Band i = i + 1 Poly(i).p1 = (Slice * Slices + Band + Slices) MOD MaxVertex Poly(i).p2 = (Slice * Slices + (Band + 1) MOD Slices + Slices) MOD MaxVertex Poly(i).p3 = Slice * Slices + (Band + 1) MOD Slices i = i + 1 NEXT Band NEXT Slice 'calculate vertex coords centering it FOR j = 0 TO UBOUND(Poly) - 1 u1 = 0 v1 = 0 u2 = TSIZEM1% v2 = TSIZEM1% u3 = TSIZEM1% v3 = 0 Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j j = j + 1 u1 = 0 v1 = 0 u2 = 0 v2 = TSIZEM1% u3 = TSIZEM1% v3 = TSIZEM1% Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j NEXT j END SUB SUB LoadSphere (Model() AS Point3d, Poly() AS PolyType, radius, Slices, Bands) 'Generation code by: 'by Relsoft=me .;*) '/// x = p SIN(Phi) COS(theta) '/// y = p SIN(Phi) SIN(theta) '/// z = p COS(Phi) MaxVertex = (1 + Slices) * (Bands + 1) - Bands REDIM Model(MaxVertex) AS Point3d i = 0 FOR SliceLoop = 0 TO Slices Phi! = PI / Slices * SliceLoop FOR BandLoop = 0 TO Bands - 1 Theta! = 2 * PI / Bands * BandLoop Model(i).x = -INT(radius * SIN(Phi!) * COS(Theta!)) Model(i).y = -INT(radius * SIN(Phi!) * SIN(Theta!)) Model(i).z = -INT(radius * COS(Phi!)) i = i + 1 NEXT BandLoop NEXT SliceLoop i = 0 MaxPoly = 0 FOR Slice = 0 TO Slices FOR Band = 0 TO Bands - 1 i = i + 2 MaxPoly = MaxPoly + 2 NEXT Band NEXT Slice REDIM Poly(MaxPoly) AS PolyType i = 0 FOR Slice = 0 TO Slices FOR Band = 0 TO Bands - 1 Poly(i).p1 = (Slice * Slices + Band + Slices) MOD MaxVertex Poly(i).p2 = Slice * Slices + (Band + 1) MOD Slices Poly(i).p3 = Slice * Slices + Band i = i + 1 Poly(i).p1 = (Slice * Slices + Band + Slices) MOD MaxVertex Poly(i).p2 = (Slice * Slices + (Band + 1) MOD Slices + Slices) MOD MaxVertex Poly(i).p3 = Slice * Slices + (Band + 1) MOD Slices i = i + 1 NEXT Band NEXT Slice 'calculate vertex coords centering it FOR j = 0 TO UBOUND(Poly) - 1 u1 = 0 v1 = 0 u2 = TSIZEM1% v2 = TSIZEM1% u3 = TSIZEM1% v3 = 0 Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j j = j + 1 u1 = 0 v1 = 0 u2 = 0 v2 = TSIZEM1% u3 = TSIZEM1% v3 = TSIZEM1% Poly(j).u1 = u1 Poly(j).v1 = v1 Poly(j).u2 = u2 Poly(j).v2 = v2 Poly(j).u3 = u3 Poly(j).v3 = v3 Poly(j).idx = j NEXT j END SUB SUB LoadTorus (Rings, Bands, RINGRADIUS, BandRadius, Model() AS Point3d, Poly() AS PolyType) 'Generation code by Biskbart. MaxPoint% = Rings * Bands REDIM Model((MaxPoint%)) AS Point3d A1! = 2 * PI / Rings: A2! = 2 * PI / Bands i% = 0 FOR S2% = 0 TO Bands - 1 FOR S1% = 0 TO Rings - 1 x1! = COS(S1% * A1!) * RINGRADIUS y1! = SIN(S1% * A1!) * RINGRADIUS Model(i%).x = x1! + COS(S1% * A1!) * SIN(S2% * A2!) * BandRadius Model(i%).y = y1! + SIN(S1% * A1!) * SIN(S2% * A2!) * BandRadius Model(i%).z = COS(S2% * A2!) * BandRadius i% = i% + 1 NEXT S1% NEXT S2% i% = 0 MaxTri% = 0 FOR S1% = Bands - 1 TO 0 STEP -1 FOR S2% = Rings - 1 TO 0 STEP -1 i% = i% + 1 MaxTri% = MaxTri% + 1 i% = i% + 1 MaxTri% = MaxTri% + 1 NEXT S2% NEXT S1% REDIM Poly(MaxTri%) AS PolyType TT2% = 0 i% = 0 FOR S2% = Rings - 1 TO 0 STEP -1 FOR S1% = Bands - 1 TO 0 STEP -1 Poly(i%).p3 = (S1% * Rings + S2% + Rings) MOD MaxPoint% Poly(i%).p2 = S1% * Rings + (S2% + 1) MOD Rings Poly(i%).p1 = S1% * Rings + S2% C% = INT(RND * 255) + 1 Poly(i%).Clr = C% Poly(i%).u1 = TSIZE% Poly(i%).v1 = 0 Poly(i%).u2 = 0 Poly(i%).v2 = 0 Poly(i%).u3 = TSIZE% Poly(i%).v3 = TSIZE% i% = i% + 1 Poly(i%).p3 = (S1% * Rings + S2% + Rings) MOD MaxPoint% Poly(i%).p2 = (S1% * Rings + (S2% + 1) MOD Rings + Rings) MOD MaxPoint% Poly(i%).p1 = S1% * Rings + (S2% + 1) MOD Rings Poly(i%).Clr = C% Poly(i%).u1 = 0 Poly(i%).v1 = 0 Poly(i%).u2 = 0 Poly(i%).v2 = TSIZE% Poly(i%).u3 = TSIZE% Poly(i%).v3 = TSIZE% T% = (T% + 1) AND 1 i% = i% + 1 NEXT S1% TT2% = ((TT2% + 1) AND 1) NEXT S2% END SUB SUB PhongPal (Ra!, Rd!, Rs!, Ga!, Gd!, Gs!, Ba!, Bd!, Bs!, N%, col1%, col2%) Range% = col2% - col1% Angle! = PI / 2! AngleStep! = (PI / 2!) / Range% FOR i% = col1% TO col2% CosineOfAngle! = COS(Angle!) Diffuse! = Rd! * CosineOfAngle! Specular! = Rs! * (CosineOfAngle! ^ N%) red% = Ra! + Diffuse! + Specular! Diffuse! = Gd! * CosineOfAngle! Specular! = Gs! * (CosineOfAngle! ^ N%) green% = Ga! + Diffuse! + Specular! Diffuse! = Bd! * CosineOfAngle! Specular! = Bs! * (CosineOfAngle! ^ N%) blue% = Ba! + Diffuse! + Specular! IF red% > 63 THEN red% = 63 IF green% > 63 THEN green% = 63 IF blue% > 63 THEN blue% = 63 IF red% < 0 THEN red% = 0 IF green% < 0 THEN green% = 0 IF blue% < 0 THEN blue% = 0 OUT &H3C8, i% OUT &H3C9, red% OUT &H3C9, green% OUT &H3C9, blue% Angle! = Angle! - AngleStep! NEXT END SUB SUB RotateAndProject (Model() AS Point3d, M AS MatrixType) STATIC FOR i = 0 TO UBOUND(Model) x! = Model(i).x y! = Model(i).y z! = Model(i).z RotX! = (x! * M.xx + y! * M.xy + z! * M.xz) - camx% RotY! = (x! * M.yx + y! * M.yy + z! * M.yz) - camy% RotZ! = (x! * M.zx + y! * M.zy + z! * M.zz) - camz% Model(i).xr = RotX! Model(i).yr = RotY! Model(i).Zr = RotZ! 'Project Distance% = (LENS - RotZ!) IF Distance% THEN Model(i).ScrX = (LENS * RotX! / Distance%) + XCENTER Model(i).ScrY = -(LENS * RotY! / Distance%) + YCENTER ELSE END IF NEXT i END SUB SUB RotMatrix (M AS MatrixType, anglex%, angley%, anglez%) 'Precalculate the SIN and COS of each angle cx! = Lcos(anglex%) sx! = Lsin(anglex%) cy! = Lcos(angley%) sy! = Lsin(angley%) cz! = Lcos(anglez%) sz! = Lsin(anglez%) M.xx = cy! * cz! M.xy = sx! * sy! * cz! - cx! * sz! M.xz = cx! * sy! * cz! + sx! * sz! M.yx = cy! * sz! M.yy = cx! * cz! + sx! * sy! * sz! M.yz = -sx! * cz! + cx! * sy! * sz! M.zx = -sy! M.zy = sx! * cy! M.zz = cx! * cy! END SUB SUB Rotnormals (V() AS VectorType, v2() AS VectorType, M AS MatrixType) FOR i = 0 TO UBOUND(V) x! = V(i).x 'Load Original vector y! = V(i).y z! = V(i).z RotX! = (x! * M.xx + y! * M.xy + z! * M.xz) - camx% RotY! = (x! * M.yx + y! * M.yy + z! * M.yz) - camy% RotZ! = (x! * M.zx + y! * M.zy + z! * M.zz) - camz% v2(i).x = RotX! v2(i).y = RotY! v2(i).z = RotZ! NEXT i END SUB SUB SetPhong16Grad 'Sets a 16 color gradient phong palette 'change the constants if you aren't happy with the colors FOR i = 0 TO 15 Ra! = 0: Rd! = INT(RND * 150) + 25: Rs! = INT(RND * 150) + 20 Ga! = 0: Gd! = INT(RND * 150) + 25: Gs! = INT(RND * 150) + 20 Ba! = 0: Bd! = INT(RND * 150) + 25: Bs! = INT(RND * 150) + 20 N% = 8 + INT(RND * 64) PhongPal Ra!, Rd!, Rs!, Ga!, Gd!, Gs!, Ba!, Bd!, Bs!, N%, i * 16, (i * 16) + 15 NEXT i END SUB SUB SetPolyBaseColor (Poly() AS PolyType) FOR i% = 0 TO UBOUND(Poly) - 1 C% = ((i%) AND 15) * 16 Poly(i%).Clr = C% i% = i% + 1 Poly(i%).Clr = C% NEXT i% END SUB SUB SetVideoSeg (Segment) STATIC DEF SEG IF VideoAddrOff& = 0 THEN ' First time the sub is called ' We need to find the location of b$AddrC, which holds the graphics ' offset (b$OffC) and segment (b$SegC). Since b$AddrC is in the default ' segment, we can find it by setting it to a certain value, and then ' searching for that value. SCREEN 13 ' Set b$SegC to A000 (00A0 in memory) PSET (160, 100), 0 ' Set b$OffC to 7DA0 (not needed in the IDE) FOR offset& = 0 TO 32764 ' Search for b$AddrC, which is IF PEEK(offset&) = &HA0 THEN ' in the default segment and IF PEEK(offset& + 1) = &H7D THEN ' should have a value of IF PEEK(offset& + 2) = &H0 THEN ' A0 7D 00 A0. IF PEEK(offset& + 3) = &HA0 THEN VideoAddrOff& = offset& + 2 ' If we found it, record the EXIT FOR ' offset of b$SegC and quit END IF ' looking. (Oddly, changing END IF ' the b$OffC doesn't seem to END IF ' do anything, so this is why END IF ' this sub only changes b$SegC) NEXT END IF ' Change b$SegC to the specified Segment POKE VideoAddrOff&, Segment AND &HFF POKE VideoAddrOff& + 1, (Segment AND &HFF00&) \ &H100 END SUB SUB ShellSort (Poly() AS PolyType, Min, Max) 'Shell sort Algorithm ' Set comparison offset to half the number of records. offset = Max \ 2 ' Loop until offset gets to zero. DO WHILE offset > 0 Limit = Max - offset DO ' Assume no switches at this offset. Switch = FALSE ' Compare elements for the specified field and switch ' any that are out of order. FOR i = Min TO Limit - 1 Ti = Poly(i).zcenter Tj = Poly(i + offset).zcenter IF Ti > Tj THEN SWAP Poly(i).idx, Poly(i + offset).idx SWAP Poly(i).zcenter, Poly(i + offset).zcenter Switch = i END IF NEXT i ' Sort on next pass only to location where last switch was made. Limit = Switch LOOP WHILE Switch ' No switches at last offset. Try an offset half as big. offset = offset \ 2 LOOP END SUB SUB SortPolys (Model() AS Point3d, Poly() AS PolyType) FOR i% = 0 TO UBOUND(Poly) Poly(i%).zcenter = Model(Poly(i%).p1).Zr + Model(Poly(i%).p2).Zr + Model(Poly(i%).p3).Zr Poly(i%).idx = i% NEXT i% ShellSort Poly(), 0, UBOUND(Poly) + 1 END SUB