Raycaster(mit Texturing) objekt orientiert

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Vertex

Betreff: Raycaster(mit Texturing) objekt orientiert

BeitragSa, März 11, 2006 23:02
Antworten mit Zitat
Benutzer-Profile anzeigen
user posted image

Auf den Spuren von Wolfenstein3D und Co, wollte ich mal einen eigenen Raycaster schreiben.

Code: [AUSKLAPPEN]
Const FACE_FRONT : Byte = 1
Const FACE_BACK  : Byte = 2
Const FACE_LEFT  : Byte = 3
Const FACE_RIGHT : Byte = 4

Type TRaycaster
   Field TileSize  : Int
   Field TileCount : Int
   Field Tiles     : TTexture[]
   Field MapSize   : Int[2]
   Field Map       : Int[,]
   Field Camera    : TCamera

   Method New()
      Self.TileSize  = 64
      Self.TileCount = 0
      Self.MapSize   = [0, 0]
      Self.Camera    = Null
   End Method

   Method LoadTile:Int(URL:Object)
      Local Texture:TTexture

      Texture = TTexture.Load(URL, Self.TileSize)
      If Not Texture Then Return -1

      Self.TileCount :+ 1
      Tiles = Tiles[..Self.TileCount]
      Tiles[Self.TileCount-1] = Texture

      Return Self.TileCount
   End Method

   Method SetMapSize(Columns:Int, Rows:Int)
      Self.MapSize[0] = Columns
      Self.MapSize[1] = Rows
      Self.Map        = New Int[Columns, Rows]
   End Method

   Method SetTile(Column:Int, Row:Int, TileNr:Int)
      If (Column < 0 Or Column => Self.MapSize[0]) Or ..
         (Row < 0 Or Row => Self.MapSize[1]) Or ..
         (TileNr < 0 Or TileNr > Self.TileCount) Then Return

      Self.Map[Column, Row] = TileNr
   End Method

   Method SetCamera(Camera:TCamera)
      Self.Camera = Camera
   End Method

   Method Render()
      If Self.Camera Then Self.Camera.Render(Self)
   End Method
End Type

Type TCamera
   Field FOV        : Float
   Field Viewport   : Int[4]
   Field ClearColor : Byte[3]
   Field Position   : Float[2]
   Field Yaw        : Float
   Field Screen     : TPixmap

   Method New()
      Self.SetFOV(60.0)
      Self.SetViewport(0, 0, GraphicsWidth(), GraphicsHeight())
      Self.SetClearColor(0, 0, 0)
      Self.SetPosition(0.0, 0.0)
      Self.SetRotation(0.0)
   End Method

   Method SetFOV(FOV:Float)
      Self.FOV = FOV
   End Method

   Method SetViewport(X:Int, Y:Int, Width:Int, Height:Int)
      Self.Viewport[0] = X
      Self.Viewport[1] = Y
      Self.Viewport[2] = Width
      Self.Viewport[3] = Height
      Self.Screen      = CreatePixmap(Width, Height, PF_RGBA8888)
   End Method

   Method SetClearColor(Red:Byte, Green:Byte, Blue:Byte, Alpha:Byte=255)
      Self.ClearColor[0] = Red
      Self.ClearColor[1] = Green
      Self.ClearColor[2] = Blue
      Self.CLearColor[3] = Alpha
   End Method

   Method SetRotation(Yaw:Float)
      Self.Yaw = Yaw
   End Method

   Method Turn(DeltaYaw:Float)
      Self.Yaw :+ DeltaYaw
   End Method

   Method SetPosition(X:Float, Z:Float)
      Self.Position[0] = X
      Self.Position[1] = Z
   End Method

   Method Translate(X:Float, Z:Float)
      Self.Position[0] :+ X
      Self.Position[1] :+ Z
   End Method

   Method Move(Speed:Float)
      Self.Position[0] :+ (Cos(Self.Yaw)*Speed)
      Self.Position[1] :+ (Sin(Self.Yaw)*Speed)
   End Method

   Method Clear()
      Local X:Int, Y:Int, Offset:Byte Ptr

      Offset = Self.Screen.Pixels
      For Y = 0 Until Self.Viewport[3]
         For X = 0 Until Self.Viewport[2]
            Offset[0] = Self.ClearColor[0]
            Offset[1] = Self.ClearColor[1]
            Offset[2] = Self.ClearColor[2]
            Offset[3] = Self.ClearColor[3]

            Offset :+ 4
         Next
      Next
   End Method

   Method Render(Raycaster:TRaycaster)
      Local DeltaAngle:Float, Ray:TRay, Column:Int
      Local Dividend:Float, Height:Int
      Local Texture:TTexture, TextureColumn:Int

      ' Clear Background
      Self.Clear()

      ' Calculate Angle for one Screen-Column
      DeltaAngle = Self.FOV/Float(Self.Viewport[2])

      ' Emit Rays
      Ray = New TRay
      Ray.Angle = Self.Yaw - Self.FOV/2.0

      ' Dividend to calculate the projected Height
      Dividend = Float(Raycaster.TileSize) * ..
                 Sin(90.0-Self.FOV/2.0)*Float(Self.Viewport[2]/2)

      For Column = 0 Until Self.Viewport[2]
         Ray.Z = Self.Position[1]
         Ray.Emit(Raycaster)

         If Ray.Tile > 0 Then
            Texture = Raycaster.Tiles[Ray.Tile-1]
            Select Ray.Face
               Case FACE_FRONT
                  TextureColumn = Int(Ray.X) Mod Raycaster.TileSize

               Case FACE_BACK
                  TextureColumn = Raycaster.TileSize - (Int(Ray.X) ..
                                  Mod Raycaster.TileSize) - 1

               Case FACE_LEFT
                  TextureColumn = Raycaster.TileSize - (Int(Ray.Z) ..
                                  Mod Raycaster.TileSize) - 1

               Case FACE_RIGHT
                  TextureColumn = Int(Ray.Z) Mod Raycaster.TileSize
            End Select

            ' Correct the Fisheye-Effect
            Height = Dividend/(Ray.Distance*Cos(Self.Yaw - Ray.Angle))

            ' Draw scaled Comlumn
            Texture.DrawColumn(Column, TextureColumn, Height, Self)
         EndIf

         Ray.Angle :+ DeltaAngle
      Next

      ' Display the Result
      DrawPixmap(Self.Screen, Self.Viewport[0], Self.Viewport[1])
   End Method
