Mint_21.3 drawing-area和goocanvas的FB笔记(八)

文章介绍了使用FreeBASIC与TinyPTC库进行图形绘制的过程,包括TinyPTC的版本差异、编译步骤,以及如何在FreeBASIC示例中集成TinyPTC绘制文本和图像。还提到了TinyPTC的局限性和与SDL和Cairo的对比,以及作者对TinyPTC进行改造以支持中文显示的尝试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FreeBASIC与TinyPTC绘图

TinyPTC是个操作非常简单的库,有各平台用的版本,linux平台版本又分为sdl版和gfx版,gfx版本比sdl版本速度快,尺寸不大,可操作的函数只有3个:

ptc_open,  ptc_update,  ptc_close

sdl版本增加了一个回调函数 ptc_cleanup_callback , 在TinyPTC即将结束前的回调。gfx版本增加了像素格式转换,用asm写的,nasm编译,ar\as处理,但没实际意义、只是放在了那里,编译mmx.s和yvs12.s与gcc的其它.o不能链接成 .a 库,修改Makefiles配置文件将AOBJECTS去掉即可。

FreeBASIC有它的.bi头文件,但没有它的.a库,所以需要自己编译(系统上要有gcc, make工具链)。对TinyPTC-SDL-0.3.2编译:到sourceforge下载后解压,在解压后的目录内执行:

make && sudo make install 即可,libtinyptc.a 是它生成的库文件,如果不 sudo make install 则将这个文件考贝到 /usr/lib/x86_64-linux-gnu下即可。

编译完成后生成一个测试程序 tinyptc_test,在终端上执行 ./tinyptc_test 显示不断变化的噪音信号,就好像老电视机收不信号满屏雪花一样。

X11 gfx版本编译事项

打开Makefile文件,将链接时的 $(AOBJECTS) 去掉。然后:

make && sudo make install ,或是直接考贝到 /usr/lib/x86_64-linux-gnu 下。

FreeBasic示例程序一:正弦曲线,中间画一条直线。

ptc_open前定义一个宽w高h的像素数组,freebasic 整数是32位的,正好是rgba的像素数 4 个8bit, ptc_open后以这个w和h的一半计算出x点对应的y点,再折算成连续数组中的位置,然后 ptc_update这个数组,就显示到屏幕上了。如果是bmp位置,可以获取位置长宽后读取位置数据装入到数组中,然后ptc_update到屏幕上去。

#include "tinyptc.bi" 

const SCR_WIDTH = 1024
const SCR_HEIGHT = 768

const SCR_SIZE = SCR_WIDTH*SCR_HEIGHT 

   dim shared buffer( 0 to SCR_SIZE-1 ) as integer 
	
   if( ptc_open( "Simple lines", SCR_WIDTH, SCR_HEIGHT ) = 0 ) then 
	  Print "Can not create ptc window!"
      end -1 
   end if 

	'data buffer is integer, e.g. 32bit/4byte color in depth
	'data arranged in ARGB order at each buffer cell &Haarrggbb

	Dim as integer x, y
	Dim as double rad = 0
	Dim as double PI = 3.1415926
	Do
		rad = 0
		for x = 0 to SCR_WIDTH/2 - 1
			''Line diagonal
			'y = x*(SCR_HEIGHT-1)/(SCR_WIDTH-1)
			'buffer(y*SCR_WIDTH + x) = RGBA(255, 0, 255, 0)

			'Sine wave
			y = SCR_HEIGHT/4 + (SCR_HEIGHT/5)*cos(rad)
			rad += 0.05
			if rad > 2*PI then
				rad = 0
			end if
			buffer(y*SCR_WIDTH + x) = RGBA(255, 255, 0, 0)
			
			'axes
			y = SCR_HEIGHT/4
			buffer(y*SCR_WIDTH + x) = RGBA(255, 0, 0, 0)			
		next x
		
		ptc_update @buffer(0) 
		sleep 10
		
	loop until( inkey = chr( 27 ) )
  
  ptc_close 

FreeBasic示例程序二:雪花噪音信号发生器

运算逻辑同示例一,只是算法不同,程序中有计算方法可细了解。

''
'' ordinary TinyPTC test, based on the original
''

#include "tinyptc.bi"

'const SCR_WIDTH = 320
'const SCR_HEIGHT = 200

const SCR_WIDTH = 1850
const SCR_HEIGHT =1000

