I'm writing a drawing program and need some advice or direction on how to handle screen updates. I've had a working program for a little while now and have recently re-written a large part of the program to handle flashing colour support.
To help explain my request I've cut most of the drawing bits out and just left in the main initialisation and screen update code to demonstrate what I am attempting to do which is:
* Use a 'drawing screen' buffer array which contains colour information of the picture being drawn, this holds byte values 0-15 which are used as a palette lookup
* Use a double buffered 'WindowedScreen' for displaying the drawn picture
* Use CanvasGadgets to section of the screen into 3 partitions for tools and drawing areas
* Use a WindowsTimer to update a colour table, this is used to redraw the output screen
* Use a bitmap to draw 'screen buffer' data using colour table of rgb values
* Draw the bitmap to WindowedScreen buffer and flip buffers to display smoothly
* Using PB 5.62 32bit on Windows with debugger turned off.
* Clicking in the top left window will draw random colour boxes using the predefined palette
If anyone has time to look at the code (mainly 'UpdateScreen') and explain a faster way to do it or if you think it would be better to do it another way that would be fantastic.
The performance isn't too bad but before I started using the double buffer approach the drawing and screen updating was a lot faster and smoother.
Code: Select all
#scrW=960
#scrH=704
#drwW=640
#drwH=512
Structure Pixel
Pixel.l
EndStructure
Structure rgbTable
r.a
g.a
b.a
EndStructure
Global dMdx=160 ; current mode horizontal pixels
Global dMdy=256 ; current mode vertical pixels
Global dMpx=#drwW/dMdx ; current mode horizontal pixel size
Global dMpy=#drwh/dMdy ; current mode vertical pixel size
Global iBeebSCRN ; image handle
Global flashing.b=0 ; flashing colour toggle
Global flashCol.a ; flashing colour index
Global fSpeed=540 ; flash speed in ms
Global gCur=-1 ; current gadget clicked
Global mx,my
Global Dim buf1.a(163839) ; beeb screen buffer
Global Dim bp(15) ; beeb palette
Global Dim rgbT.rgbTable(15) ; rgb lookup table
Global Dim ct(15) ; colour table look for redrawing main canvas
Global Dim bpFlash(15) ; flash palette 0-7 phase 1, 8-15 phase 2
; Exit program and display a message
Procedure Exit_ART(m.s)
If m<>""
MessageRequester("Error", m, 0)
EndIf
End
EndProcedure
; display program stats 104,500,204,200
Procedure showstats()
Protected x,y
x=104+30
y=500
Box(x,y+1,90,198,bp(0))
DrawText(x,y,StrU(mx,#PB_Long))
DrawText(x,y+16,StrU(my,#PB_Long))
DrawText(x,y+128,StrU(gCur,#PB_Long))
EndProcedure
; draw box outline, assumes startdrawing is already active
Procedure drawBox(x1,y1,x2,y2,c)
FrontColor(c)
LineXY(x1,y1,x2,y1)
LineXY(x2,y1,x2,y2)
LineXY(x1,y2,x2,y2)
LineXY(x1,y1,x1,y2)
EndProcedure
;-------- Init and Load --------
If InitSprite() = 0
Exit_ART("Cannot init Sprite subsystem!")
EndIf
If InitMouse() = 0
Exit_ART("Cannot init Mouse subsystem!")
EndIf
If InitKeyboard() = 0
Exit_ART("Cannot init Keyboard subsystem!")
EndIf
If OpenWindow(0,0,0,#scrW, #scrH, "ART for Windows 0.1",#PB_Window_SystemMenu | #PB_Window_ScreenCentered) = 0
Exit_ART("Cannot init Graphics subsystem! ("+StrU(#scrW,#PB_Long)+"x"+StrU(#scrh,#PB_Long)+")") ;#scrW #scrh
EndIf
; define beeb 2 palette
Restore paletteData
For i=1 To 15
Read.a rgbT(i)\r
Read.a rgbT(i)\g
Read.a rgbT(i)\b
bp(i)=RGB(rgbT(i)\r,rgbT(i)\g,rgbT(i)\b)
Next
bp(0) = RGB(0,0,0)
rgbT(0)\r=0
rgbT(0)\g=0
rgbT(0)\b=0
; flashing palette - pointer to BP colour
For i=0 To 7
bpFlash(i)=i
bpFlash(i+8)=7-i
Next
; temp buffer data - this buffer normally gets written to or modified when with drawing procedures
For i=0 To 163839
If i<16
buf1(i)=i % 15
EndIf
Next
; main drawing area
iBeebSCRN=CreateImage(#PB_Any,#drwW,#drwH,32)
If StartDrawing(ImageOutput(iBeebSCRN))
Box(0,0,639,511,bp(0))
StopDrawing()
EndIf
; buffered drawing area 4,4,640,512
If OpenWindowedScreen(WindowID(0), 4,4, 640, 512)=0
Exit_ART("Cannot init main canvas windowed screen object!")
EndIf
; init screen gadgets and initial state
CanvasGadget(0,0,520,648,#scrH-520) ; pallete gadget
SetGadgetAttribute(0, #PB_Canvas_Cursor , #PB_Cursor_Cross)
CanvasGadget(1,648,0,#scrW-648,#scrH) ; tool gadget
SetGadgetAttribute(1, #PB_Canvas_Cursor , #PB_Cursor_Cross)
CanvasGadget(2,0,0,648,520) ; drawing gadget (never drawn to)
SetGadgetAttribute(2, #PB_Canvas_Cursor , #PB_Cursor_Cross)
AddWindowTimer(0,0,fSpeed)
;-------- Draw controls --------
; canvas 0 - palette
If StartDrawing(CanvasOutput(0))
Box(0,0,647,#scrH-519,bp(0))
;drawBox(0,0,647,#scrH-519,bp(5))
DrawText(10,10,"Palette Gadget",bp(2))
StopDrawing()
EndIf
; canvas 1 - tools
If StartDrawing(CanvasOutput(1))
; clear canvas to black
Box(0,0,#scrW-648,#scrH,bp(0))
;drawBox(0,0,#scrW-647,#scrH-1,bp(3))
DrawText(10,10,"Tools Gadget",bp(2))
; stats
x=104
y=500
DrawText(x,y,"mX:")
DrawText(x,y+16,"mY:")
DrawText(x,y+32,"pX:")
DrawText(x,y+48,"pY:")
DrawText(x,y+64,"mB:")
DrawText(x,y+80,"mA:")
DrawText(x,y+96,"CT:")
DrawText(x,y+112,"TS:")
DrawText(x,y+128,"gC:")
StopDrawing()
EndIf
; canvas 2 - drawing area
If StartDrawing(CanvasOutput(2))
; clear canvas to black
Box(0,0,647,519,bp(0))
; main canvas double border
;drawBox(0,0,647,519,bp(1))
;drawBox(1,1,646,518,bp(1))
StopDrawing()
EndIf
If StartDrawing(ScreenOutput())
DrawImage(ImageID(iBeebSCRN),0,0)
StopDrawing()
EndIf
FlipBuffers()
;-------- MainLoop --------
Repeat
; event loop
Repeat
Event = WindowEvent()
Select event
Case #PB_Event_Timer ; handle flashing colours
flashing=(flashing+1) & 1
; update flashing colour pointer
For i=0 To 7
If flashing
bpFlash(i+8)=7-i
Else
bpFlash(i+8)=i
EndIf
Next
Case #PB_Event_Gadget ; gadget events
gCur=EventGadget()
; set mouse action if none already set for left mouse click
If EventType() = #PB_EventType_LeftButtonDown
; handle general lb event
EndIf
; determine which gadget has triggered an event
Select gCur
;-------- Palette Gadget Area --------
Case 0
mx = GetGadgetAttribute(gCur, #PB_Canvas_MouseX)
my = GetGadgetAttribute(gCur, #PB_Canvas_MouseY)
; left click or mouse down / move events
If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(gCur, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
; handle general lb and lb move event for gadget 0
EndIf
;-------- Tools Gadget Area --------
Case 1 ; tools area
mx = GetGadgetAttribute(gCur, #PB_Canvas_MouseX)
my = GetGadgetAttribute(gCur, #PB_Canvas_MouseY)
If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(gCur, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
; handle general lb and lb move event for gadget 1
EndIf
; left button release events
If EventType()=#PB_EventType_LeftButtonUp
; handle general lb up gadget 1
EndIf
;-------- Drawing Gadget Area --------
Case 2 ; drawing area
mx = GetGadgetAttribute(gCur, #PB_Canvas_MouseX)
my = GetGadgetAttribute(gCur, #PB_Canvas_MouseY)
If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(gCur, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
; handle general lb and lb move event for gadget 2
; update pixels in buf1
c=Random(15)
m=ArraySize(buf1())
xs=(mx-16) / dMpx
ys=255-((my+4) / dMpy)
For y=0 To 10
For x=0 To 5
a=(y+ys)*640+x+xs
If a>-1 And a<m
buf1((y+ys)*640+x+xs)=c
EndIf
Next
Next
EndIf
; left button release events
If EventType()=#PB_EventType_LeftButtonUp
; handle general lb up gadget 2
EndIf
EndSelect
; left general button release events
If EventType()=#PB_EventType_LeftButtonUp
; handle general lb up
EndIf
Case #PB_Event_CloseWindow ; close application event
End
EndSelect
Until event=0
;-------- Update Screen --------
; update screen
If StartDrawing(ImageOutput(iBeebSCRN))
Buffer = DrawingBuffer() ; Get the start address of the screen buffer
Pitch = DrawingBufferPitch() ; Get the length (in byte) took by one horizontal line
PixelFormat = DrawingBufferPixelFormat() ; Get the pixel format.
; configure palette for RGB or BGR
If PixelFormat = #PB_PixelFormat_32Bits_RGB
For i=0 To 15
ct(i)=bp(bpFlash(i))
Next
Else ; Else it's 32bits_BGR
For i=0 To 15
ct(i)=rgbT(bpFlash(i))\b+rgbT(bpFlash(i))\g<<8+rgbT(bpFlash(i))\r<<16
Next
EndIf
; beeb pixels are 4 screen pixels wide by 2 screen pixels high
For y = 0 To 511
*Line.Pixel = Buffer+Pitch*y
yMul=(y/2)*640
For x=0 To 159
dc = ct(buf1(x+yMul))
*Line\Pixel = dc ; Write the pixel directly to the memory !
*line+4
*Line\Pixel = dc ; Write the pixel directly to the memory !
*Line+4
*Line\Pixel = dc ; Write the pixel directly to the memory !
*Line+4
*Line\Pixel = dc ; Write the pixel directly to the memory !
*Line+4
Next
Next
StopDrawing()
EndIf
; draw beeb screen on screen buffer
If StartDrawing(ScreenOutput())
DrawImage(ImageID(iBeebSCRN),0,0)
StopDrawing()
EndIf
; update tools
If StartDrawing(CanvasOutput(1))
; show stats
showstats()
StopDrawing()
EndIf
FlipBuffers()
ExamineKeyboard() ;Keyboard
Until KeyboardPushed(#PB_Key_Escape)
End
;
;-------- Data Section --------
;
DataSection
; palette Data
paletteData:
Data.a 255,000,000,000,255,000,255,255,000,000,000,255,255,000,255
Data.a 000,255,255,255,255,255,128,128,128,192,000,000,000,192,000
Data.a 192,192,000,000,000,192,192,000,192,000,192,192,192,192,192
EndDataSection
; colour map, flashing colour default is 540ms
; 0 black
; 1 red
; 2 green
; 3 yellow
; 4 blue
; 5 magenta
; 6 cyan
; 7 white
; 8 flashing black-white
; 9 flashing red-cyan
; 10 flashing green-magenta
; 11 flashing yellow-blue
; 12 flashing blue-yellow
; 13 flashing magenta-green
; 14 flashing cyan-red
; 15 flashing white-black