End Type

Type TRay
   Field Angle    : Float
   Field X        : Float
   Field Z        : Float
   Field Tile     : Int
   Field Distance : Float
   Field Face     : Byte

   Method Emit(Raycaster:TRaycaster)
      Local DeltaX:Float, DeltaZ:Float, DX:Float, DZ:Float, TanAngle:Float
      Local Quit:Int, Face:Byte, MapColumn:Int, MapRow:Int, Tile:Int, Distance:Float
      Local OldX:Float, OldZ:Float, OldTile:Int, OldDistance:Float, OldFace:Byte

      ' 0° => Angle <= 360°
      Self.Angle = Self.Angle Mod 360.0
      If Self.Angle < 0.0 Then Self.Angle = 360.0+Self.Angle
      TanAngle = Tan(Self.Angle)

      ' Find horizontal intersection
      Quit = False
      If Self.Angle > 0.0 And Self.Angle < 180.0 Then
         DeltaZ = Float(Raycaster.TileSize)
         DeltaX = DeltaZ/TanAngle
         Self.Z = Float((Int(Raycaster.Camera.Position[1]) / ..
                  Raycaster.TileSize)*Raycaster.TileSize + Raycaster.TileSize)
         DZ     = Self.Z - Raycaster.Camera.Position[1]
         DX     = DZ/TanAngle
         Self.X = Raycaster.Camera.Position[0] + DX
         Face   = FACE_BACK

      ElseIf Self.Angle > 180.0 And Self.Angle < 360.0 Then
         DeltaZ = -Float(Raycaster.TileSize)
         DeltaX = DeltaZ/TanAngle
         Self.Z = Float((Int(Raycaster.Camera.Position[1]) / ..
                  Raycaster.TileSize)*Raycaster.TileSize)
         DZ     = Self.Z - Raycaster.Camera.Position[1]
         DX     = DZ/TanAngle
         Self.X = Raycaster.Camera.Position[0] + DX
         FACE   = FACE_FRONT

      ElseIf Self.Angle = 0.0 Or Self.Angle = 180.0
         Quit  = True

      ElseIf Self.Angle = 90.0 Then
         DeltaZ = Float(Raycaster.TileSize)
         DeltaX = 0.0
         Self.Z = Float((Int(Raycaster.Camera.Position[1]) / ..
                  Raycaster.TileSize)*Raycaster.TileSize + Raycaster.TileSize)
         Self.X = Raycaster.Camera.Position[0]
         FACE   = FACE_BACK

      ElseIf Self.Angle = 270.0 Then
         DeltaZ = -Float(Raycaster.TileSize)
         DeltaX = 0.0
         Self.Z = Float((Int(Raycaster.Camera.Position[1]) / ..
                  Raycaster.TileSize)*Raycaster.TileSize)
         Self.X = Raycaster.Camera.Position[0]
         FACE   = FACE_FRONT
      EndIf

      Tile = 0
      While Not Quit
         MapColumn = Int(Self.X)/Raycaster.TileSize
         If Self.Angle => 0.0 And Self.Angle <= 180.0 Then
            MapRow = Int(Self.Z)/Raycaster.TileSize
         ElseIf Self.Angle > 180.0 And Self.Angle < 360.0 Then
            MapRow = Int(Self.Z)/Raycaster.TileSize - 1
         EndIf

         If MapColumn < 0 Or MapColumn > Raycaster.MapSize[0] - 1 Or ..
            MapRow < 0 Or MapRow > Raycaster.MapSize[1] - 1 Then Exit

         Tile = Raycaster.Map[MapColumn, MapRow]
         If Tile > 0 Then Exit

         Self.X :+ DeltaX
         Self.Z :+ DeltaZ
      Wend

      If Tile > 0 Then
         DX = Raycaster.Camera.Position[0] - Self.X
         DZ = Raycaster.Camera.Position[1] - Self.Z
         Distance = Sqr(DX*DX + DZ*DZ)
      EndIf

      OldX        = Self.X
      OldZ        = Self.Z
      OldDistance = Distance
      OldTile     = Tile
      OldFace     = Face

      ' Find vertical intersection
      Quit = False
      If (Self.Angle > 270.0 And Self.Angle < 360.0) Or ..
         (Self.Angle > 0.0 And Self.Angle < 90.0) Then
         DeltaX = Float(Raycaster.TileSize)
         DeltaZ = TanAngle*DeltaX
         Self.X = Float(Int(Raycaster.Camera.Position[0])/Raycaster.TileSize * ..
                  Raycaster.TileSize + Raycaster.TileSize)
         DX     = Self.X - Raycaster.Camera.Position[0]
         DZ     = TanAngle*DX
         Self.Z = Raycaster.Camera.Position[1]+DZ
         Face   = FACE_RIGHT

      ElseIf Self.Angle > 90.0 And Self.Angle < 270.0 Then
         DeltaX = -Float(Raycaster.TileSize)
         DeltaZ = TanAngle*DeltaX
         Self.X = Float(Int(Raycaster.Camera.Position[0])/Raycaster.TileSize * ..
                  Raycaster.TileSize)
         DX     = Self.X - Raycaster.Camera.Position[0]
         DZ     = TanAngle*DX
         Self.Z = Raycaster.Camera.Position[1]+DZ
         Face   = FACE_LEFT

      ElseIf Self.Angle = 90.0 Or Self.Angle = 270.0 Then
         Quit = True

      ElseIf Self.Angle = 0.0 Then
         DeltaX = Float(Raycaster.TileSize)
         DeltaZ = 0.0
         Self.X = Float(Int(Raycaster.Camera.Position[0])/Raycaster.TileSize * ..
                  Raycaster.TileSize + Raycaster.TileSize)
         Self.Z = Raycaster.Camera.Position[1]
         Face   = FACE_RIGHT

      ElseIf Self.Angle = 180.0
         DeltaX = -Float(Raycaster.TileSize)
         DeltaZ = 0.0
         Self.X = Float(Int(Raycaster.Camera.Position[0])/Raycaster.TileSize * ..
                  Raycaster.TileSize)
         Self.Z = Raycaster.Camera.Position[1]
         Face   = FACE_LEFT
      EndIf

      Tile = 0
      While Not Quit   
         MapRow = Int(Self.Z)/Raycaster.TileSize
         If (Self.Angle > 270.0 And Self.Angle < 360.0) Or ..
             (Self.Angle => 0.0 And Self.Angle < 90.0) Then
            MapColumn = Int(Self.X)/Raycaster.TileSize
         ElseIf Self.Angle => 90.0 And Self.Angle <= 270.0 Then
            MapColumn = Int(Self.X)/Raycaster.TileSize - 1
         EndIf

         If MapColumn < 0 Or MapColumn > Raycaster.MapSize[0] - 1 Or ..
            MapRow < 0 Or MapRow > Raycaster.MapSize[1] - 1 Then Exit

         Tile = Raycaster.Map[MapColumn, MapRow]
         If Tile > 0 Then Exit

         Self.X :+ DeltaX
         Self.Z :+ DeltaZ
      Wend

      ' Find the shortest Distance
      If Tile > 0 Then
         DX = Raycaster.Camera.Position[0] - Self.X
         DZ = Raycaster.Camera.Position[1] - Self.Z
         Distance = Sqr(DX*DX + DZ*DZ)

         If OldTile > 0 Then
            If Distance <= OldDistance Then
               Self.Distance = Distance
               Self.Tile     = Tile
               Self.Face     = Face
            Else
               Self.Distance = OldDistance
               Self.X        = OldX
               Self.Z        = OldZ
               Self.Tile     = OldTile
               Self.Face     = OldFace
            EndIf
         Else
            Self.Distance = Distance
            Self.Tile     = Tile
            Self.Face     = Face
         EndIf
      Else
         Self.Distance = OldDistance
         Self.X        = OldX
         Self.Z        = OldZ
         Self.Tile     = OldTile
         Self.Face     = OldFace
      EndIf
   End Method
