FLC-Dateien laden
Übersicht

![]() |
kreismanBetreff: FLC-Dateien laden |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
http://udn.epicgames.com/Two/B...tions.html
das wär interessant |
||
ingeneur |
![]() |
Kernle 32DLL |
![]() Antworten mit Zitat ![]() |
---|---|---|
Echt klasse! Wenn ich darf baue ich das direkt mal in meine Engine ein ![]() Edit: Ich denke nicht das ich den Thread gepusht habe, er war doch eh noch ganz oben ![]() |
||
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
![]() |
D2006Administrator |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group