At any rate, I think proper clipping is probably worth the code, because it takes less time overall pushing less pixels.
Ive been thinking a bit recently about tilemapped backgrounds (well any background) and sprites and im a little concerned.

My main concern is when you draw a sprite over a background, the only way to clear it is to redraw the portion of the background that was overwritten (due to a fullscreen redraw being too slow). And this needs to be done each time a sprite is moved/updated.

However i am worried that there may be noticeable flicker given that this technique will render the restored background to the LCD before the sprite is redrawn at its new position. Meaning that the background will be 'visible' through the sprite for a portion of time. Im hoping that it can be drawn close enough together that the effect is not noticeable.
tr1p1ea wrote:
My main concern is when you draw a sprite over a background, the only way to clear it is to redraw the portion of the background that was overwritten (due to a fullscreen redraw being too slow). And this needs to be done each time a sprite is moved/updated.
To minimize the number of writes you need to do, it will become practically imperative to combine your write and erase with this new LCD. If you want to make it simple, you can switch the parts of the sprite that won't be part of the new sprite to the background image, then scan over the area that will hold the new sprite, changing each pixel as you go. If you have transparent sprites, it's probably just easier to do an 18x18 rectangle (for example) if you're moving a 16x16 icon 2 pixels up and 2 pixels to the side.
A few possible answers:

- Be clever and figure out a way to redraw the sprite and background at the same time. You might get tearing but you won't get flicker.

- Double buffering using partial images. (This is theoretical, I haven't heard if anybody's tested partial images yet or how well they work.)

For example, if you need to be able to atomically update a 32-pixel-wide region, you could limit the program to a 288x240 area of the LCD, giving yourself an extra 32 columns' worth of GRAM to play with.

Code:

               (partial image 0)  (partial image 1)
DISPLAY  |###|==================|-------|----------------|###|
            .                  . .       .                .
           .                  .   .       .                .
          .                  .     .       .                .
GRAM     |==================|.......|-------|----------------|
         |                  |       |       |                |
         | left part of     |   X   |   Y   | right part     |
         | background       |       |       | of background  |
         |                  |       |       |                |
         |==================|.......|-------|----------------|
   
                                   ||  draw stuff to "X",
                                   \/  then change R82-R84
   
GRAM     |==================|=======|.......|----------------|
         |                  |       |       |                |
         | left part of     |   X   |   Y   | right part     |
         | background       |       |       | of background  |
         |                  |       |       |                |
         |==================|=======|.......|----------------|
          .                  .       .     .                .
           .                  .       .   .                .
            .                  .       . .                .
DISPLAY  |###|==================|=======|----------------|###|
           \
            unused area (white or possibly black)

Generalizing this, you could update the whole screen in rolling fashion, or you could shuffle the "extra" columns around whenever you need to update a different part of the screen. There are lots of possibilities.

(Of course there's the possibility of flickering while you're changing the LCD registers, but that shouldn't take more than a few tens of microseconds.)

- Poor man's double buffering using R60. I suggested this to KermM at one point, I don't know if anybody's tried it yet. As he said earlier, when you hide part of the screen using R60, the image that was previously displayed *stays there*, and fades to white *slowly* over the course of a few seconds. I would guess that if you set NL to 0, draw something to the hidden part of GRAM, then set NL back to 27h, all in the space of a millisecond or so, the flicker would be imperceptible.
I think that while we're discussing our new paradigms for working with the CSE, I should mention the Apple //e from the 1980s. I actually have one of these computers along with the appropriate technical manuals, and I'm seeing a lot of similarities between the way we work this device and the way people worked the //e:
- The //e's processor was incredibly slow: 1 MHz. Every instruction counted, even more than it will here.
- Also, while the //e's screen was accessible through simple RAM areas (not a port or memory trigger), these RAM areas followed the interlace pattern of the TVs they were displaying on. In addition, the color schemes for the 280x192 HIRES screen, while 1 bit per pixel, were really strange and based on pixel positions, requiring overhead to calculate where sprites would be drawn.
And through it all, some really magnificent little gems were produced.
Nothing more fun than trying to learn ASM color from code on the forums... I'm assuming there's a tutorial on it in the DCSE SDK, right?
There are a few z80 tutorials out there; namely z80 in 28 days (the more popular) and Hot Dogs z80 Tutorial. Both has different teaching methods, and I prefer 28 days.
It is asm, so it requires a few tools to compile the code to a .8xp or CSE extension, which I am certain are included in the SDK. The CSE functions with similar code, however the color screen is not taught in 28 days (a pity), so graphically that will be different. Pretty sure some (probably a bunch?) of the memory locations will be at different addresses due to different OS's. But hey learning z80 for the monochrome brotheren might be your best best. I prefer mimas (not for the CSE).. its an on-calc dev, so it's easier to sit in bed or out on the go.
I do not have a non-color calc... So my best bet is to try to adapt from 28 days or something to color?
I don't have a CSE, but i imagine the only thing that you really need to worry about for now is the LCD. The system routines (bcalls) have been moved around a bit it seems (and i would assume they're not all the same as the previous calcs). But the actually z80 assembly language is the same. Adding a to b works the same, sending or reading a byte to port 1 is the same (the ports just might do different things). So i would say start with 28 days and either ask or look at code that explains how the LCD works. Kerm has released a few programs with the source well documented, as has AssemblyBandit. But most of the CSE programmers moved from the 83/+ series to the CSE, so it's really just finding the differences (the ports, system calls, etc.).
I have been experimenting with windows for a while now. If you are not careful with them you get a lot of garbage on screen until you power the calc off and on again.