End Type

Type TTexture
   Field Height : Int
   Field Texels : Int[,]

   Method New()
      Self.Height = 0
      Self.Texels = Null
   End Method

   Method Delete()
      If Self.Texels Then MemFree(Self.Texels)
   End Method

   Method DrawColumn(X:Int, Column:Int, Height:Int, Camera:TCamera)
      Local DeltaY:Float, StartY:Int, Y:Int
      Local Texel:Int, TempY:Int, Offset:Byte Ptr

      DeltaY = Float(Self.Height)/Float(Height)
      If Height > Camera.Viewport[3] Then
         StartY = (Height - Camera.Viewport[3])/2
         Height = Camera.Viewport[3]
      Else
         StartY = 0
      EndIf

      TempY = Camera.Viewport[3]/2 - Height/2 - StartY

      For Y = StartY Until Height+StartY
         Row = Int(Float(Y)*DeltaY)

         Offset = Camera.Screen.Pixels + ..
                  (TempY+Y)*Camera.Viewport[2]*4 + X*4

         Texel = Self.Texels[Row, Column]
         Offset[2] = (Texel Shr 16) & $FF
         Offset[1] = (Texel Shr 8) & $FF
         Offset[0] = Texel & $FF
      Next
   End Method

   Function Load:TTexture(URL:Object, TileSize:Int)
      Local Pixmap:TPixmap, Texture:TTexture

      Pixmap = LoadPixmap(URL)
      If Not Pixmap Then Return Null

      Pixmap = ResizePixmap(Pixmap, TileSize, Pixmap.Height)
      Pixmap = Pixmap.Convert(PF_RGBA8888)

      Texture = New TTexture
      Texture.Height = Pixmap.Height
      Texture.Texels = New Int[Texture.Height, TileSize]
      MemCopy(Texture.Texels, Pixmap.PixelPtr(0, 0), TileSize*Texture.Height*4)

      Return Texture
   End Function
