FLC-Dateien laden

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

kreisman

Betreff: FLC-Dateien laden

BeitragFr, Nov 20, 2009 11:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo zusammen,

da ich in der Uni einige tolle Bücher zum Thema Dateiformate entdeckt habe, musste ich sofort einige davon umsetzen. Hier das erste, welches fertig geworden ist:

FLC-Dateien sind animierte Bilddateien ähnlich einem Gif. Genaueres findet sich hier

Hier also die Funktion:

Code: [AUSKLAPPEN]

SuperStrict

Import brl.stream
Import brl.glmax2d
Import brl.d3d7max2d
Import brl.bank
Import BRL.EndianStream
Import "palette.bmx"
'Chunk-Konstanten
Const FLC_BYTE_RUN_CHUNK   :Int   = 15
Const COLOR_256_CHUNK   :Int = 4
Const DELTA_FLC_CHUNK   :Int   = 7
Rem
FLC-Dateien sind ein schönes Beispiel für einen Chunkaufbau in Dateien.
Folgender aufbau:
Header
   FrameChunk1
      SubChunk1(z.B.RunByteChunk)
      SubChunk2(z.B.Color256Chunk)
   FrameChunk2
      SubChunk1(z.B.DeltaFLCChunk)
   ...
      ...


EndRem
Function LoadFLC:TImage(url:Object,palette:Int[]=Null)
   
      
   'FLC-Header
   Local size:Int          '/* Size of FLIC including this header */
    Local Typ:Short         '/* File Type 0xAF11, 0xAF12, 0xAF30, 0xAF44, ... */
     Local frames:Short      '/* Number of frames in first segment */
    Local width:Short       '/* FLIC width in pixels */
    Local height:Short      '/* FLIC height in pixels */
     Local depth:Short       '/* Bits per pixel (usually 8) */
     Local flags:Short       '/* Set To zero Or To three */
     Local speed:Int         '/* Delay between frames */
     Local reserved1:Short   '/* Set To zero */
     Local created:Int       '/* Date of FLIC creation (FLC only) */
     Local creator:Int       '/* Serial number Or compiler id (FLC only) */
     Local updated:Int       '/* Date of FLIC update (FLC only) */
     Local updater:Int       '/* Serial number (FLC only), see creator */
     Local aspect_dx:Short   '/* Width of square rectangle (FLC only) */
     Local aspect_dy:Short   '/* Height of square rectangle (FLC only) */
     Local ext_flags:Short   '/* EGI: flags For specific EGI extensions */
     Local keyframes:Short   '/* EGI: key-image frequency */
     Local totalframes:Short '/* EGI: total number of frames (segments) */
     Local req_memory:Int    '/* EGI: maximum chunk size (uncompressed) */
     Local max_regions:Short '/* EGI: Max. number of regions in a CHK_REGION chunk */
     Local transp_num:Short  '/* EGI: number of transparent levels */
     Local reserved2:Byte[38]'/* Set To zero */
     Local oframe1:Int       '/* Offset To frame 1 (FLC only) */
    Local oframe2:Int       '/* Offset To frame 2 (FLC only) */
     Local reserved3:Byte[40]'/* Set To zero */
   
   'Chunk Header
   Local c_size:Int          '/* Size of the chunk, including subchunks */
     Local c_Type_:Short       '/* Chunk Type: 0xF1FA */
     Local chunks:Short        '/* Number of subchunks */
     Local Delay_:Short        '/* Delay in milliseconds */
     Local reserved:Short      '/* Always zero */
     Local c_width:Short         '/* Frame width override (If non-zero) */
     Local c_height:Short      '/* Frame height override (If non-zero) */
   'Hilfsvariblen
   Local stream:TStream
   Local frames_Data:TFLC_Frame[]
   Local result:TImage
   
   
   stream = LittleEndianStream(ReadStream(url)) 'Stream konvertieren
   
   'Header einlesen
   size       = ReadInt(stream)     '0x00
   typ        = ReadShort(stream)   '0x04 Signatur
   frames       = ReadShort(stream)   '0x06
   width      = ReadShort(stream)   '0x08
   height     = ReadShort(stream)   '0xA0
   depth      = ReadShort(stream)   '0xC0 Bit per Pixel
    flags      = ReadShort(stream)   '0xE0
   speed       = ReadInt(stream)   '0x10 Delay-Time
   ReadShort(stream)            '0x14 reserviert
   created    = ReadInt(stream)   '0x16 Time & Date
   creator       = ReadInt(stream)   '0x1H Seriennummer
   updated      = ReadInt(stream)   '0x1E Time & Date
   updater      = ReadInt(stream)   '0x22 Seriennummer
   aspect_dx   = ReadShort(stream)   '0x26
   aspect_dy   = ReadShort(stream)   '0x28
   stream.Readbytes(reserved2,38)   '0x2A reserviert (00)
   oframe1      = ReadInt(stream)   '0x50
   oframe2      = ReadInt(stream)   '0x54
   stream.Readbytes(reserved3,40)   '0x58 Füllbytes (00)
   'Array für die Frames vorbereiten
   frames_data = New TFLC_Frame[frames]

   result = TImage.Create(width,height,frames,MASKEDIMAGE,0,0,0)
   'Hier werden die eigentlichen Frames geladen
   Local ii:Int 'Hilfszählvariable
   
   For Local i:Int = 0 To frames+6    'Aus mir unerklärlichen Gründen sind immer 6 Frames mehr drin als
                          'Im Header definiert.
      If i = 0 Then             'Wird der erste Chunk gelesen dann existiert noch keine Palette vom Vorgängerframe.
         frames_data[ii] = TFLC_FRAME.Create(width,height,stream,Null,Null,palette)
                        
      Else
            
         frames_data[ii] = TFLC_FRAME.Create(width,height,stream,frames_data[ii-1].pix,frames_data[ii-1].ColorChunk)
         If frames_data[ii].runbyteChunk_ Then 'Immer wenn ein Runbyte chunk kommt muss der Frame davor 
            frames_data[ii-1] = frames_data[ii]'gelöscht werden (das sind die 6 Frames, die nicht zum Bild gehören)
            ii:-1
            frames_data[ii-1].runbyteChunk_ = False
         EndIf
                     
      EndIf
      result.setPixmap(ii,frames_data[ii].pix)
      ii:+1   
   Next
   
   CloseStream(stream)
   Return result