That said: They can be very useful too. I wrote this routine for drawing an image at the cursor that is _SPR_SIZEH wide and _SPR_SIZEV tall.


Code:

; Settings:
#define _SPR_SIZEH 32
#define_SPR_SIZEV 32
;============================================================================
; M A C R O's
;============================================================================
; Select Register
#macro lcd_sReg(reg)
   ld a,reg
   out (pLcdCmd),a
   out (pLcdCmd),a
#endmacro
; Select GRAM register
#macro lcd_dStart()
   lcd_sReg(lrGram)
#endmacro

#macro lcd_wRegImm(reg,val)
   ld a,reg
   ld hl,val
   call lcd_wReg_hl
#endmacro
#macro lcd_wRegHL(reg)
   ld a,reg
   call lcd_wReg_hl
#endmacro
#macro lcd_wRegDE(reg)
   ld a,reg
   call lcd_wReg_de
#endmacro
#macro lcd_rRegHL(reg)
   ld a,reg
   call lcd_rReg_hl
#endmacro
#macro lcd_rRegDE(reg)
   ld a,reg
   call lcd_rReg_de
#endmacro

;============================================================================
; G R A P H I C S
;============================================================================
; Routine: dSprite
; Draw an 8*8 sprite at cursor position
; HL = Sprite address
cl_dSprite:
   push hl
   lcd_rRegHL(lrRow)            ; Get cursor row in HL         
   lcd_wRegHL(lrWinTop)         ; Define top border
   ld de,_SPR_SIZEV-1            
   add hl,de   
   lcd_wRegHL(lrWinBottom)      ; Define bottom border
   
   lcd_rRegDE(lrCol)            ; Get cursor column in DE
   lcd_wRegDE(lrWinLeft)         ; Define left border
   ld hl,_SPR_SIZEH-1
   add hl,de
   lcd_wRegHL(lrWinRight)         ; Define right border
   
   pop hl
   
   lcd_dStart()               ; Select graphics ram
   ld b,_SPR_SIZEH * _SPR_SIZEV * 2; Init counter
   otir                     ; Write all pixels
   ret                     ; Return

;============================================================================
; L C D   C O N T R O L
;============================================================================
; Routine: write register
; Parameters:
;   A = register
;   HL/DE = value (pick relevant routine)
; Additionally:
;   C = pLcdData (important!)
lcd_wReg:
lcd_wReg_hl:
   out (pLcdCmd),a            ; Select register
   out (pLcdCmd),a
   out (c),h                  ; Write value
   out (c),l
   ret
lcd_wReg_de:
   out (pLcdCmd),a            ; Select register
   out (pLcdCmd),a
   out (c),d                  ; Write value
   out (c),e
   ret

; Routine: read register
; Parameters:
;   A = register
;   HL/DE = value (pick relevant routine)
; Additionally:
;   C = pLcdData (important!)   
lcd_rReg:
lcd_rReg_hl:
   out (pLcdCmd),a
   out (pLcdCmd),a
   in h,(c)
   in l,(c)
   ret
lcd_rReg_de:
   out (pLcdCmd),a
   out (pLcdCmd),a
   in d,(c)
   in e,(c)
   ret
   
; Set window to be fullscreen again
lcd_normalWindow:
   ld c,pLcdData                  ; Get port pLcdData in C
   lcd_wRegImm(lrWinTop,$0000)      ; Define top border
   lcd_wRegImm(lrWinBottom,$00EF)      ; Define bottom border
   lcd_wRegImm(lrWinLeft,$0000)      ; Define left border
   lcd_wRegImm(lrWinRight,$013F)      ; Define right border   
   ret


Very important edit: If you don't turn off the run indicator you are going to have a bad time!

Code:
bcall(_maybe_RunIndicOff)   ; Disable Run indicator

And after you're done you can turn it back on:

Code:
bcall(_maybe_RunIndicOn)   ; Disable Run indicator
[/code]
keoni29 wrote:
I have been experimenting with windows for a while now. If you are not careful with them you get a lot of garbage on screen until you power the calc off and on again.

That said: They can be very useful too.
They can be very useful indeed! Most of the existing sprite routines make use of windowing to avoid having to set the LCD pointer coordinates more than once. Smile
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 3 of 3
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement