Buchempfehlung
Windows System Programming
Windows System Programming
Das Kompendium liefert viele interessante Informationen zur Windows-Programmierung auf Englisch. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!


Referenz - Tipps und Tricks

Referenz-Navigation

 

Double Buffering
Vermeiden Sie Double Buffering (ein Bild zuerst in einen Puffer schreiben, und es dann in den Video-RAM kopieren) soweit wie möglich. Die Gfx-Lib benutzt bereits ein Double Buffering System, um den Bildschirm zu aktualisieren. Wenn Sie Ihren eigenen Zweitpuffer verwenden, müssen nur weitere (unbenötigte) Bildschirmkopien durchgeführt werden, wodurch Ihr Programm langsamer wird. Stattdessen sollten Sie die bereits unterstützten Flipping-Funktionen (Verwendung mehrerer Bildschirmseiten; siehe BefehlsreferenzeintragSCREENSET und das Beispiel von BefehlsreferenzeintragMULTIKEY) benutzen.

Arten der Bildpuffer
BefehlsreferenzeintragGET und BefehlsreferenzeintragPUT unterstützen neben normalen BefehlsreferenzeintragArrays auch BefehlsreferenzeintragPointer als Bildpuffer:

TYPE FB_IMAGE FIELD = 1
   width AS USHORT
   height AS USHORT
   imageData(64000) AS UBYTE
END TYPE

DIM udt AS FB_IMAGE
DIM udt_ptr AS FB_IMAGE PTR
DIM array(16001) AS INTEGER
DIM array_ptr AS INTEGER PTR

udt_ptr = @udt
array_ptr = @array(0)

SCREENRES 320, 200

' Diese Anweisungen haben dieselbe Funktion
GET (0, 0)-(319, 199), array
GET (0, 0)-(319, 199), array(0)
GET (0, 0)-(319, 199), @array(0)
GET (0, 0)-(319, 199), array_ptr
GET (0, 0)-(319, 199), @array_ptr[0]

' Diese Anweisungen sind ebenfalls äquivalent zueinander
GET (0, 0)-(319, 199), @udt
GET (0, 0)-(319, 199), udt_ptr
GET (0, 0)-(319, 199), @udt_ptr[0]

In diesem Beispiel wurde GET verwendet, es funktioniert aber ebenso mit PUT.

Bildpuffer bei Drawing Primitives
Alle Drawing Primitives (einfachste Grafikanweisungen) können an GET/PUT-Puffer angewandt werden. Dadurch ist es für Sie möglich, auf eine beliebige Anzahl von nicht-Bildschirm-Oberflächen zu zeichnen, und diese später auf den Bildschirm zu übertragen:

DIM buffer(9602) AS USHORT
DIM sprite(1028) AS UBYTE
SCREENRES 320, 200

' Da als Puffer ein GET/PUT-Puffer angenommen wird,
' setzen wir seine ersten vier Bytes so, dass sie einen
' normalen GET/PUT-Puffer-header bilden.
buffer(0) = 160 SHL 3   ' Breite * 8
buffer(1) = 120     ' Höhe

CIRCLE buffer, (16, 16), 15, 12, , , 1, F
GET    buffer, ( 0,  0)-( 31,  31), sprite
PSET   sprite, (16, 16), 15
LINE   buffer, ( 0,  0)-(159, 119), 2, B
PUT    buffer, (50, 50), sprite, PSET
PUT            (80, 40), buffer, PSET

Einen einfacheren Weg, einen solchen GET/PUT-Puffer zu erstellen stellt die IMAGECREATE-Funktion dar. Durch sie wird automatisch ein Puffer reserviert und initialisiert. Das obige Beispiel könnte dadurch so aussehen:

DIM buffer AS ANY PTR
DIM sprite AS ANY PTR

SCREENRES 320, 200

buffer = IMAGECREATE(160, 120)
sprite = IMAGECREATE(32, 32)

CIRCLE buffer, (16, 16), 15, 12, , , 1, F
GET    buffer, ( 0,  0)-( 31,  31), sprite
PSET   sprite, (16, 16), 15
LINE   buffer, ( 0,  0)-(159, 119), 2, B
PUT    buffer, (50, 50), sprite, PSET
PUT            (80, 40), buffer, PSET

IMAGEDESTROY buffer
IMAGEDESTROY sprite

Wenn Sie auf einen Puffer zeichnen, werden die Koordinaten durch den letzten Aufruf von BefehlsreferenzeintragWINDOW beeinflusst, jedoch nicht von BefehlsreferenzeintragVIEW. Die Clipping-Grenzen werden auf die Gesamtgröße des Puffers gesetzt. Natürlich kann der optionale Zielpuffer-Parameter bei allen Drawing Primitives angegeben werden, und darf sowohl ein Array als auch ein Pointer sein, wie im Falle des GET/PUT-Bildpuffers.

