Code archives/Graphics/3D Engine
This code has been declared by its author to be Public Domain code.
Download source code
| Simple 3D engine with linear texturemapping (for Blitz 2D) |
; Demo: Framework for a simplyfied 3D Engine featuring linear Texturemapping. ; Minor bugs. Supports Quads only. Someone should add Perspective Correction. ; Z-order by Quads and not by Pixel. Goodie: Renderer is using only Integers! ; No "hidden Quads removal" Function implemented yet - depends heavily on usage... ; Send obscene amounts of cash to howaboutpeace@utopia.gov j/k. Enjoy! ; Credits go to Toshi - thx for his Qbasic Texture Mapper (I removed all Floats) and ; to ParanoidPete and to some other PPL who are writing 3D-tutorials all the time. ; PS: Funny: I got "fps: INFINITY" in Fullscreen Mode :) ... Move the Mouse to Zoom in. Graphics 320,240,16,2 SetBuffer BackBuffer() ; -- init texturemapper texturefile$="texture256.jpg" If FileType(texturefile$)=1 Then ; if it exists then load it... txt=LoadImage(texturefile$); use any 256*256 pixel texture Else txt=CreateImage(256,256) ; else create one on the fly SetBuffer ImageBuffer(txt) For i=0 To 255 Color i,255-i,0 Line 255-i,0,255,i Color 255,255-i,255-i Line 0,255-i,i,255 Next SetBuffer BackBuffer() EndIf Global imgtxt=ImageBuffer(txt) Dim Lefttable%(480, 2), Righttable%(480, 2) ;Scan converter tables (make shure to reserve enough) Dim Polypoints%(3, 1) ; Array for polygon co-ords, 4 pairs(x,y) co -ords Global Miny%, Maxy% Global Pwidth%, Pheight% Pwidth = 255 Shl 16 ;original picture width in pixels -1 shl 16 Pheight = 255 Shl 16 ;original picture height in pixels -1 shl 16 ; eo init texturemapper Dim zbuffer(10000) ; maximum of 10k Quads (don't worry, would be too slow anyway :) ) ; Read in a mesh Restore building Read anz Dim xwww(anz),ywww(anz),zwww(anz) Dim xw(anz),yw(anz),zw(anz) For i=0 To anz Read xwww(i) Read ywww(i) Read zwww(i) Next a=0 alpha=1 beta=1 gamma=1 zoom=-500 ; better alter "mausy#" to zoom in (see below) ; MMMMMMMMMMMMMMMMMMMMMMMMMmmmmmain While KeyDown(1)=0 Miny% = 32767 ;set initial smallest y co-ord of polygon After rotation Maxy% = 0 ;set initial largest y co-ord of polygon After rotation ; calc frames per second tt=MilliSecs() fps#=1000.0/(tt-ttold) fpsadd#=fpsadd#+fps# fpscount=fpscount+1 If fpscount>19 Then fpsreal#=fpsadd#/20 fpsadd#=0 fpscount=0 EndIf ttold=tt ; eo calc fps ; Cls Color 0,0,0 Rect 0,0,320,240,1 a=a+1.0 ; automatic rotation... If a>359.9 Then a=0 alpha=a beta=a gamma=a+a Mod 360 mausy#=0.1+(MouseY()/50.0) ; the renderer is working with rotated Copies of the original Points to prevent degeneration by Floating Inaccuracy For i=0 To anz ; rotate pitch, roll and yaw xl1#=zwww(i)*Sin(gamma)+xwww(i)*Cos(gamma) yl1#=ywww(i) zl1#=zwww(i)*Cos(gamma)-xwww(i)*Sin(gamma) xl2#=xl1 yl2#=yl1*Cos(beta)-zl1*Sin(beta) zl2#=yl1*Sin(beta)+zl1*Cos(beta) xl3#=(yl2*Sin(alpha)+xl2*Cos(alpha)) yl3#=(yl2*Cos(alpha)-xl2*Sin(alpha)) zl3#=(zl2) ; Projecting 3D to 2D If yloc# - Zoom <> 0 Then yloc = Int(yl3 ) * 200 / (zl3 - Zoom) If xloc# - Zoom <> 0 Then xloc = Int(xl3 ) * 200 / (zl3 - Zoom) xw(i)=((mausy#)*xloc) +160 yw(i)=((mausy#)*yloc) +120 zw(i)=(zl3+256) ; remember this for Z-sorting Next ; z-sorting... For i=0 To 10000 zbuffer(i)=-1 ; wipe out old zbuffer info (could be optimized) Next For i=0 To anz-3 Step 4 If zw(i)>=0 ; clip Quads behind Camera zwmax=zw(i) If zwmax<zw(i+1) Then zwmax=zw(i+1) If zwmax<zw(i+2) Then zwmax=zw(i+2) If zwmax<zw(i+3) Then zwmax=zw(i+3) While zbuffer(zwmax)<>-1 And zwmax<10000 ; find next free slot zwmax=zwmax+1 Wend zbuffer(zwmax)=i EndIf Next LockBuffer ImageBuffer(txt) LockBuffer BackBuffer() For i2=10000 To 0 Step -1 ; reading quads in z-order from far to near i=zbuffer(i2) If i>-1 And i< anz-2 ; if it isn't -1 then it's a Quad Point 1 ID ; Mapping... GetPolygonPoints(i) FindSmallLargeY() ; Send polygon points To the scan converter X1% = Polypoints%(0, 0) Y1% = Polypoints%(0, 1) X2% = Polypoints%(1, 0) Y2% = Polypoints%(1, 1) ScanConvert(X1%, Y1%, X2%, Y2%, 1) ;scan top of picture X1% = Polypoints%(1, 0) Y1% = Polypoints%(1, 1) X2% = Polypoints%(2, 0) Y2% = Polypoints%(2, 1) ScanConvert(X1%, Y1%, X2%, Y2%, 2) ;scan Right of picture X1% = Polypoints%(2, 0) Y1% = Polypoints%(2, 1) X2% = Polypoints%(3, 0) Y2% = Polypoints%(3, 1) ScanConvert(X1%, Y1%, X2%, Y2%, 3) ;scan bottom of picture X1% = Polypoints%(3, 0) Y1% = Polypoints%(3, 1) X2% = Polypoints%(0, 0) Y2% = Polypoints%(0, 1) ScanConvert(X1%, Y1%, X2%, Y2%, 4) ;scan Left of picture TextureMap() ; eo mapping EndIf Next UnlockBuffer BackBuffer() UnlockBuffer ImageBuffer(txt) Color 255,255,255 Text 0,0,"fps "+fpsreal# Flip 0 Wend End ; --- texture mapping functions Function GetPolygonPoints(ilocal%) ; initially read in a rectangle For Count% = 0 To 3 Polypoints%(Count%, 0) = xw(ilocal%+Count%) Polypoints%(Count%, 1) = yw(ilocal%+Count%) Next End Function Function FindSmallLargeY() For Count% = 0 To 3 Ycoord% = Polypoints%(Count%, 1) If Ycoord% < Miny% Then ; is this the New lowest y co-ord? Miny% = Ycoord% ; Yes... End If If Ycoord% > Maxy% Then ; is this the New highest y co-ord? Maxy% = Ycoord% ; Yes... End If Next End Function Function ScanConvert (X1%, Y1%, X2%, Y2%, Pside) ; This procedure takes as defined by X1%,Y1%,x2,Y2%. ; It also takes a var telling it which side of the picture we are ; mapping. The var are 1,2,3,4 for top,Right,bottom,Left. This routine decides ; which ;side; of the polygon the Line is on, And Then calls the ; appropriate routine. If Y2% < Y1% Then temp%=X1% : X1%=X2% : X2%=temp% temp%=Y1% : Y1%=Y2% : Y2%=temp% Lineheight% = (Y2% - Y1%) ScanLeftSide(X1%, X2%, Y1%, Lineheight%, Pside) Else Lineheight% = (Y2% - Y1%) ScanRightSide(X1%, X2%, Y1%, Lineheight%, Pside) End If End Function Function ScanLeftSide (X1%, X2%, Ytop%, Lineheight%, Pside) ; This procedure calculates the x points for the Left side of the ; polygon. It also calculates the x,y co-ords of the picture For the Left ; side of the polygon. Lineheight% = Lineheight% + 1 ; prevent divide by zero Xadd = (X2% - X1%) Shl 16 Xadd = Xadd / Lineheight% If Pside = 1 Then Px = Pwidth% - 1 Py = 0 Pxadd = -Pwidth% / Lineheight% Pyadd = 0 End If If Pside = 2 Then Px = Pwidth% Py = Pheight% Pxadd = 0 Pyadd = -Pheight% / Lineheight% End If If Pside = 3 Then Px = 0 Py = Pheight% Pxadd = Pwidth% / Lineheight% Pyadd = 0 End If If Pside = 4 Then Px = 0 Py = 0 Pxadd = 0 Pyadd = Pheight% / Lineheight% End If x = X1% Shl 16 For y% = 0 To Lineheight% Ytopy%=Ytop%+y% If Ytopy%<0 Then Ytopy%=0 Lefttable(Ytopy%, 0) = x Sar 16 ;polygon x Lefttable(Ytopy%, 1) = Px ;picture x Lefttable(Ytopy%, 2) = Py ;picture y x = x + Xadd ;Next polygon x Px = Px + Pxadd ;Next picture x Py = Py + Pyadd ;Next picture y Next End Function Function ScanRightSide (X1%, X2%, Ytop%, Lineheight%, Pside) ; This procedure calculates the x points For the Right side of the ; ; polygon. It also calculates the x,y co-ords of the picture For the ; Right side of the polygon. Lineheight% = Lineheight% + 1 ; No divide by zero Xadd = (X2% - X1%) Shl 16 Xadd = Xadd / Lineheight% If Pside = 1 Then Px = 0 Py = 0 Pxadd = Pwidth% / Lineheight% Pyadd = 0 End If If Pside = 2 Then Px = Pwidth% Py = 0 Pxadd = 0 Pyadd = Pheight% / Lineheight% End If If Pside = 3 Then Px = Pwidth% Py = Pheight% Pxadd = -Pwidth% / Lineheight% Pyadd = 0 End If If Pside = 4 Then Px = 0 Py = Pheight% Pxadd = 0 Pyadd = -Pheight% / Lineheight% End If x = X1% Shl 16 For y% = 0 To Lineheight% Ytopy%=Ytop%+y% If Ytopy%<0 Then Ytopy%=0 Righttable(Ytopy%, 0) = x Sar 16 ;polygon x Righttable(Ytopy%, 1) = Px ;picture x Righttable(Ytopy%, 2) = Py ;picture y x = x + Xadd ;Next polygon x Px = Px + Pxadd ;Next picture x Py = Py + Pyadd ;Next picture y Next End Function Function TextureMap() ; This is the actual mapping routine. Only linerar mapping, no perspective correction :/ ; It takes the co-ords that have been calculated by the scan converter ; And 'traces' across the original picture in between them looking at ; the pixel Color And Then plotting a pixel in that Color in the ; current position within the polygon. ; If you were able to optimze this in speed or accuracy then please let us know. For y% = Miny% To Maxy% If y>0 And y<=239 ; clipping y Polyx1% = Lefttable((y%), 0) ;get Left polygon x Px1 = Lefttable(y%, 1) ;get Left picture x Py1 = Lefttable(y%, 2) ;get Left picture y Polyx2% = Righttable((y%), 0) ;get Right polygon x Px2 = Righttable(y%, 1) ;get Right picture x Py2 = Righttable(y%, 2) ;get Right picture y Linewidth% = Polyx2% - Polyx1% ;what is the width of this polygon Line Linewidth%=Linewidth% Or 1 ;prevent divide by zero Pxadd = ((Px2 - Px1)) / Linewidth% ;squash picture xdist into poly xdist Pyadd = ((Py2 - Py1)) / Linewidth% ;squash picture ydist into poly ydist For x% = Polyx1% To Polyx2% If x>0 And x<=319 ; clipping x Col%=ReadPixelFast((Px1 Shr 16),(Py1 Shr 16),imgtxt) WritePixelFast x%,y%,Col% EndIf Px1 = Px1 + Pxadd ; move x picture co-ord Py1 = Py1 + Pyadd ; move y picture co-ord Next EndIf Next End Function ; eo texture mapping functions .building ; a simple cube mesh: 24 Points (unshared Vertices) and 6 Quads (must be clockwise): ; (Of course you could implement a Loading Function as well) Data 23 ; number of pts -1 ; x y z 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 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 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 |