End Type


Beispiel:
Code: [AUSKLAPPEN]
SuperStrict

Framework BRL.Max2D

Import BRL.GLMax2D
Import BRL.StandardIO
Import BRL.PolledInput
Import BRL.PNGLoader

Include "Raycaster.bmx"

Global Raycaster : TRaycaster
Global Camera    : TCamera

Global MapWidth : Int
Global MapDepth : Int
Global Column   : Int
Global Row      : Int
Global Tile     : Int

Global FrameCount : Int
Global Start      : Int
Global FPS        : Int

Graphics(320, 240, 0, 0)

' Init Raycaster
Raycaster = New TRaycaster

' Load Tileset
Raycaster.LoadTile("Tile1.png")
Raycaster.LoadTile("Tile2.png")
Raycaster.LoadTile("Tile3.png")
Raycaster.LoadTile("Tile4.png")
Raycaster.LoadTile("Tile5.png")
Raycaster.LoadTile("Tile6.png")
Raycaster.LoadTile("Tile7.png")
Raycaster.LoadTile("Tile8.png")

' Read Map
RestoreData Level
ReadData MapWidth, MapDepth
Raycaster.SetMapSize(MapWidth, MapDepth)
For Row = 0 Until MapDepth
   For Column = 0 Until MapWidth
      ReadData Tile
      Raycaster.SetTile(Column, Row, Tile)
   Next
