Inigo Quilez   ::     ::  
I never did anything impresive during my QBasic programming era. But at some point, once I knew C coding, I decided to come back to my old DOS programming environment and try to rotate a cube. I didn't want to use any assembler routines, so what I did was to draw the cube in wireframe and then fill the inside with the regular fill() instruction. It worked out quite ok. The nicest trick is probably that I used not the regular 13h mode (320x200x256 colors) but the mode 7 (320x200, 16 colors). That allowed me to have fast swaping routine, and also to do some nice trick. For example, as long as my 3d objects didn't have more than 16 triangles (or faces), I could assign one fixed color to each of them, and then do the shading by changing the appopiate entry in the pallete table and simulate 256 colors. Neat!


The code is bellow, I don't even want to have a look to it... Just... Enjoy if you can. I know it works, cause it still runs here in my XP machine.

DEFINT A-Z TYPE CARA c1 AS INTEGER c2 AS INTEGER c3 AS INTEGER c4 AS INTEGER END TYPE TYPE PUN2D x AS INTEGER Y AS INTEGER END TYPE TYPE PUN3D x AS SINGLE Y AS SINGLE z AS SINGLE END TYPE DECLARE FUNCTION ProyectaX (p AS PUN3D) DECLARE FUNCTION ProyectaY (p AS PUN3D) DECLARE SUB Pixel3D (p AS PUN3D, Col%) DECLARE SUB Linea3D (a AS PUN3D, b AS PUN3D, Col%) DECLARE SUB Traslada (p AS PUN3D, vect AS PUN3D) DECLARE SUB Rota (p AS PUN3D, p AS PUN3D, aX AS SINGLE, aY AS SINGLE, aZ AS SINGLE) DECLARE SUB DibujaPoly (n AS INTEGER, Col%) DECLARE SUB PoneColor (Col%, r%, v%, a%) SCREEN 7 DIM SHARED Posicion AS PUN3D DIM SHARED Vertice(0 TO 7) AS PUN3D DIM SHARED VScreen(0 TO 7) AS PUN2D DIM SHARED Poly(0 TO 5) AS CARA DIM SHARED Col(0 TO 5) AS INTEGER DIM SHARED Medio(0 TO 5) AS PUN3D DIM SHARED normal(0 TO 5) AS PUN3D DIM SHARED AuxVertice(0 TO 7) AS PUN3D DIM SHARED AuxMedio(0 TO 5) AS PUN3D DIM SHARED AuxNormal(0 TO 5) AS PUN3D DIM SHARED Orden(0 TO 5) AS INTEGER Poly(0).c1 = 3 Poly(0).c2 = 2 Poly(0).c3 = 1 Poly(0).c4 = 0 Poly(1).c1 = 4 Poly(1).c2 = 5 Poly(1).c3 = 6 Poly(1).c4 = 7 Poly(2).c1 = 0 Poly(2).c2 = 1 Poly(2).c3 = 5 Poly(2).c4 = 4 Poly(3).c1 = 1 Poly(3).c2 = 2 Poly(3).c3 = 6 Poly(3).c4 = 5 Poly(4).c1 = 2 Poly(4).c2 = 3 Poly(4).c3 = 7 Poly(4).c4 = 6 Poly(5).c1 = 3 Poly(5).c2 = 0 Poly(5).c3 = 4 Poly(5).c4 = 7 Col(0) = 1 Col(1) = 2 Col(2) = 3 Col(3) = 4 Col(4) = 5 Col(5) = 6 'cube Vertice(0).x = -20 Vertice(0).Y = -20 Vertice(0).z = -20 Vertice(1).x = 20 Vertice(1).Y = -20 Vertice(1).z = -20 Vertice(2).x = 20 Vertice(2).Y = -20 Vertice(2).z = 20 Vertice(3).x = -20 Vertice(3).Y = -20 Vertice(3).z = 20 Vertice(4).x = -20 Vertice(4).Y = 20 Vertice(4).z = -20 Vertice(5).x = 20 Vertice(5).Y = 20 Vertice(5).z = -20 Vertice(6).x = 20 Vertice(6).Y = 20 Vertice(6).z = 20 Vertice(7).x = -20 Vertice(7).Y = 20 Vertice(7).z = 20 FOR i% = 0 TO 5 DIM p1 AS PUN3D DIM p2 AS PUN3D DIM p3 AS PUN3D DIM p4 AS PUN3D DIM u AS PUN3D DIM v AS PUN3D DIM n AS PUN3D p1 = Vertice(Poly(i%).c1) p2 = Vertice(Poly(i%).c2) p3 = Vertice(Poly(i%).c3) p4 = Vertice(Poly(i%).c4) mx = (p1.x + p2.x + p3.x + p4.x) / 4 my = (p1.Y + p2.Y + p3.Y + p4.Y) / 4 mz = (p1.z + p2.z + p3.z + p4.z) / 4 Medio(i%).x = mx Medio(i%).Y = my Medio(i%).z = mz u.x = p2.x - p1.x u.Y = p2.Y - p1.Y u.z = p2.z - p1.z v.x = p3.x - p1.x v.Y = p3.Y - p1.Y v.z = p3.z - p1.z n.x = u.Y * v.z - u.z * v.Y n.Y = v.x * u.z - u.x * v.z n.z = u.x * v.Y - u.Y * v.x mo! = SQR(n.x * n.x + n.Y * n.Y + n.z * n.z) normal(i%).x = n.x / mo! normal(i%).Y = n.Y / mo! normal(i%).z = n.z / mo! NEXT i% Posicion.x = 0 Posicion.Y = 0 Posicion.z = 100 aX! = 0 aY! = 0 aZ! = 0 FOR i% = 0 TO 5 Orden(i%) = i% NEXT i% DO aX! = aX! + .01 aY! = aY! + .07 aZ! = aZ! + .05 FOR i% = 0 TO 7 Rota Vertice(i%), AuxVertice(i%), aX!, aY!, aZ! Traslada AuxVertice(i%), Posicion d! = 200 / AuxVertice(i%).z VScreen(i%).x = 160 + AuxVertice(i%).x * d! VScreen(i%).Y = 100 - AuxVertice(i%).Y * d! NEXT i% FOR i% = 0 TO 5 Rota Medio(i%), AuxMedio(i%), aX!, aY!, aZ! Traslada AuxMedio(i%), Posicion Rota normal(i%), AuxNormal(i%), aX!, aY!, aZ! NEXT i% FOR i% = 0 TO 5 FOR j% = 0 TO i% - 1 z1 = AuxMedio(Orden(i%)).z z2 = AuxMedio(Orden(j%)).z IF (z1 > z2) THEN o% = Orden(i%) Orden(i%) = Orden(j%) Orden(j%) = o% END IF NEXT j% NEXT i% SCREEN , , 1, 0 CLS FOR i% = 0 TO 5 'IF (AuxMedio(Orden(i%)).z < Posicion.z) THEN ' DibujaPoly Orden(i%), Col(Orden(i%)) 'END IF IF (AuxNormal(Orden(i%)).z > 0) THEN DibujaPoly Orden(i%), Col(Orden(i%)) END IF NEXT i% PCOPY 1, 0 LOOP WHILE INKEY$ = "" DEFSNG A-Z SUB DibujaPoly (n AS INTEGER, Col%) DIM p1 AS PUN2D DIM p2 AS PUN2D DIM p3 AS PUN2D DIM p4 AS PUN2D p1 = VScreen(Poly(n).c1) p2 = VScreen(Poly(n).c2) p3 = VScreen(Poly(n).c3) p4 = VScreen(Poly(n).c4) mx = (p1.x + p2.x + p3.x + p4.x) / 4 my = (p1.Y + p2.Y + p3.Y + p4.Y) / 4 r% = (63 * AuxNormal(n).z) CALL PoneColor(Col%, r%, .5 * r%, .5 * r%) LINE (p1.x, p1.Y)-(p2.x, p2.Y), Col% LINE (p2.x, p2.Y)-(p3.x, p3.Y), Col% LINE (p3.x, p3.Y)-(p4.x, p4.Y), Col% LINE (p4.x, p4.Y)-(p1.x, p1.Y), Col% PAINT (mx, my), Col%, Col% END SUB SUB Linea3D (a AS PUN3D, b AS PUN3D, Col%) x1 = ProyectaX(a) y1 = ProyectaY(a) x2 = ProyectaX(b) y2 = ProyectaY(b) LINE (x1, y1)-(x2, y2), Col% END SUB SUB Pixel3D (p AS PUN3D, Col%) PSET (ProyectaX(p), ProyectaY(p)), Col% END SUB SUB PoneColor (Col%, r%, v%, a%) OUT &H3C8, Col% OUT &H3C9, r% OUT &H3C9, v% OUT &H3C9, a% END SUB DEFINT A-Z FUNCTION ProyectaX (p AS PUN3D) ProyectaX = 200 * p.x / p.z END FUNCTION FUNCTION ProyectaY (p AS PUN3D) ProyectaY = 200 * p.Y / p.z END FUNCTION DEFSNG A-Z SUB Rota (ori AS PUN3D, dest AS PUN3D, aX AS SINGLE, aY AS SINGLE, aZ AS SINGLE) ' eje Y xa = COS(aY) * ori.x - SIN(aY) * ori.z za = SIN(aY) * ori.x + COS(aY) * ori.z ' eje Z dest.x = COS(aZ) * xa + SIN(aZ) * ori.Y ya = COS(aZ) * ori.Y - SIN(aZ) * xa ' eje X dest.z = COS(aX) * za - SIN(aX) * ya dest.Y = SIN(aX) * za + COS(aX) * ya END SUB SUB Traslada (p AS PUN3D, vect AS PUN3D) p.x = p.x + vect.x p.Y = p.Y + vect.Y p.z = p.z + vect.z END SUB

Enjoy your nostalgia moment :)