'''Code supplement for the rotation article '''This is supposed to show you how to use wireframes instead of points '''The filled cube is far from perfect as it used PAINT so I had to '''check a lower number for the z component of our projected coord. '''Pls be sure to check the code out as I will be explaing it in detail '''in the next issue of QBCM. :*) '''SetvideoSeg by Plasma357 '''Rel.betterwebber.com DECLARE SUB DrawModelHIDEFace (Model() AS ANY, Tri() AS ANY) DECLARE SUB DrawModelFill (Model() AS ANY, Tri() AS ANY) DECLARE SUB DrawModel (Model() AS ANY, Tri() AS ANY) DECLARE SUB SetVideoSeg (Segment%) DECLARE SUB RotateAndProject (Model() AS ANY, AngleX%, AngleY%, AngleZ%) DECLARE SUB LoadCube (Model() AS ANY, Tri() AS ANY, Scale!) DEFINT A-Z REM $DYNAMIC TYPE Point3d x AS SINGLE 'Normal 3d coords y AS SINGLE z AS SINGLE xr AS SINGLE 'Rotated 3d coords yr AS SINGLE zr AS SINGLE scrx AS INTEGER 'Translated and projected scry AS INTEGER '2d Coords END TYPE TYPE PolyType p1 AS INTEGER 'vertex 1 p2 AS INTEGER p3 AS INTEGER clr AS INTEGER 'color idx AS INTEGER 'index for later use END TYPE CONST FALSE = 0, TRUE = NOT FALSE CONST LENS = 256 'Z CONST XCENTER = 160 '?? CONST YCENTER = 100 '?? CONST PI = 3.14151693# REDIM SHARED Vpage(32009) AS INTEGER 'our Video buffer 'Polyhedra stuff REDIM SHARED Model(1) AS Point3d '3d Coords REDIM SHARED CubePoly(1) AS PolyType '12 faces/Polys DIM SHARED Thetax, Thetay, Thetaz 'Angle of rotation DIM SHARED camx%, camy%, camz% 'camera CLS SCREEN 0 WIDTH 80 'Initialize 3d model LoadCube Model(), CubePoly(), 1 RendMode = 0 LOCATE 1, 1 PRINT "Choose Render Type:" PRINT PRINT "1. WireFrame" PRINT "2. WireFrame + BackFace Culling" PRINT "3. Filled" K$ = INPUT$(1) SELECT CASE ASC(K$) CASE 49 RendMode = 0 'Wireframe CASE 50 RendMode = 1 'Back face culled CASE 51 RendMode = 2 'Filled CASE ELSE RendMode = 0 END SELECT CLS SCREEN 13 RANDOMIZE TIMER camx% = 0 camy% = 0 camz% = 0 Thetax = INT(RND * 360) Thetay = INT(RND * 360) Thetaz = INT(RND * 360) Vpage(6) = 2560 'GET/PUT stuuff Vpage(7) = 200 Layer = VARSEG(Vpage(0)) + 1 'Easy buffer reference SetVideoSeg Layer 'Set Draw to buffer Finished = 0 DO K$ = INKEY$ SELECT CASE UCASE$(K$) 'Camera control 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 END SELECT Thetax = (Thetax + 1) MOD 360 'rotate our angles Thetay = (Thetay + 1) MOD 360 Thetaz = (Thetaz + 1) MOD 360 RotateAndProject Model(), Thetax, Thetay, Thetaz '12 muls SetVideoSeg Layer 'set draw to Buffer LINE (0, 0)-(319, 199), 0, BF 'CLS SELECT CASE RendMode CASE 0 DrawModel Model(), CubePoly() 'WireFrame CASE 1 DrawModelHIDEFace Model(), CubePoly() 'Wire with BF culling CASE 2 DrawModelFill Model(), CubePoly() 'Filled CASE ELSE END SELECT SetVideoSeg &HA000 'Set Draw to buffer WAIT &H3DA, 8 'Vsynch PUT (0, 0), Vpage(6), PSET 'Blit LOOP UNTIL K$ = CHR$(27) CLS SCREEN 0 WIDTH 80 END 'vertices of Cube CUBEDATA: DATA 50, 50, 50 : 'x,y,z DATA -50, 50, 50 DATA -50,-50, 50 DATA 50,-50, 50 DATA 50, 50,-50 DATA -50, 50,-50 DATA -50,-50,-50 DATA 50,-50,-50 'Faces/Poly in 4 point 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 DrawModel (Model() AS Point3d, Tri() AS PolyType) STATIC FOR I = 0 TO UBOUND(Tri) j = Tri(I).idx x1 = Model(Tri(j).p1).scrx 'Get triangles from "projected" x2 = Model(Tri(j).p2).scrx 'X and Y coords since Znormal X3 = Model(Tri(j).p3).scrx 'Does not require a Z coord y1 = Model(Tri(j).p1).scry 'V1= Point1 connected to V2 then y2 = Model(Tri(j).p2).scry 'V2 to V3 and so on... Y3 = Model(Tri(j).p3).scry LINE (x1, y1)-(x2, y2), Tri(j).clr LINE -(X3, Y3), Tri(j).clr LINE -(x1, y1), Tri(j).clr NEXT I END SUB SUB DrawModelFill (Model() AS Point3d, Tri() AS PolyType) STATIC ''Draws our cube hiding the faces FOR I = 0 TO UBOUND(Tri) j = Tri(I).idx x1 = Model(Tri(j).p1).scrx 'Get triangles from "projected" x2 = Model(Tri(j).p2).scrx 'X and Y coords since Znormal X3 = Model(Tri(j).p3).scrx 'Does not require a Z coord y1 = Model(Tri(j).p1).scry 'V1= Point1 connected to V2 then y2 = Model(Tri(j).p2).scry 'V2 to V3 and so on... Y3 = Model(Tri(j).p3).scry Znormal = (x2 - x1) * (y1 - Y3) - (y2 - y1) * (x1 - X3) IF (Znormal < -256) THEN '<-256 so vector facing us 'cuz our z component is not 'normalized and paint would sometimes 'fail ;*) LINE (x1, y1)-(x2, y2), Tri(j).clr LINE -(X3, Y3), Tri(j).clr LINE -(x1, y1), Tri(j).clr xcen = (x1 + x2 + X3) \ 3 ycen = (y1 + y2 + Y3) \ 3 PAINT (xcen, ycen), Tri(j).clr END IF NEXT I END SUB SUB DrawModelHIDEFace (Model() AS Point3d, Tri() AS PolyType) STATIC ''Draws our cube hiding the faces FOR I = 0 TO UBOUND(Tri) j = Tri(I).idx x1 = Model(Tri(j).p1).scrx 'Get triangles from "projected" x2 = Model(Tri(j).p2).scrx 'X and Y coords since Znormal X3 = Model(Tri(j).p3).scrx 'Does not require a Z coord y1 = Model(Tri(j).p1).scry 'V1= Point1 connected to V2 then y2 = Model(Tri(j).p2).scry 'V2 to V3 and so on... Y3 = Model(Tri(j).p3).scry Znormal = (x2 - x1) * (y1 - Y3) - (y2 - y1) * (x1 - X3) IF (Znormal < 0) THEN '<0 so vector facing us LINE (x1, y1)-(x2, y2), Tri(j).clr LINE -(X3, Y3), Tri(j).clr LINE -(x1, y1), Tri(j).clr END IF NEXT I END SUB SUB LoadCube (Model() AS Point3d, Tri() AS PolyType, Scale!) REDIM Model(7) AS Point3d '8 vertices RESTORE CUBEDATA FOR I = 0 TO 7 READ x, y, z Model(I).x = x * Scale! 'scale it according to Model(I).y = y * Scale! 'the parameter Model(I).z = z * Scale! NEXT I REDIM Tri(11) AS PolyType j = 0 FOR I = 0 TO 5 READ p1, p2, p3, p4 Tri(j).p1 = p4 Tri(j).p2 = p2 Tri(j).p3 = p1 Tri(j).idx = j Tri(j).clr = 20 + INT(RND * 128) j = j + 1 Tri(j).p1 = p4 Tri(j).p2 = p3 Tri(j).p3 = p2 Tri(j).idx = j Tri(j).clr = 20 + INT(RND * 128) j = j + 1 NEXT I END SUB SUB RotateAndProject (Model() AS Point3d, AngleX, AngleY, AngleZ) STATIC ''Right handed system ''when camera components increase: ''x=goes left ''y=goes down ''z=goes into the screen ' so when increased: 'x =right 'y=up 'z=into you '  y ' | ' | ' | ' 0-- -- --  ' / x ' / ' / z ' \/ '''rotation: counter-clockwise of each axis ''ei. make yourself perpenicular to the axis ''wave your hand from the center of your body to the left. ''That's how it rotates. ;*) 'convert degrees to radians ax! = AngleX * PI / 180 ay! = AngleY * PI / 180 az! = AngleZ * PI / 180 'Precalculate the SIN and COS of each angle cx! = COS(ax!) sx! = SIN(ax!) cy! = COS(ay!) sy! = SIN(ay!) cz! = COS(az!) sz! = SIN(az!) '''After2 hours of work, I was able to weed out the constants from '''Rotate and project N to reduce my muls to 9 instead of 12. woot!!!! xx! = cy! * cz! xy! = sx! * sy! * cz! - cx! * sz! xz! = cx! * sy! * cz! + sx! * sz! yx! = cy! * sz! yy! = cx! * cz! + sx! * sy! * sz! yz! = -sx! * cz! + cx! * sy! * sz! zx! = -sy! zy! = sx! * cy! zz! = cx! * cy! FOR I = 0 TO UBOUND(Model) x! = Model(I).x y! = Model(I).y z! = Model(I).z RotX! = (x! * xx! + y! * xy! + z! * xz!) - camx% RotY! = (x! * yx! + y! * yy! + z! * yz!) - camy% RotZ! = (x! * zx! + y! * zy! + z! * zz!) - camz% Model(I).xr = RotX! Model(I).yr = RotY! Model(I).zr = RotZ! 'Project Distance% = (LENS - RotZ!) IF Distance% > 0 THEN Model(I).scrx = (LENS * RotX! / Distance%) + XCENTER Model(I).scry = -(LENS * RotY! / Distance%) + YCENTER ELSE END IF NEXT I END SUB SUB SetVideoSeg (Segment) STATIC 'By Plasma 357 (Jon Petrosky) 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