const SCR_SIZE = SCR_WIDTH*SCR_HEIGHT

	dim shared buffer( 0 to SCR_SIZE-1 ) as integer

	'Integer is 8Bytes, e.g. 64bits per sizeof(integer)
	dim noise as integer, carry as integer, index as integer, seed as integer
	
	if( ptc_open( "freeBASIC v0.01 - tinyPTC test", SCR_WIDTH, SCR_HEIGHT ) = 0 ) then
		end -1
	end if
	
    seed = &h12345

    do
    
    	for index = 0 to SCR_SIZE-1
			noise = (seed shr 3) xor seed
        	carry = noise and 1
        	noise = noise shr 1
        	seed = seed shr 1
        	seed = seed or (carry shl 30)
        	noise = noise and &hFF
        	buffer(index) = rgb( noise, noise, noise )
    	next index
    
    	ptc_update @buffer(0)
   
    loop until( inkey = chr( 27 ) )
	
	
	ptc_close

FreeBasic示例程序二:朱丽叶环

通过函数运算,将值放入数组,然后ptc_update到屏幕上。

' The Lord of the Julia Rings
' The Fellowship of the Julia Ring
' Free Basic
' Relsoft
' Rel.BetterWebber.com
'



#ifdef __FB_WIN32__
#include once "windows.bi"
#endif

#include once "tinyptc.bi"

'320*240
'const SCR_WIDTH = 640  * 1
'const SCR_HEIGHT = 480 * 1

const SCR_WIDTH = 1850  * 1
const SCR_HEIGHT = 1000 * 1

const SCR_SIZE = SCR_WIDTH*SCR_HEIGHT
const SCR_MIDX = SCR_WIDTH \ 2
const SCR_MIDY = SCR_HEIGHT \ 2


const PI = 3.141593
const MAXITER = 20
const MAXSIZE = 4


dim shared Buffer(SCR_SIZE - 1) as integer
dim Lx(SCR_WIDTH-1) as single
dim Ly(SCR_HEIGHT-1) as single
dim shared sqrt(SCR_SIZE - 1) as single


if( ptc_open( "Julia (Relsoft)", SCR_WIDTH, SCR_HEIGHT ) = 0 ) then
	end -1
end if

dim px as integer, py as integer
dim p as single, q as single
dim xmin as single, xmax as single, ymin as single, ymax as single
dim theta as single
dim deltax as single, deltay as single
dim x as single, y as single
dim xsquare as single, ysquare as single
dim ytemp as single
dim temp1 as single, temp2 as single
dim i as integer, pixel as integer
dim p_buffer as integer ptr, p_bufferl as integer ptr
dim t as uinteger, frame as uinteger
dim ty as single
dim r as integer, g as integer, b as integer
dim red as integer, grn as integer, blu as integer
dim tmp as integer, i_last as integer

dim cmag as single
dim cmagsq as single
dim zmag as single
dim drad as single
dim drad_L as single
dim drad_H as single
dim ztot as single
dim ztoti as integer

xmin = -2.0
xmax =  2.0
ymin = -1.5
ymax =  1.5

deltax = (xmax - xmin) / (SCR_WIDTH - 1)
deltay = (ymax - ymin) / (SCR_HEIGHT - 1)

for i = 0 to SCR_WIDTH - 1
    lx(i) = xmin + i * deltax
next i

for i = 0 to SCR_HEIGHT - 1
    ly(i) = ymax - i * deltay
next i

for i = 0 to SCR_SIZE - 1
    sqrt(i) = sqr(i)
next i


#ifdef __FB_WIN32__
	dim hwnd as HWND
	hwnd = GetActiveWindow( )
#endif

dim stime as integer, Fps as single, Fps2 as single

stime = timer

do
    p_buffer = @buffer(0)
    p_bufferl = @buffer(SCR_SIZE-1)

    frame = (frame + 1) and &H7fffffff
    theta = frame * PI / 180

    p = cos(theta) * sin(theta * .7)
    q = sin(theta) + sin(theta)
    p = p * .6
    q = q * .6



    cmag = sqr(p *p + q* q)
    cmagsq = (p *p + q* q)
    drad = 0.04
    drad_L = (cmag - drad)
    drad_L = drad_L * drad_L
    drad_H = (cmag + drad)
    drad_H = drad_H * drad_H


    for py = 0 to (SCR_HEIGHT shr 1) - 1
        ty = ly(py)
        for px = 0 to SCR_WIDTH - 1
            x = Lx(px)
            y = ty
            xsquare = 0
            ysquare = 0
            ztot =0
            i = 0
            while (i < MAXITER) and (( xsquare + ysquare ) < MAXSIZE)
                xsquare = x * x
                ysquare = y * y
                ytemp = x * y * 2
                x = xsquare - ysquare + p
                y = ytemp + q
                zmag = (x * x + y * y)
                if (zmag < drad_H) then
                	if (zmag > drad_L) and (i > 0) then
                    		ztot = ztot + ( 1 - (abs(zmag - cmagsq) / drad))
                    		i_last = i
                    end if
                end if
                i = i + 1
                if zmag > 4.0 then
                    exit while
                end if
            wend

            if ztot > 0 then
                i = cint(sqr(ztot) * 500)
            else
                i = 0
            end if
              if i < 256 then
                red = i
              else
                red = 255
              end if

              if i < 512 and i > 255 then
                grn = i - 256
              else
                if i >= 512 then
                  grn = 255
                else
                  grn = 0
                end if
              end if

              if i <= 768 and i > 511 then
                blu = i - 512
              else
                if i >= 768 then
                  blu = 255
                else
                  blu = 0
                end if
              end if

          		tmp = cint((red+grn+blu) * 0.33)
          		red = cint((red+grn+tmp) * 0.33)
          		grn = cint((grn+blu+tmp) * 0.33)
          		blu = cint((blu+red+tmp) * 0.33)

              select case (i_last and 3)
          		case 1
                  tmp = red
                  red = grn
                  grn = blu
                  blu = tmp
          		case 2
                  tmp = red
                  blu = grn
                  red = blu
                  grn = tmp
              end select

            pixel = rgb( red, grn, blu )
            *p_buffer = pixel
            *p_bufferl = pixel
            p_buffer = p_buffer + 1
            p_bufferl = p_bufferl - 1
        next px
    next py

    'calc fps
    fps = fps + 1
    if stime + 1 < timer then
     fps2 = fps
     fps = 0
     stime = timer
