Buchempfehlung
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
"Der" Petzold, das über 1000 Seiten starke Standardwerk zum Win32-API - besonders nützlich u. a. bei der GUI-Programmierung in FreeBASIC! [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

 

Achtung: Dieser Abschnitt richtet sich an fortgeschrittene Programmierer, die einen tieferen Einblick in die Verwaltung von Grafikpuffern erhalten wollen. Er behandelt folgende Themen:



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 Gfxlib benutzt bereits ein Double-Buffering-System, um den Bildschirm zu aktualisieren. Wenn Sie Ihren eigenen Zweitpuffer verwenden, müssen nur weitere (unnötige) 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 Grafikpuffer
BefehlsreferenzeintragGET und BefehlsreferenzeintragPUT unterstützen neben normalen BefehlsreferenzeintragArrays auch BefehlsreferenzeintragPointer als Grafikpuffer:

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(16008) 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]
SLEEP

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


Grafikpuffer bei Drawing Primitives
Alle Drawing Primitives (einfachste Grafikanweisungen wie BefehlsreferenzeintragLINE, BefehlsreferenzeintragCIRCLE usw.) können an Grafikpuffer 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.

Beispiel:

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

' Da als Puffer ein Grafikpuffer angenommen wird,
' setzen wir seine ersten vier Bytes so, dass sie einen
' normalen Grafikpuffer-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
SLEEP

Einen einfacheren Weg, einen solchen Grafikpuffer zu erstellen stellt die Funktion BefehlsreferenzeintragIMAGECREATE dar. Durch sie wird automatisch ein Puffer der richtigen Größe reserviert und sein Header initialisiert. Das obige Beispiel könnte dadurch so aussehen:

Beispiel: Grafikpuffer mit IMAGECREATE reservieren

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
SLEEP

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. Der optionale Zielpuffer-Parameter kann bei allen Drawing Primitives angegeben werden und darf sowohl ein Array als auch ein Pointer sein, wie im Falle des Grafikpuffers.


GfxPrint
Um einen transparenten Text pixelgenau an einer beliebigen Fensterposition auszugeben, dient der Befehl BefehlsreferenzeintragDRAW STRING. Vor FreeBASIC v0.16 existierte dieser Befehl noch nicht, konnte jedoch durch eine eigene Routine ersetzt werden. 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 Grafikpuffer zu schreiben.

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
  w As INTEGER
  h AS INTEGER
  data AS UBYTE PTR
END TYPE

ENUM
  FB_FONT_8 = 0,
  FB_FONT_14,
  FB_FONT_16,
  FB_FONT_COUNT
END ENUM

EXTERN __fb_font(0 to FB_FONT_COUNT-1) ALIAS "__fb_font" AS fb_FontType

' Entfernen Sie das Kommentar-Zeichen vor dem
' Zeichenformat, das Sie benutzen wollen
'#DEFINE fb_FontData (__fb_font(FB_FONT_8))
'#DEFINE fb_FontData (__fb_font(FB_FONT_14))
'#DEFINE fb_FontData (__fb_font(FB_FONT_16))

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 Kompressionsfunktionen 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

DECLARE SUB showData(buffer() AS UBYTE)

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 "test.bas" 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
ShowData src_buffer()

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
ShowData src_buffer()
SLEEP
END

SUB showData(buffer() AS UBYTE)
  DIM i AS INTEGER
  PRINT "Contents: ";
  FOR i = 3 TO 36: PRINT CHR(buffer(i)); : NEXT
  PRINT " [...]"
END SUB



OpenGL-Textur
Das Erstellen einer OpenGL-Textur mit einem Grafikpuffer 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

#INCLUDE ONCE "GL/gl.bi"
#INCLUDE ONCE "GL/glu.bi"

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
    ' Breite oder Höhe keine Potenz von 2
    EXIT FUNCTION
  END IF

  REDIM dat(w * h * 4) AS UBYTE
  p = CAST(UINTEGER PTR, @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)
      ' vertausche R und B, um das GL_RGBA-Texturformat zu nutzen
      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 19.01.2013 von RedakteurMOD gespeichert.
  Versionen Versionen