EndFunction
Rem
Klasse für einen FLC-Frame. Hier werden erst der Frame-Chunk Header gelesen, um dann die unterchunks auszulesen
Dies sind in der Regel:
   RUN_Byte_Chunk   (Komplettes Bild RLE-komprimiert gepeichert)
   Color_256_Chunk   (Palette die 256 Farben enthält, aus denen das Bild besteht)
   Delta_FLC_Chunk   (Hier werden nur die Pixel gespeichert die sich im Vergleich zum Vorgängerbild geändert haben
EndRem
Type TFLC_FRAME
   
   Field pix:TPixmap 'Der eigentliche Frame
   Field imagedata:Int[][] 'Dieser Array dient nur zum Speichern des ersten RunByteChunks
   Field ColorChunk:TCOLOR_256_CHUNK 'Chunk vom VorgängerFrame
   Field runbyteChunk_:Byte = False 'Flag ob der Frame RunByteChunk ist.
   
   Function Create:TFLC_FRAME(width:Int,height:Int,stream:TStream,oldimage:TPixmap,palette:TColor_256_Chunk,palette_civ:Int[]=Null)
   Local result:TFLC_FRAME   
   
   Local bytes:TBank 'Puffer in den alle Daten des Chunks auf einmal geladen werden
   Local prefixChunk_Size:Int,prefixChunk_Type:Short
   Local c_size:Int , c_Type_:Short , chunks:Short , runbytechunk:TFLC_RUN_BYTE_Chunk'
   Local delta:TDELTA_FLC_Chunk
   Local jumpPos:Int
      result = New TFLC_FRAME
      'Frame Header
      c_size        = ReadInt(stream)       '0x00 FrameSize in Bytes
       c_Type_       = ReadShort(stream)      '0x04 Signatur 0xF1FA (61946)
      chunks         = ReadShort(stream)      '0x06 Zahl der Chunks
                  ReadInt(stream)      'Reserviert
                  ReadInt(stream)      'reserviert   
      
      result.ColorChunk = palette 'Alte palette übergeben
      
      'Chunks im Framechunk lesen
      For Local i:Int = 1 To chunks
      
         prefixChunk_Size = ReadInt(stream)   '0x00 ChunkSize
         prefixChunk_type = ReadShort(stream)'0x04 Type (siehe Konstanten)
         
         'Den Typ der Chunks bestimmer und entsprechen einlesen
         Select prefixChunk_type
      
            Case FLC_BYTE_RUN_CHUNK
               'Den Chunk erst in den Speicher laden und dann verarbeiten
               'Sollte schneller sein als alles einzeln aus der Datei zu lesen
               bytes = TBank.Create(prefixChunk_Size-6) '6 Byte werden abgezogen, das ein Int und ein Short zum Header gehören siehe oben
               bytes.Read(stream , 0 , prefixChunk_Size-6)
               runbytechunk=TFLC_RUN_BYTE_Chunk.Create(bytes,width,height)
               result.imagedata = runbytechunk.GetImageData()
               If palette <> Null Then  'Exitstiert eine Palette, dann wird aus den Daten ein Bild erstellt
                  result.CreatePixmap()
                  result.runbyteChunk_=True 'Flag das in diesem Frame ein RunByte gelesen wurde
               EndIf
            Case COLOR_256_CHUNK    'Color_256_Chunks sind soweit ich das gesehen habe immer 772 Bytes groß
                           'Dummerweise lese ich aus der Datei immer zahlen Jenseits der 60000 Byte grenze aus
               prefixChunk_Size:-6
               If prefixChunk_Size > 772 Or prefixChunk_Size < 0 Then prefixChunk_Size=772
               'Sollte die Palette das das erste Mal geladen werden..
               If palette = Null Then
                  bytes = TBank.Create(prefixChunk_Size)
                  bytes.Read(stream,0,prefixChunk_Size)
                  result.ColorChunk=TColor_256_Chunk.Create(bytes,palette_civ)
                  
                  '... dann wird aus RunByteChunk und Palette ein Bild erstellt
                  result.CreatePixmap()
               Else
                  '... sonst kann die Palette übersprungen werden. jedenfalls bei den FLC-Dateien
                  'mit denen ich es getestet habe.
                  jumpPos = StreamPos(stream)
                  jumpPos:+prefixChunk_Size
                  SeekStream(Stream,jumppos)
               EndIf                      
            Case DELTA_FLC_CHUNK
               bytes = TBank.Create(prefixChunk_Size-6)
               bytes.Read(stream , 0 , prefixChunk_Size-6)
               delta=TDELTA_FLC_Chunk.Create(bytes,oldimage,palette,height)
               result.pix = delta.newImage 'Beim DeltaChunk wird direkt in der Pixmap geändert
            Default
            
         EndSelect
      
      Next
      If result.colorChunk = Null Then result.colorChunk = palette
      Return result
   
   EndFunction
   
   Rem
   'Hier werden die geladenen Daten in eine Pixmap umgewandelt. Diese Funktion wird eigentlich nur für den
   ersten Run_BYTE_Chunk benutz, weil die Palette für den Frame erst danach geladen wird.
   Bei der Optimierung habe ich mich an dem brl.bmploader modul orientiert.
   EndRem
   Method CreatePixmap:TPixmap()
   Local width:Int,height:Int   
   Local paldim:Int,line:Int[],debug:Int
      
      height = imagedata.dimensions()[0]-1
      width  = imagedata[0].dimensions()[0]-1
      pix=TPixmap.Create( width,height,PF_BGRA8888 )
      palDim = ColorChunk.palette.dimensions()[0]
      For Local y:Int=height-1 To 0 Step -1
         line = New Int[width]   
         For Local x:Int=0 Until width
            debug = imagedata[y][x]
            line[x]=ColorChunk.palette[imagedata[y][x]]
         Next
         ConvertPixels(line,PF_BGRA8888,pix.pixelptr(0,y),pix.format,width)
      Next   

   
   EndMethod
EndType

Type TFLC_RUN_BYTE_Chunk
   
   Field line:Int[][] 'Daten der Pixel welche Farbe aus der Palette sie habe.
      
   Function Create:TFLC_RUN_BYTE_Chunk(bytes:TBank,width:Int,height:Int)
   Local result:TFLC_RUN_BYTE_Chunk
   Local absSizeCount:Byte
   Local SizeCount:Byte,widthcounter:Int
   Local pos:Int,pixel:Byte
   'Local packetCount:Byte '/*Ignorieren*/
   
      result = New TFLC_RUN_BYTE_Chunk
      
      result.line = New Int[][height+1]
         Rem
      Im RunByteChunk kommen nach dem Header für jede PixelReihe mehrere Packete
      jedes Packet beginnt mit einem Byte...
      EndRem
      For Local y:Int = 0 To height-1
         widthcounter = 0
         pos:+1'Hier sollte der Packetcount gelesen werden dieser ist ein Relikt aus FLI-Dateien und
         'Kann ignoriert werden.
         'packetCount = PeekByte(bytes,pos);pos:+1
         result.line[y] = New Int[width]
               
         While widthcounter < width
                  
            SizeCount = PeekByte(bytes,pos);pos:+1'Packet Heade Size
            absSizeCount = (Sizecount~255)+1     'Für den Fall das es Negativ ist 2er komplemt Bilden
            Rem
            ... ist dieses Positiv ist das nächste Byte zu lesen und dessen Wert SizeCount-Mal in diese
            Pixelreihe zu füllen.(Komprimierte Packet)
            EndRem
            If sizecount <= 127 Then 'RLE Compressed
               pixel = PeekByte(bytes,pos);pos:+1
               For Local a:Int = 0 To sizecount-1
                  result.line[y][a+widthcounter] = pixel
               Next
               widthcounter:+sizecount   
            Rem
            ... ist dieses Negativ müssen die nächsten x Byte gelesen werden, wobei x gleich der Absolutwert
            von SizeCount ist.
            EndRem
            Else
                     
               For Local aa:Int = 0 To absSizeCount-1
                  
                     result.line[y][widthcounter + aa] = PeekByte(bytes,pos);pos:+1
   
               Next
               widthcounter:+absSizeCount
               EndIf
                  
            Wend
      Next      
      Return result
      
   EndFunction
   
   Method GetImageData:Int[][]()
      
      Return line
      
   EndMethod
   
EndType

Type TCOLOR_256_Chunk
   
   Field size:Int
   Field packets:Short
   Field palette:Int[]
   Field skipCount:Byte
   Field changeCount:Byte
   
   Function Create:TColor_256_Chunk(bytes:TBank,palette_civ:Int[])
   Local result:TColor_256_Chunk   
   Local r:Byte,g:Byte,b:Byte,pos:Int
         
      result = New TColor_256_Chunk
   
      result.packets    = PeekShort(bytes,0)
      result.skipCount    = PeekByte(bytes , 2)
      result.changeCount   = PeekByte(bytes , 3)
      pos = 4
      Select result.changeCount
      
         Case 0 'Einen anderen ChangeCount als 0 ist bei mir noch nie aufgetreten.
            result.palette = New Int[256]
            If palette_civ <> Null Then
               'DebugStop
               result.palette = palette_civ[..]
               pos:+63*3
               For Local c:Int = 63 To 255
                  
                  r = PeekByte(bytes , pos ) ; Pos:+ 1
                  g = PeekByte(bytes , pos ) ; Pos:+ 1
                  b = PeekByte(bytes , pos ) ; Pos:+ 1
                  If c >= 249 Then 'Aus geschwindigkeitsgründen Maske ich direkt die Pixel die ich als Maske
                           'haben möchte. In diesem Fall wär das 255 und somit Pink
                     result.palette[c] = r*$10000 + g*$100 + b
                  Else
                     result.palette[c] = 255*$1000000 +r*$10000 + g*$100 + b
                  EndIf
               Next
            
            Else
               For Local c:Int = 0 To 255
                  
                  r = PeekByte(bytes , pos ) ; Pos:+ 1
                  g = PeekByte(bytes , pos ) ; Pos:+ 1
                  b = PeekByte(bytes , pos ) ; Pos:+ 1
                  If c >= 249 Then 'Aus geschwindigkeitsgründen Maske ich direkt die Pixel die ich als Maske
                              'haben möchte. In diesem Fall wär das 255 und somit Pink
                     result.palette[c] = r*$10000 + g*$100 + b
                  Else
                     result.palette[c] = 255*$1000000 +r*$10000 + g*$100 + b
                  EndIf
               Next
            
            EndIf
         
         
         Default
         
      EndSelect
      Return result
      
   EndFunction
EndType
Rem
Der DeltaFLCChunk ist ein bisl tricky
EndRem
Type TDELTA_FLC_Chunk
   
   Field newImage:TPixmap 'Neue Pixmap in welche die Pixmap vom Vorgängerframe reinkopiert wird
   Field pos:Int      
   Field columnpos:Int      'Aktuelle SpaltenposPos in der aktuellen Reihe.
   
   
   Function Create:TDELTA_FLC_Chunk(bytes:TBank,oldimage:TPixmap,palette:TColor_256_Chunk,height:Int)
   Local result:TDELTA_FLC_Chunk,w:Int,h:Int
   Local lines:Int ,optshort:Short,optshort2:Short,skipcount:Short,packetcount:Short
   Local currentLine:Int   
      
      result = New TDELTA_FLC_Chunk
      result.newImage = oldimage.Copy()
      'Zeilen einlesen und ändern
      lines = PeekShort(bytes,result.pos);result.pos:+2    'Anzahl Zeilen
      currentLine = 0                        'Aktuelle Zeile. Wichig, da Zeilen übersprungen werden können
      While (lines > 0)

      
         optshort = PeekShort(bytes , result.pos);result.pos:+ 2
         'Am Anfang jeder Zeile steht ein oder mehrere Optionale Shorts
         'Dabei steht in diesem im 15 und 14 bit informationen, was mit diesen Shorts anzufangen ist            
         
         'The opcode is the packet count For the line, it can be zero
         'Packete auslesen            
         If (GetBit(optshort,15) = 0 And GetBit(optshort,14) = 0) Then
            If optshort = 0 DebugStop
            packetcount = optshort   
            For Local p:Int = 0 To packetcount-1
               result.ReadPacket(bytes,currentLine,packetcount,result.newImage,palette,result.newImage.width,height)   
            Next
            currentLine:+1
            lines:-1
            result.columnpos=0   
               
         'Dieser ist immer der Letzte Optionale Short. Danach folgen die Packet mit Pixeldaten
         ElseIf GetBit(optshort,15) = 0 And GetBit(optshort,14) = 1 Then
            'Diese Kombination sollte nie erreicht werden
            RuntimeError "NOOOOOOOOOOOOOOOOOOOOOOOOO" 'NOOOOOOOOOOOOOOOOOOOO
         ElseIf GetBit(optshort,15) = 1 And GetBit(optshort,14) = 0 Then
            DebugLog("optshort: (1,0)")
            'Kam bei mir noch nie vor.
            'Store the opcode's low byte (bits 0-7) in the last pixel of the line
                     
         ElseIf GetBit(optshort,15) = 1 And GetBit(optshort,14) = 1 Then
            'Der Absolutwert des Optionalen Shorts in die Anzahl Reihen die zu überspringen sind
            'DebugLog(optshort & $C000)
            skipcount = (optshort~$FFFFFFFF)+1
            currentLine:+skipcount
               
         EndIf

      Wend
      
      
      
      Return result
   EndFunction
   
   Method ReadPacket(bytes:TBank,line:Short,packets:Short,newImage:TPixmap,palette:TColor_256_Chunk,width:Int,height:Int)
   Local columnskip:Byte,column:Int
   Local RLE_Count:Byte,pixel:Byte,pixel2:Byte
       
      columnskip    = PeekByte(bytes,pos);pos:+1
      columnpos:+columnskip 'Pixwel überspringen
      RLE_Count    = PeekByte(bytes,pos);pos:+1 'Hier sind die pixel Wieder RLE-Komprimiert.
      column = columnpos
      
      If RLE_Count < $80 Then 'Ist RLE_Count Positiv x Pixel auslesen.
         For Local i:Int = 0 To RLE_Count-1
            'Gemein ist hier, dass der DELTA_FLC_CHUNK Word-orientated ist. Also in pixel 2 Byte stehen.
            'anstatt 1 Byte wie im RunByteChunk. Daher müssen die Bytes jeweils einzeln ausgelesen werden und die nächsten
            '2 Pixel ersetzt werden.
            
            'Damits schneller geht kommen die pixel direkt in die Pixmap
            If columnpos+1 < width Then
               WritePixel(newImage,columnpos,line,palette.palette[PeekByte(bytes,pos)])
               WritePixel(newImage,columnpos+1,line,palette.palette[PeekByte(bytes,pos+1)])
            EndIf
            pos:+2
            
            columnpos:+2
         Next
      Else
         'Ist der RLE_Count negativ werden die nächsten 2 Byte gelesen und x mal die nächsten 2 Pixel
         'ersetzt, wobei x der absolutbetrag von RLE_Count ist.
         pixel  = PeekByte(bytes,pos)
         pixel2 = PeekByte(bytes,pos+1);pos:+2
         For Local i:Int = 0 To (RLE_Count~255)
            
            If columnpos+1 < width Then
               WritePixel(newImage,columnpos,line,palette.palette[pixel])
               WritePixel(newImage,columnpos+1,line,palette.palette[pixel2])
            EndIf
            
            columnpos:+2
         Next
      EndIf
      
   EndMethod
EndType

'Diese Funktion ist zum Auslesen der einzelnen Bits im DeltaFLCChunk
'Mein Danke dafür geht an Bladerunner
Function GetBit:Byte(vx:Int, num:Int)
   Local test:Short   
   test = 1 Shl (num-1)     
   test = vx & test
   Return test Shr(num-1)
End Function



Zum Testen hab ich auch ein Beispiel geschrieben

Code: [AUSKLAPPEN]

SuperStrict

'Framework brl.max2d
Import "flcloader.bmx"
Import brl.glmax2d

Local img:TImage
Local time:Long,i:Int
'SetGraphicsDriver(GLMax2DDriver())

Graphics 800,600
SetMaskColor 255,0,255
img = LoadFLC("Run.flc")
If Not img RuntimeError "FLC nicht geladen werden";End
time = MilliSecs()
SetClsColor(0,0,255)

While Not KeyHit(KEY_ESCAPE)
   
   Cls
   DrawImage(img,0,0,i)
   
   If MilliSecs() - time > 100 Then
      i:+1
      time = MilliSecs()
   EndIf
   If i >=120 Then i = 0   
      
      
   Flip

Wend


hier gibt es die FLC-Datei zum Beispiel.
  • Zuletzt bearbeitet von kreisman am Di, Dez 15, 2009 21:34, insgesamt einmal bearbeitet

Arrangemonk

BeitragFr, Nov 20, 2009 15:20
Antworten mit Zitat
Benutzer-Profile anzeigen
http://udn.epicgames.com/Two/B...tions.html

das wär interessant
ingeneur

Kernle 32DLL

BeitragDi, Dez 15, 2009 9:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Echt klasse! Wenn ich darf baue ich das direkt mal in meine Engine ein Smile

Edit: Ich denke nicht das ich den Thread gepusht habe, er war doch eh noch ganz oben Shocked
Mein PC: "Bluelight" - Xtreme Gamer PC [Video]
Meine Projekte: Cube-Wars 2010 [Worklog]
Anerkennungen: 1. Platz BCC #7 , 1. Platz BCC #22 , 3. Platz BAC #89
Ich war dabei: NRW Treff III, IV ; Frankfurter BB Treffen 2009
  • Zuletzt bearbeitet von Kernle 32DLL am Di, Dez 15, 2009 9:59, insgesamt einmal bearbeitet

D2006

Administrator

BeitragDi, Dez 15, 2009 9:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Klar darfst du. Um das zu fragen hättest du den Thread nicht erst pushen müssen. Alle Codes im Archiv sind gemeinfrei, kannst sie also verwenden, wie du willst.
Intel Core i5 2500 | 16 GB DDR3 RAM dualchannel | ATI Radeon HD6870 (1024 MB RAM) | Windows 7 Home Premium
Intel Core 2 Duo 2.4 GHz | 2 GB DDR3 RAM dualchannel | Nvidia GeForce 9400M (256 MB shared RAM) | Mac OS X Snow Leopard
Intel Pentium Dual-Core 2.4 GHz | 3 GB DDR2 RAM dualchannel | ATI Radeon HD3850 (1024 MB RAM) | Windows 7 Home Premium
Chaos Interactive :: GoBang :: BB-Poker :: ChaosBreaker :: Hexagon :: ChaosRacer 2

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group