#ifdef __FB_WIN32__
     SetWindowText( hwnd, "FreeBasic Julia Rings FPS:" & Fps2 )
#endif
    end if
    ptc_update @buffer(0)
loop until inkey <> ""


ptc_close

end

由于它体积小,在嵌入式设备上有一定用处,在数据算法绘图上也能用,操作步骤简单,也决定了操控灵活性上有局限性。优快云 上也能找到 TinyPTC 的应用和简介,所以就把它编译和试运行效果贴上来了。但是,它的功能似乎需要改造,比如显示个中文标注之类的,SDL对中文的渲染显示要SDL_TTF支持,而且用着不很顺手,还是cairo比较得以应手。

改造TinyPTC-SDL-0.3.2的相关文件和Makefile,增加freebasic可使用的 ptc_drawtest 函数,修改tinyptc.bi文件, 修改示例程序一,之后运行的效果如下(思来想去改造它没意义,因为freebasic本身就支持SDL, CAIRO,可以直接编程做图):

具体改造:

1、给sdl.c加引用 #include "cairo/cairo.h" ,然后定义cairo_surface_t *csurf; 和 cairo_t *crx; 两个指针,再加上 int ptc_drawtest 函数。

在它的头文件tinyptc.h中加上一句 extern int ptc_drawtest(void);extern int ptc_drawtest(void); ,让外部程序访问使用。

需关注的要点一:SDL_SetVideoMode产生的指针不是cairo要用的surface指针,要用它的 pixels 创建 cairo surface

需关注的要点二:cairo 显示完成后,要用 SDL_Flip 渲染 cairo 在 surface 上创建的文字。

int
ptc_drawtest(void)
{
    //Best fit, 1024 x 768
    csurf = cairo_image_surface_create_for_data( \
            ptc_video_surface->pixels, CAIRO_FORMAT_ARGB32, \
            ptc_stored_width, ptc_stored_height, ptc_stored_width*4);

    crx = cairo_create(csurf);
    cairo_set_source_rgba(crx, 1.0, 0.0, 0.0, 1.0);
    cairo_set_font_size(crx, 50.0);
    cairo_move_to(crx, 100, 300);
    cairo_show_text(crx, "Hello world -from Mongnewer!");
    cairo_move_to(crx, 100, 400);
    cairo_show_text(crx, "问候美丽的地球村");
    cairo_move_to(crx, 100, 500);
    cairo_show_text(crx, "测试的中文在绘图后显示效果");
    cairo_stroke(crx);
    SDL_Flip(ptc_video_surface);
    return PTC_SUCCESS;
}

2、对tinyptc.bi文件的改造(在 /usr/local/include/freebasic下面)

3、原来的make文件生成库时把测试程序也链接进去了,这样freebasic程序在编译时会出现main函数重复定义错误,因此生成库中去除原来的测试程序。

4、笔记示例一程序的修改:头部加上 #include "cairo/cairo.bi",在尾部 ptc_update @buffer(0)后面加上 ptc_drawtest()

修改后的TinyPTC放在csdn上了,下载后可看到修改细节。下面是它的链接:

优快云下载链接icon-default.png?t=N7T8https://download.youkuaiyun.com/download/weixin_45707491/88966995

下面是FreeBASIC直接操作SDL和CAIRO显示汉字示例

' SDL_image example written by Edmond Leung (leung.edmond@gmail.com)
'
' free.jpg, basic.gif and horse.tga are taken from the official freeBasic
' website.
' modified by: Mongnewer 25 march 2024

#include  "SDL\SDL.bi"
#include  "SDL\SDL_image.bi"
#include  "cairo/cairo.bi"

