FreeBASIC gfx 基本 graphics 绘图
8、ScreenControl与屏幕窗口位置设置
FreeBASIC通过自建屏幕窗口摆脱了原来的屏幕模式限制,既然是窗口,在屏幕坐标中就有它的位置。ScreenControl GET_WINDOW_POS x, y 获取窗口左上角的x, y位置;ScreenControl SET_WINDOW_POS x, y则将窗口放在屏幕坐标的 x, y处,配合 ScreenEvent(@e),下面的程序在获取快速鼠标点击窗口绘图区时快速变动窗口位置并回到原处,看上去是在抖动。当判断鼠标点击的关闭窗口时,退出程序。
在Do与Loop的尾部,有一个sleep 5 毫秒的语句,让CPU更好地处理其它事件。
'' examples/manual/gfx/screencontrol.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'SCREENCONTROL'
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgScreencontrol
'' --------
'' include fbgfx.bi for some useful definitions
#include "fbgfx.bi"
'' use FB namespace for easy access to types/constants
Using FB
Dim e As Event
Dim As Long x0, y0, x, y
Dim As Integer shakes = 0
Dim As Any Ptr img
ScreenRes 320, 200, 32
Print "Click to shake window"
'' find window coordinates
ScreenControl GET_WINDOW_POS, x0, y0
Do
If (shakes > 0) Then
'' do a shake of the window
If (shakes > 1) Then
'' move window to a random position near its original coordinates
x = x0 + Int(32 * (Rnd() - 0.5))
y = y0 + Int(32 * (Rnd() - 0.5))
ScreenControl SET_WINDOW_POS, x, y
Else
'' move window back to its original coordinates
ScreenControl SET_WINDOW_POS, x0, y0
End If
shakes -= 1
End If
If (ScreenEvent(@e)) Then
Select Case e.type
'' user pressed the mouse button
Case EVENT_MOUSE_BUTTON_PRESS
If (shakes = 0) Then
'' set to do 20 shakes
shakes = 20
'' find current window coordinates to shake around
ScreenControl GET_WINDOW_POS, x0, y0
End If
'' user closed the window or pressed a key
Case EVENT_WINDOW_CLOSE, EVENT_KEY_PRESS
'' exit to end of program
Exit Do
End Select
End If
'' free up CPU for other programs
Sleep 5
Loop
9、图像的透明度处理
程序通过imagecreate创建一块像素存储内存,然后即可用circle和line在image绘RGBA格式的圆和线,它们的 A = alpha 值不同。左侧用put带参数Pset, 右侧用put 带参数alpha, 左右图的透明度发生了变化。
'' examples/manual/gfx/rgba.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'RGBA'
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgRgba
'' --------
'open a graphics screen (320 * 240, 32-bit)
ScreenRes 320, 240, 32
Dim As Any Ptr img
Dim As Integer x, y
'make an image that varies in transparency and color
img = ImageCreate(64, 64)
For x = 0 To 63
For y = 0 To 63
PSet img, (x, y), RGBA(x * 4, 0, y * 4, (x + y) * 2)
Next y
Next x
Circle img, (31, 31), 25, RGBA(0, 127, 192, 192), ,,, F 'semi-transparent blue circle
Line img, (26, 20)-(38, 44), RGBA(255, 255, 255, 0), BF 'transparent white rectangle
'draw a background (diagonal white lines)
For x = -240 To 319 Step 10
Line (x, 0)-Step(240, 240), RGB(255, 255, 255)
Next
Line (10, 10)-(310, 37), RGB(127, 0, 0), BF 'red box for text
Line (10, 146)-(310, 229), RGB(0, 127, 0), BF 'green box for Putting onto
'draw the image and some text with PSET
Draw String(64, 20), "PSet"
Put(48, 48), img, PSet
Put(48, 156), img, PSet
'draw the image and some text with ALPHA
Draw String (220, 20), "Alpha"
Put(208, 48), img, Alpha
Put(208, 156), img, Alpha
'Free the image memory
ImageDestroy img
'Keep the window open until the user presses a key
Sleep
put 最后的参数如果是 xor 则两个白色图叠加时共有部份就变成黑色。
put 后带 Pset 与 put 后带 trans 参数的区别
put 后带参数 or 的叠加图
imagecrete 三个图,用and叠加的效果
几种效果放在一起的效果图,做图方式是一样的,还是创建像素内存块,画广场然后 put 上去。
'' examples/manual/gfx/put-all.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'PUT (GRAPHICS)'
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgPutgraphics
'' --------
Declare Function checkered_blend( ByVal src As ULong, ByVal dest As ULong, ByVal param As Any Ptr ) As ULong
Screen 14, 32 '' set 320*240*32 gfx mode
Dim As Any Ptr sprite
Dim As Integer counter = 0
sprite = ImageCreate( 32, 32 ) '' allocate memory for 32x32 sprite
Line sprite, ( 0, 0 )-( 31, 31 ), RGBA(255, 0, 0, 64), bf '' draw a sprite ...
Line sprite, ( 4, 4 )-( 27, 27 ), RGBA(255, 0, 0, 192), bf
Line sprite, ( 0, 0 )-( 31, 31 ), RGB(0, 255, 0), b
Line sprite, ( 8, 8 )-( 23, 23 ), RGBA(255, 0, 255, 64), bf
Line sprite, ( 1, 1 )-( 30, 30 ), RGBA(0, 0, 255, 192)
Line sprite, ( 30, 1 )-( 1, 30 ), RGBA(0, 0, 255, 192)
Cls
Dim As Integer i : For i = 0 To 63 '' draw the background
Line( i,0 )-( i,240 ), RGB( i * 4, i * 4, i * 4 )
Next i
'' demonstrate all drawing methods ...
Put( 8,14 ), sprite, PSet
Put Step( 16,20 ), sprite, PReset
Put Step( -16,20 ), sprite, And
Put Step( 16,20 ), sprite, Or
Put Step( -16,20 ), sprite, Xor
Put Step( 16,20 ), sprite, Trans
Put Step( -16,20 ), sprite, Alpha, 96
Put Step( 16,20 ), sprite, Alpha
Put Step( -16,20 ), sprite, Add, 192
Put Step( 16,20 ), sprite, Custom, @checkered_blend, @counter
'' print a description near each demo
Draw String (100, 26), "<- pset"
Draw String Step (0, 20), "<- preset"
Draw String Step (0, 20), "<- and"
Draw String Step (0, 20), "<- or"
Draw String Step (0, 20), "<- xor"
Draw String Step (0, 20), "<- trans"
Draw String Step (0, 20), "<- alpha (uniform)"
Draw String Step (0, 20), "<- alpha (per pixel)"
Draw String Step (0, 20), "<- add"
Draw String Step (0, 20), "<- custom"
ImageDestroy( sprite ) '' free allocated memory for sprite
Sleep : End 0
'' custom blender function: chequered put
Function checkered_blend( ByVal src As ULong, ByVal dest As ULong, ByVal param As Any Ptr ) As ULong
Dim As Integer Ptr counter
Dim As ULong pixel
counter = Cast(Integer Ptr, param)
pixel = IIf(((*counter And 4) Shr 2) Xor ((*counter And 128) Shr 7), src, dest)
*counter += 1
Return pixel
End Function
用bload 将当前工作区(screenset n, 0 中的 n 区)的像素存成文件,用bsave 将像素文件装入工作区,用screencopy 将工作区的像素考贝到当前的显示区。
如果将一个位图文件装到一个工作区,在另一个工作工绘图并与位置异或,然后进行显示,往复进行异或显示,就是一幅动态的火焰列马图。
''
'' This fbgfx example deals with:
'' - palette
'' - multiple pages and double buffering
'' - direct access to the screen memory
'' - drawing to GET/PUT buffers
''
#define MAX_EXPLOSIONS 32
#define MAX_EXPLOSION_SIZE 100
#include "fbgfx.bi"
'const FALSE = 0
'const TRUE = (-1)
type EXPLOSION_TYPE
sprite as ubyte ptr
x as integer
y as integer
used as integer
count as integer
end type
sub animate_fire(byval buffer as ubyte ptr, byval new_ as integer = 0)
dim w as integer, h as integer, pitch as integer
dim c0 as integer, c1 as integer, c2 as integer, c3 as integer
dim header as FB.PUT_HEADER ptr
header = cast(FB.PUT_HEADER ptr, buffer)
w = header->width
h = header->height
pitch = header->pitch
if new_ then
line buffer, (0, 0)-(w-1, h-1), 0, bf
for i as integer = 0 to 5
circle buffer, ((w\4)+(rnd*(w\2)), (h\4)+(rnd*(h\2))), (w\6), 191,,,,F
next
else
for y as integer = 1 to h-2
for x as integer = 1 to w-2
c0 = buffer[32 + (y * pitch) + x - 1]
c1 = buffer[32 + (y * pitch) + x + 1]
c2 = buffer[32 + ((y - 1) * pitch) + x]
c3 = buffer[32 + ((y + 1) * pitch) + x]
c0 = ((c0 + c1 + c2 + c3) \ 4) - rnd*2
if (cint(c0) < 0) then c0 = 0
buffer[32 + (y * pitch) + x] = c0
next
next
end if
end sub
dim pal(256) as integer, r as integer, g as integer, b as integer
dim explosion(MAX_EXPLOSIONS) as EXPLOSION_TYPE
dim work_page as integer
screen 14, 8, 3
randomize timer
'' load image and get palette
screenset 2
bload exepath() & "/../fblogo.bmp"
palette get using pal
'' image uses first 64 colors; since we need colors 0-191, we need to move
'' these 64 colors into colors 192-255.
screenlock
dim as byte ptr pixel = screenptr()
for i as integer = 0 to (320*240)-1
pixel[i] = 192 + pixel[i]
next
screenunlock
for i as integer = 0 to 63
pal(192+i) = pal(i)
next
'' create fire palette
for i as integer = 0 to 63
pal(i) = i
pal(64+i) = &h3F or (i shl 8)
pal(128+i) = &h3F3F or (i shl 16)
next
palette using pal
'' start demo
screenset 1, 0
work_page = 1
do
screencopy 2, work_page
for i as integer = 0 to MAX_EXPLOSIONS-1
if (explosion(i).used = FALSE) and ((rnd*50) < 1) then
dim as integer size = (MAX_EXPLOSION_SIZE\4) + (rnd*((MAX_EXPLOSION_SIZE*3)/4))
with explosion(i)
.sprite = imagecreate( size, size )
.x = rnd*320
.y = rnd*240
.used = TRUE
.count = 192
end with
animate_fire( explosion(i).sprite, TRUE )
end if
if explosion(i).used then
animate_fire( explosion(i).sprite )
put (explosion(i).x, explosion(i).y), explosion(i).sprite, trans
explosion(i).count -= 1
if explosion(i).count <= 0 then
explosion(i).used = FALSE
end if
end if
next
screensync
work_page xor= 1
screenset work_page, work_page xor 1
loop while inkey = ""
10、 gfx 与 cairo 并用
gfx 绘图方便, 它本身不能显示汉字,对少量的汉字可以做成图直接 put 上去。下面的方法是在 gfx 绘图尾部,调用 cairo 的绘图能力,将文本 “显示中文” show 到需要的位置。
'' examples/manual/gfx/put-or.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'OR'
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgOrGfx
'' --------
'' Modified: Mongnewer 9, March 2024
#INCLUDE ONCE "cairo/cairo.bi"
''open a graphics window
ScreenRes 320, 200, 32
''create 3 sprites containing red, green and blue circles
Const As Long r = 32
Dim As Any Ptr cr, cg, cb
cr = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
cg = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
cb = ImageCreate(r * 2 + 1, r * 2 + 1, RGBA(0, 0, 0, 0))
Circle cr, (r, r), r, RGB(255, 0, 0), , , 1, f
Circle cg, (r, r), r, RGB(0, 255, 0), , , 1, f
Circle cb, (r, r), r, RGB(0, 0, 255), , , 1, f
''put the sprite at three different multipier
''levels, overlapping each other in the middle
Put (146 - r, 108 - r), cr, Or
Put (174 - r, 108 - r), cg, Or
Put (160 - r, 84 - r), cb, Or
''free the memory used by the sprites
ImageDestroy cr
ImageDestroy cg
ImageDestroy cb
''pause the program before closing
VAR c_s_t = cairo_image_surface_create_for_data( _
SCREENPTR, CAIRO_FORMAT_ARGB32, _
320, 200, 320 * 4)
VAR crx = cairo_create(c_s_t)
cairo_set_source_rgb(crx, 1.0, 1.0, 1.0) ' white background
cairo_move_to(crx, 10, 20)
cairo_show_text(crx, "显示中文")
Sleep
cairo_destroy(crx)
cairo_surface_destroy(c_s_t)
End 0