Screen update speed

Advanced game related topics
User avatar
FourthStone
User
User
Posts: 26
Joined: Mon Dec 11, 2017 8:44 am
Location: Australia

Screen update speed

Post by FourthStone »

Hi All,

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
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: Screen update speed

Post by IceSoft »

why you don't draw directly on the screen?
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
User avatar
FourthStone
User
User
Posts: 26
Joined: Mon Dec 11, 2017 8:44 am
Location: Australia

Re: Screen update speed

Post by FourthStone »

IceSoft wrote:why you don't draw directly on the screen?
Couple of questions for this approach:
* Can I do this in realtime while updating the drawing buffer and other tools every frame?
* There are quite a lot of things happening in realtime such as buttons, labels, stats, flashing colours etc. and I need to redraw the drawing frame and respond to mouse controls as frequently as possible to make it all smooth.
* can you point me to an example of this approach, I'm pretty new to PB so while I understand what you're saying I've not seen this approach in the help or demo code.

I am willing to rewrite the guts of the program for the right approach so any advice would be helpful for me to try out but I just need a little assistance to get started, mostly with a fast buffer draw routine and using mouse input from direct screen updates.
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Screen update speed

Post by Demivec »

Here are two things that can be done (whether for image or screen drawing).

Both changes have to do with pixel size. First, change the pixel structure to include 4 bytes instead of one. Second change the drawing loop to duplicate the even numbered lines to the odd numbered lines.

Here's just the code for those changes:

Code: Select all

Structure Pixel
  ;Pixel.l
  Pixel.l[4]
EndStructure
and the drawing update loop

Code: Select all

   ; 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
      If y & 1
        ;if an odd line, copy previous line
        CopyMemory(*Line - Pitch, *line, 160 * SizeOf(Pixel))
      Else
        For x=0 To 159
          dc = ct(buf1(x+yMul))
          
          *Line\Pixel[0] = dc ; Write the pixel directly to the memory !
          *Line\Pixel[1] = dc ; Write the pixel directly to the memory !
          *Line\Pixel[2] = dc ; Write the pixel directly to the memory !
          *Line\Pixel[3] = dc ; Write the pixel directly to the memory !
          *Line+SizeOf(Pixel)
          
        Next
      EndIf
    Next
I didn't do any timing tests to compare. It should be faster in theory at least. :)
User avatar
FourthStone
User
User
Posts: 26
Joined: Mon Dec 11, 2017 8:44 am
Location: Australia

Re: Screen update speed

Post by FourthStone »

Demivec wrote:Both changes have to do with pixel size. First, change the pixel structure to include 4 bytes instead of one. Second change the drawing loop to duplicate the even numbered lines to the odd numbered lines.
...
I didn't do any timing tests to compare. It should be faster in theory at least. :)
I like both these approaches! Something new to play with, I've tried it out but I didn't notice much difference but I'll setup some timing code and do comparisons.

Thanks for offering some suggestions, this is exactly what I need to try something different and new :D
Post Reply