GfxPrint
Sie können die Funktion der BefehlsreferenzeintragPRINT-Routine durch eine eigene Prozedur erweitern, die die vordefinierten Gfxlib-fonts verwendet. Das folgende Beispiel enthält die BefehlsreferenzeintragSUB GfxPrint, die das Zeichnen von transparentem Text an jeder Position sowie Clipping-Grenzen unterstützt; ebenso ist es möglich, in einen Bildpuffer zu schreiben:
Anmerkung: Dieses Beispiel funktioniert nur mit FB-Versionen <= FB0.15
Ab FB-Version 0.16 gibt es die Funktion
BefehlsreferenzeintragDRAW STRING
Für neuere FB-Versionen gibt es die DrawString-Routine (Ersatz für GfxPrint)

DECLARE SUB GfxPrint( BYREF text AS STRING, _
   BYVAL x AS INTEGER, BYVAL y AS INTEGER, _
   BYVAL col AS INTEGER, BYVAL buffer AS ANY PTR = 0 )

TYPE fb_FontType
   h AS INTEGER
   data AS UBYTE PTR
END TYPE

' Entfernen Sie das Kommentar-Zeichen vor dem
' Zeichenformat, das Sie benutzen wollen
'EXTERN fb_FontData ALIAS "fb_font_8x8" AS fb_FontType
'EXTERN fb_FontData ALIAS "fb_font_8x14" AS fb_FontType
'EXTERN fb_FontData ALIAS "fb_font_8x16" AS fb_FontType

SUB GfxPrint( BYREF text AS STRING, _
   BYVAL x AS INTEGER, BYVAL y AS INTEGER, _
   BYVAL col AS INTEGER, BYVAL buffer AS ANY PTR = 0 )

   DIM row AS INTEGER, i AS INTEGER
   DIM bits AS UBYTE PTR

   FOR i = 1 TO LEN(text)
      bits = fb_FontData.data + (ASC(MID$(text, i, 1)) * _
        fb_FontData.h)
      FOR row = 0 TO fb_FontData.h-1
         IF (buffer) THEN
            LINE buffer, (x + 7, y + row)-(x, y + row), col, _
               , *bits SHL 8
         ELSE
            LINE (x + 7, y + row)-(x, y + row), col, , *bits _
               SHL 8
         END IF
         bits += 1
      NEXT row
      x += 8
   NEXT i
END SUB

SCREENRES 320, 200
GfxPrint "Hello world!", 112, 96, 15
SLEEP

Achtung: Die GfxLib speichert alle Font- und BefehlsreferenzeintragPaletten-Daten in einem LZW-komprimierten Format, um Ihre EXEs klein zu halten, und dekomprimiert sie erst mit dem ersten BefehlsreferenzeintragSCREENRES-Aufruf. Wenn Sie BefehlsreferenzeintragSCREENRES in Ihrem Programm nie aufrufen, werden Zugriffe auf die Palette und Font-Daten unbrauchbare Daten zurückliefern.

LZW-Codec in der GfxLib
Die GfxLib speichert die Paletten- und Font-Daten in einem LZW-komprimierten Format, und entpackt diese erst, wenn zum ersten mal SCREENRES aufgerufen wird. Der LZW-Codec ist in Ihren Programmen nicht aufrufbar; er wurde nicht als eigener Befehl eingebaut. Es ist dennoch möglich, auf die Kompressonsfunktionen zuzugreifen, indem Sie die Funktionen einfach deklarieren; die Gfxlib muss jedoch durch einen SCREENRES-Aufruf aktiviert sein.

Beispiel:

DECLARE FUNCTION LZW_Encode _
   ALIAS "fb_hEncode" ( _
   BYVAL in_buffer  AS ANY PTR, _
   BYVAL in_size    AS INTEGER, _
   BYVAL out_buffer AS ANY PTR, _
   BYREF out_size   AS INTEGER _
   ) AS INTEGER

DECLARE FUNCTION LZW_Decode _
   ALIAS "fb_hDecode" ( _
   BYVAL in_buffer  AS ANY PTR, _
   BYVAL in_size    AS INTEGER, _
   BYVAL out_buffer AS ANY PTR, _
   BYREF out_size   AS INTEGER _
   ) AS INTEGER

DIM src_buffer(100000) AS UBYTE
DIM src_size AS INTEGER
DIM dest_buffer(100000) AS UBYTE
DIM dest_size AS INTEGER