Next

' Add Camera
Camera = New TCamera
Camera.SetClearColor(30, 10, 0)
Camera.SetPosition(672.0, 672.0)
Raycaster.SetCamera(Camera)

While Not KeyDown(KEY_ESCAPE)
   If KeyDown(KEY_LEFT)  Then Camera.Turn(-1.0)
   If KeyDown(KEY_RIGHT) Then Camera.Turn( 1.0)

   If KeyDown(KEY_UP)   Then Camera.Move( 1.0)
   If KeyDown(KEY_DOWN) Then Camera.Move(-1.0)

   Raycaster.Render()

   SetColor(255, 255, 255)
   DrawText(FPS+" FPS", 10, 10)

   Flip()
   FrameCount :+ 1
   
   If MilliSecs() - Start > 999 Then
      FPS        = FrameCount
      FrameCount = 0
      Start      = MilliSecs()
   EndIf
Wend

EndGraphics()
End

#Level
DefData 20, 20
DefData 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
DefData 1, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 3, 3, 6, 6, 6, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 3, 3, 6, 6, 6, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 6, 6, 6, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 2, 2, 0, 3, 3, 6, 6, 6, 6, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1
DefData 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 1
DefData 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
DefData 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 1


Ist noch recht langsam, da ich zu faul war, die Pixmaps durch Speicherbänke zu ersetzen.

Mal schauen, ob ich noch Boden und Himmel, sowie Texturefiltering hinzufüge.

Beispiel mit Texturen und lauffähiger *.exe Datei unter Download

mfg olli
vertex.dreamfall.at | GitHub
  • Zuletzt bearbeitet von Vertex am So, März 12, 2006 18:48, insgesamt einmal bearbeitet

BtbN

BeitragSo, März 12, 2006 10:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Wow, nicht schlecht!
Bei mir läuft der Spaß zwar nur mit ~20FPS, das liegt aber eher an meinem Rechner.
Allerdings fängts arg an zu laggen, wenn ich mich ner Wand nähere.

Suco-X

Betreff: ......

BeitragSo, März 12, 2006 12:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi
Sehr schön.
Mfg Suco
Intel Core 2 Quad Q8300, 4× 2500 MHz, 4096 MB DDR2-Ram, GeForce 9600GT 512 MB

Vertex

BeitragSo, März 12, 2006 18:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke!

So, habe ihn jetzt rund 4 mal schneller gemacht. Mehr Perfomance reise ich da jetzt sicher nichtmehr heraus.

mfg olli
vertex.dreamfall.at | GitHub

Jan_

Ehemaliger Admin

BeitragMo, März 13, 2006 9:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Nett, aber ich muss zustimmen, die 200 FPS, sind wahrscheinlich nicht für normal sterbliche zu erreichen.

ich müsste das mal auf meiner GF 6800 testen, aber hier, komme ich cniht über 20 herraus. (3,2GHZ Radeon 9600 & 512 MB DDR 400)
between angels and insects

Phalastos

BeitragMo, März 13, 2006 9:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Nett, aber ich muss zustimmen, die 200 FPS, sind wahrscheinlich nicht für normal sterbliche zu erreichen.


Einfach mal die ganze Ad-Ware deinstallieren Jan. Smile

Ich habe durchgehend 76 FPS ( denke mal vSync ist aktiv ) mit einer viel schlechteren Konfiguration. ( Athlon 2200+, 512 MB Radeon 9100 64 MB )

Gruß

Alex
Forbiddenmagic - Warfare of Forgotten Power

Vertex

BeitragMo, März 13, 2006 15:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi!

Der Raycaster ist ein Softwarerenderer, somit sollte es nicht auf die Grafikkarte sondern auf den Prozessor(nichteinmal Arbeitspeicher) ankommen.

Habe einen 2,8 GHz Pentium IV.

Benutze mal statts "Import BRL.GLMax2D" "Import BRL.D3D7Max2D". Bei mir sinkt da die FPS-Rate schlagartig auf 70, aber ist denke ich Treibersache.

Hatte jetzt noch bi-lineares Texturefiltering eingebaut, ist aber noch zu lahm.

mfg olli
vertex.dreamfall.at | GitHub

DarkEvil

BeitragMi, Jun 28, 2006 0:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Also mit meinen Athlon64 3700+, Geforce 5900xt und 1GB Ram komme ich so auf 300-350 FPS im Fenster Modus.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group