Const SCR_WIDTH = 1124
Const SCR_HEIGHT = 868

dim shared video as SDL_Surface ptr
dim shared freeImg as SDL_Surface ptr, basicImg as SDL_Surface ptr, horseImg as SDL_Surface ptr
dim version as const SDL_version ptr

dim shared csurf as cairo_surface_t ptr
dim shared crx as cairo_t ptr

declare sub drawtest()

declare sub blitImage _
   (byval img as SDL_Surface ptr, byval x as integer, byval y as integer)

'	dim shared video as SDL_Surface ptr
'	dim freeImg as SDL_Surface ptr, basicImg as SDL_Surface ptr, horseImg as SDL_Surface ptr

'	dim version as const SDL_version ptr
	version = IMG_Linked_Version()

	' display the version number of the SDL_image being used
	print "Using SDL_image version number: "; SDL_VERSIONNUM(version->major, _
   	version->minor, version->patch)

	' initialise sdl with video support
	if (SDL_Init(SDL_INIT_VIDEO) < 0) then
   		print "Couldn't initialise SDL: "; *SDL_GetError()
	end if

	' check to see if the images are in the correct formats
	if (IMG_isJPG(SDL_RWFromFile("data/free.jpg", "rb")) = 0) then
   		print "The image (free.jpg) is not a jpg file."
	end if
	if (IMG_isGIF(SDL_RWFromFile("data/basic.gif", "rb")) = 0) then
   		print "The image (basic.gif) is not a gif file."
	end if

	' set the video mode
	video = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, 32, SDL_HWSURFACE or SDL_DOUBLEBUF)
	
	if (video = NULL) then
   		print "Couldn't set video mode: "; *SDL_GetError()
	end if

	' load the images into an SDL_RWops structure
	dim freeRw as SDL_RWops ptr, basicRw as SDL_RWops ptr
	freeRw = SDL_RWFromFile("data/free.jpg", "rb")
	basicRw = SDL_RWFromFile("data/basic.gif", "rb")

	' load the images onto an SDL_Surface using three different functions available
	' in the SDL_image library
	freeImg = IMG_LoadJPG_RW(freeRw)
	horseImg = IMG_Load("data/horse.tga")
	basicImg = IMG_LoadTyped_RW(basicRw, 1, "gif")

	dim done as integer
	done = 0

	do while (done = 0)
   		dim event as SDL_Event
   
   		do while (SDL_PollEvent(@event))
      		if (event.type = SDL_QUIT_) then done = 1
      			if (event.type = SDL_KEYDOWN) then
        	 		if (event.key.keysym.sym = SDLK_ESCAPE) then done = 1      
      		end if
   		loop

   		dim destrect as SDL_Rect
   		destrect.w = video->w
   		destrect.h = video->h
   
   		' clear the screen with the colour white
   		SDL_FillRect(video, @destrect, SDL_MapRGB(video->format, 255, 255, 255))
   
   		' draw the images onto the screen
   		'blitImage freeImg, 245, 205 
   		'blitImage basicImg, 250, 230 
   		'blitImage horseImg, 145, 200 

		blitImage freeImg, 170, 205

   		blitImage horseImg, 345, 330 
		blitImage freeImg, 445, 335 
   		blitImage basicImg, 450, 360 
		
		blitImage freeImg, 650, 215 
   		blitImage basicImg, 650, 240 		

		blitImage freeImg, 150, 455 
   		blitImage basicImg, 150, 480 		
	
		drawtest()
		SDL_Flip(video)
		sleep 20
	loop

	cairo_destroy(crx)
	cairo_surface_destroy(csurf)
	SDL_Quit

' sub-routine used to help with blitting the images onto the screen
sub blitImage _
   (byval img as SDL_Surface ptr, byval x as integer, byval y as integer)
	dim dest as SDL_Rect
   	dest.x = x
   	dest.y = y
   	SDL_BlitSurface(img, NULL, video, @dest)
end sub

sub drawtest()
    'Best fit, 1024 x 768
    csurf = cairo_image_surface_create_for_data( _
            video->pixels, CAIRO_FORMAT_ARGB32, _
            SCR_WIDTH, SCR_HEIGHT, SCR_WIDTH*4)
 
    crx = cairo_create(csurf)
    cairo_set_source_rgba(crx, 1.0, 0.0, 0.0, 1.0)
    cairo_set_font_size(crx, 20.0)
    cairo_move_to(crx, 600, 600)
    cairo_show_text(crx, "Hello world -from Mongnewer!")
    cairo_move_to(crx, 600, 650)
    cairo_show_text(crx, "问候美丽的地球村")
    cairo_move_to(crx, 600, 700)
    cairo_show_text(crx, "测试的中文在绘图后显示效果")
    cairo_stroke(crx)
    SDL_Flip(video)
end sub

显示效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值