' Funktioniert nur, wenn die GfxLib verwendet wird
SCREENRES 400, 300

src_size = 0
OPEN "gfxlib.txt" FOR BINARY AS #1
WHILE NOT EOF(1)
   GET #1,, src_buffer(src_size)
   src_size += 1
WEND
CLOSE #1
PRINT "Data size before compression:", src_size
GOSUB ShowData

dest_size = 100000
PRINT "Compressing...";
LZW_Encode @src_buffer(0), src_size, _
   @dest_buffer(0), dest_size
PRINT "done."

PRINT "Data size after compression:", dest_size
PRINT

src_size = 100000
PRINT "Decompressing...";
LZW_Decode @dest_buffer(0), dest_size, _
   @src_buffer(0), src_size
PRINT "done."

PRINT "Data size before decompression:", src_size
GOSUB ShowData
SLEEP
END

ShowData:
   DIM i AS INTEGER
   PRINT "Contents: ";
   FOR i = 3 TO 36: PRINT CHR$(src_buffer(i)); : NEXT
   PRINT " [...]"
RETURN

OpenGL-Textur
Das Erstellen einer OpenGL-Textur mit einem GET/PUT-Puffer ist einfach; hier ist ein kleiner Codeauszug, der diese Aufgabe erledigt:

#DEFINE TEX_MASKED   &h1
#DEFINE TEX_MIPMAP   &h2
#DEFINE TEX_NOFILTER &h4
#DEFINE TEX_HASALPHA &h8

FUNCTION CreateTexture( BYVAL buffer AS ANY PTR, _
   BYVAL flags AS INTEGER = 0 ) AS GLuint
   REDIM dat(0) AS UBYTE
   DIM p AS UINTEGER PTR, s AS USHORT PTR
   DIM AS INTEGER w, h, x, y, col
   DIM tex AS GLuint
   DIM AS GLenum format, minfilter, magfilter

   CreateTexture = 0

   s = buffer
   w = s[0] SHR 3
   h = s[1]

   IF( (w < 64) OR (h < 64) ) THEN
      EXIT FUNCTION
   END IF
   IF( (w AND (w-1)) OR (h AND (h-1)) ) THEN
      '' Width/height not powers of 2
      EXIT FUNCTION
   END IF

   REDIM dat(w * h * 4) AS UBYTE
   p = @dat(0)

   glGenTextures 1, @tex
   glBindTexture GL_TEXTURE_2D, tex

   FOR y = h-1 TO 0 STEP -1
      FOR x = 0 TO w-1
         col = POINT(x, y, buffer)
         ' Swap R and B so we can use the GL_RGBA texture format
         col = RGBA(col AND &hFF, _
            (col SHR  8) AND &hFF, _
            (col SHR 16) AND &hFF, _
             col SHR 24)
         IF( flags AND TEX_HASALPHA ) THEN
            *p = col
         ELSE
            IF( (flags AND TEX_MASKED) AND (col = &hFF00FF) ) THEN
               *p = 0
            ELSE
               *p = col OR &hFF000000
            END IF
         END IF
         p += 4
      NEXT x
   NEXT y

   IF( flags AND ( TEX_MASKED OR TEX_HASALPHA ) ) THEN
      format = GL_RGBA
   ELSE
      format = GL_RGB
   END IF

   IF( flags AND TEX_NOFILTER ) THEN
      magfilter = GL_NEAREST
   ELSE
      magfilter = GL_LINEAR
   END IF

   IF( flags AND TEX_MIPMAP ) THEN
      gluBuild2DMipmaps GL_TEXTURE_2D, format, w, _
         h, GL_RGBA, GL_UNSIGNED_BYTE, @dat(0)
      IF( flags AND TEX_NOFILTER ) THEN
         minfilter = GL_NEAREST_MIPMAP_NEAREST
      ELSE
         minfilter = GL_LINEAR_MIPMAP_LINEAR
      END IF
   ELSE
      glTexImage2D GL_TEXTURE_2D, 0, format, w, _
         h, 0, GL_RGBA, GL_UNSIGNED_BYTE, @dat(0)
      minfilter = magfilter
   END IF
   glTexParameteri GL_TEXTURE_2D, _
      GL_TEXTURE_MIN_FILTER, minfilter
   glTexParameteri GL_TEXTURE_2D, _
      GL_TEXTURE_MAG_FILTER, magfilter

   CreateTexture = tex

END FUNCTION

Zusätzliche Informationen und Funktionen
  • Der Referenzeintrag wurde am 06.08.2007 von RedakteurVolta angelegt.
  • Die aktuellste Version wurde am 17.08.2011 von Redakteurnemored gespeichert.
  Versionen Versionen