Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
PutTile16x16 Pixels + Attributes
#16
Okay. This is faster. it's also quite a lot longer!

I had to hand time this at about 8.5 seconds for 80 loops. Which means it takes about 5.3 frames to fill the screen once. (Your 8 loop test would take about 42 frames). I can't use the frames counter to time it, because Interrupts HAVE to be disabled.

I hope around 3 times faster is good?

This could probably be optimized slightly better, I don't think I'm using passed in parameters well.

I also think you might be able to see how the fourspriter code was made to go quite a lot faster...

Code:
SUB putTile(x as uByte, y as uByte, graphicsAddr as uInteger)

poke @ptx+1,x  
poke @pty+1,y
poke Uinteger @ptgraddr+1,graphicsAddr

ptDataPoint:
asm
JP pt_start

ptstackSave:
defb 0,0

pt_start:
ld a,i
push af ; Save interrupt status.

; Routine to save the background to the buffer

         DI ; we really, really, REALLY can NOT be having interrupts while the stack and IX and IY are pointed elsewhere.
        
         PUSH IX
         PUSH IY
end asm
ptgraddr:
asm
         ld      HL, 65535 ; Self modifying code should load this with the graphics address.
        
        
;; Print sprites routine
        
         LD (ptstackSave), SP ; Save Stack Pointer
        
         LD SP,HL   ; now SP points at the start of the graphics.
        
        
       ; This function returns the address into HL of the screen address
end asm
ptx:
asm      
         ld      a,0 ; Load in x
         ld      IYH, a ; save it
         ld      l,a
end asm
pty:
asm
         ld      a,0 ; Load in y
         ld      IYL, a ; save it
         ld      d,a
         and     24
         add     a,64
         ld      h,a
         ld      a,d
         and     7
         rrca
         rrca
         rrca
         or      l
         add     a,2   ; Need to be to the right so backwards writing pushes land properly.
         ld      l,a
        
         ; SO now, HL -> Screen address, and SP -> Graphics. Time to start loading.
        
         POP BC    ; Row 0
         POP DE    ; row 1
         EX AF,AF'
         POP AF    ; row 2
         EX AF,AF'
         EXX
         POP BC    ; row 3
         POP DE    ; row 4
         POP HL    ; row 5
         EXX
        
         ; All right. We're loaded. Time to dump!
        
         LD IX,0
         ADD IX,SP  ; Save our stack pointer into IX
        
         LD SP,HL  ; point at the screen.
         PUSH BC   ; row 0
        
         INC H
         LD SP,HL
         PUSH DE   ; row 1
        
         INC H
         LD SP,HL
         EX AF,AF'
         PUSH AF   ; row 2
                  
         INC H
         LD SP,HL
         EXX
         PUSH BC   ; row 3
         EXX    
        
         INC H
         LD SP,HL
         EXX
         PUSH DE   ; row 4
         EXX

         INC H
         LD SP,HL
         EXX
         PUSH HL   ; ROW 5
         EXX        
        
         ; We're empty. Time to load up again.
        
         LD SP,IX
         POP BC    ; ROW 6
         POP DE    ; ROW 7
         EX AF,AF'
         POP AF    ; ROW 8
         EX AF,AF'
         EXX
         POP BC    ; ROW 9
         POP DE    ; ROW 10
         POP HL    ; ROW 11
         EXX
        
         ; and we're loaded up again! Time to dump this graphic on the screen.
        
         LD IX,0
         ADD IX,SP ; save SP in IX
        
         INC H
         LD SP,HL
         PUSH BC   ; ROW 6
        
         INC H
         LD SP,HL
         PUSH DE   ; ROW 7
        
         DEC HL
         DEC HL
        
         ; Aha. Snag. We're at the bottom of a character. What's the next address down?
         ld   a,l    
         and  224    
         cp   224    
         jp   z,ptSameThird3

ptNextThird3:
         ld   de,1760        
         and  a            
         sbc  hl,de        
         jp ptAddrDone3

ptSameThird3:
         ld   de,32        
         and  a                
         adc  hl,de        

ptAddrDone3:
          INC HL
          INC HL
        
          LD SP,HL
          EX AF,AF'
          PUSH AF  ; ROW 8
          
          INC H
          LD SP,HL
          EXX
          PUSH BC  ; ROW 9
          EXX
          
          INC H
          LD SP,HL
          EXX
          PUSH DE  ; ROW 10
          EXX
            
          INC H
          LD SP,HL
          EXX
          PUSH HL  ; ROW 11
          EXX                      
    
        
         ; Okay. Registers empty. Reload time!
         LD SP,IX
         POP BC    ; ROW 12
         POP DE    ; ROW 13
        
         EXX
         POP BC    ; ROW 14
         POP DE    ; ROW 15
         POP HL    ; Top Attrs
         EXX
        
         EX AF,AF'
         POP AF    ; Bottom Attrs
         EX AF,AF'
        
        
         ; and the last dump to screen
        
         INC H
         LD SP,HL
         PUSH BC
        
         INC H
         LD SP,HL
         PUSH DE
        
         INC H
         LD SP,HL
         EXX
         PUSH BC
         EXX
        
         INC H
         LD SP,HL
         EXX
         PUSH DE
         EXX
end asm
#line 222
asm        
        
         ; Pixels done. Just need to do the attributes.
         ; So set HL to the attr address:
        
         ld      a,IYL        ;ypos
        
         rrca
         rrca
         rrca               ; Multiply by 32
         ld      l,a        ; Pass to L
         and     3          ; Mask with 00000011
         add     a,88       ; 88 * 256 = 22528 - start of attributes.
         ld      h,a        ; Put it in the High Byte
         ld      a,l        ; We get y value *32
         and     224        ; Mask with 11100000
         ld      l,a        ; Put it in L
         ld      a,IYH      ; xpos
         adc     a,l        ; Add it to the Low byte
         ld      l,a        ; Put it back in L, and we're done. HL=Address.        
         INC HL             ; we need to be to the right of the ATTR point as pushes write backwards.
         INC HL
        
         ; attr
         LD SP,HL
         EXX
         PUSH HL            ; top row
         EXX
        
         LD HL,34           ; we need to move down to the next row. We already backed up 2, so we add 34.
         ADD HL,SP
         LD SP,HL
         EX AF,AF'          ; bottom row
         PUSH AF
        
                
        
ptNextSprite2:
        
         ; done. Cleanup.
         LD SP,(ptstackSave) ;  put our stack back together.
        
         ; done all 4 final clean up
        
         POP IY
         POP IX
        
         POP AF  ; recover interrupt status
         JP PO, pt_nointerrupts ; skip EI if we didn't have them enabled to begin with.
         EI      ; Okay. We put everything back.
pt_nointerrupts:
END ASM
END SUB


dim x,y as ubyte
dim adr as Uinteger

    adr=0
    for y=0 to 11
        for x=0 to 15
            putTile(x<<1,y<<1,adr)
            'adr=adr+36
        next x
    next y
Reply
#17
britlion Wrote:Oh, so it's not passing the first value in the stack - stdcall passes it in the register AND in the stack, which is a little confusing.

So we CAN use FASTCALL, even if the compiler complains to shortcut that, and use a shorter stack. I think I see.

There's the confusion - fastcall would say "hey, you can't do that!" and so I sort of went with that.
You CAN, but you SHOULD NOT, unless you really manage the stack yourself. :roll: If you use FASTCALL in a function with 2 or more params, or a function with local vars, it will crash your program.
Reply
#18
boriel Wrote:You CAN, but you SHOULD NOT, unless you really manage the stack yourself. :roll: If you use FASTCALL in a function with 2 or more params, or a function with local vars, it will crash your program.

So YOU get to break all the rules? We kids never have any fun.
:-)

Understood.
Reply
#19
britlion Wrote:Okay. This is faster. it's also quite a lot longer!

I had to hand time this at about 8.5 seconds for 80 loops. Which means it takes about 5.3 frames to fill the screen once. (Your 8 loop test would take about 42 frames). I can't use the frames counter to time it, because Interrupts HAVE to be disabled.

I hope around 3 times faster is good?

This could probably be optimized slightly better, I don't think I'm using passed in parameters well.

I also think you might be able to see how the fourspriter code was made to go quite a lot faster...
Britlion, this is great! That's what I call "fast". I wonder a bit why the tiles from ROM at position 0 looks different in your version than from mine. I don't care anyyway because I can adapt my BorIDE Tile editor then for it, if the format is different. Now with THAT fast PutTile routine we can write very fast games.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#20
LCD Wrote:Britlion, this is great! That's what I call "fast". I wonder a bit why the tiles from ROM at position 0 looks different in your version than from mine. I don't care anyyway because I can adapt my BorIDE Tile editor then for it, if the format is different. Now with THAT fast PutTile routine we can write very fast games.

LCD: This isn't exactly well tested yet. It could be putting out bad data. :-) Congratulations on being a beta tester!
Reply
#21
britlion Wrote:
LCD Wrote:Britlion, this is great! That's what I call "fast". I wonder a bit why the tiles from ROM at position 0 looks different in your version than from mine. I don't care anyyway because I can adapt my BorIDE Tile editor then for it, if the format is different. Now with THAT fast PutTile routine we can write very fast games.

LCD: This isn't exactly well tested yet. It could be putting out bad data. :-) Congratulations on being a beta tester!
Now it is tested. You have attribute after complete bitmap date, I had Attribute after each Line of date, so I fixed this in my version. Thanks...
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#22
I'm glad it's working for you! Didn't realise you had attributes there. Would be too hard to make the code do that, I guess, owing to the method of access. You could do attributes first, or last, but not middle. It did seem to make more sense to go in order of lowest memory address to highest, somehow. You can get about 20% of the tiles changed inside one screen refresh, so it doesn't really matter too much which way round that happens.

Glad you like it. Now I'm intrigued as to what you are doing with it....
Reply
#23
boriel Wrote:The problem here is __ATTR_ADDR is taking into account a configurable SCREEN_ADDRESS variable (previously discussed here). So if you want your program to work in a variable screen address, you should work considering 0 offset an adding (SCREEN_ADDRESS) at the end, so should change it this way:

Code:
;; 23 T-States up to here
         ;; The following must be changed, start form 0 and add (SCREEN_ADDRESS) later
         ; add     a,88       ; 88 * 256 = 22528 - start of attributes.

Boriel - if you put in the limit that any screen address has to be 256-byte aligned (and really, it should be. That's the whole point of INC H going to the next line in a character), then you could just tweak the add A,88 there to add in the "page number" instead.... no?

I think that would be a better result, allowing for a variable screen address.

Incidentally, why have a variable screen address? For writing to a shadow screen? If it's about other computers....they won't have the screen layout of a spectrum anyway!
Reply
#24
britlion Wrote:I'm glad it's working for you! Didn't realise you had attributes there. Would be too hard to make the code do that, I guess, owing to the method of access. You could do attributes first, or last, but not middle. It did seem to make more sense to go in order of lowest memory address to highest, somehow. You can get about 20% of the tiles changed inside one screen refresh, so it doesn't really matter too much which way round that happens.
No need to change anything, I love it. The 20% change is no problem if I use delta-scrolling (means: draw only tiles if they are changed). The routine is fast enough for my needs.

britlion Wrote:Glad you like it. Now I'm intrigued as to what you are doing with it....
First, it will be included in the code library of BorIDE Big Grin together with PutChar and PutBlock, and then I will write one or two games using it.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#25
Hi all

I'm trying to use britlion's putTile library but I'm getting screen garbage instead of a defined 2x2 UDG. For instance, please look at this code that defines a 2x2 circle:

Code:
Dim circulo(31) As uByte => { _
      0, 63, 64, 67, 79, 79, 95, 95, _        REM bloque circulo 1 de 4
      0,252,  2,194,242,242,250,250, _
     95, 95, 79, 79, 67, 64, 63,  0, _
    250,250,242,242,194,  2,252,  0 _
}
Poke uInteger 23675, (@circulo (0))

putTile (10,10,@circulo)

Instead of printing a 2x2 circle with an outside square, it prints some screen garbage, including flashing sprites, so I must be reading and/or writing in a wrong memory address.
Please, could you tell me what is the right way to deal with putTile and 2x2 sprites?

Thanks and regards
Reply
#26
You don't have enough data, for starters. It's years since I wrote it, so I'm going back to first principles - but right at the very top it says:

' Routine to place a 16 pixel by 16 pixel "Tile" onto the screen at character position x,y from adddress given.
' Data must be in the format of 16 bit rows, followed by attribute data.



So, given I think it requires 68 bytes of data, it's clear that since you're only giving it 64 (scratch that. 32), you're going to get some random colour data.

Also, I think you are giving it UDG, rather than 16 bit rows?

Should be:

0,0, _
63,252, _
64,2, _
67,194 _
79,242, _
...
...
colour byte, colour byte, colour byte, colour byte

I think.



You are also doing a DIM of 32 bytes in your code there, and trying to put 64 bytes into it.... - that's a bit weird. So looks like you are actually defining a 1x2 half circle and giving it 32 bytes of extra data that's ignored? That would explain garbage on screen, I think. As well as the data not being ordered correctly.

Code:
Dim circulo(31)

I don't think you should use an array. I don't know what extra data is in the array that might make it break. I'd just use an ASM block with an @pointer in it. Then it's raw data.
Reply
#27
Thanks britlion, so I forgot to add more data and that's why isn't working Undecided I'll try it again, but in the meantime I was testing your FourSpriter (<!-- l --><a class="postlink-local" href="http://www.boriel.com/forum/how-to-tutorials/topic400.html">how-to-tutorials/topic400.html</a><!-- l --> and <!-- l --><a class="postlink-local" href="http://www.boriel.com/forum/how-to-tutorials/topic397.html">how-to-tutorials/topic397.html</a><!-- l -->) and it works very good for what I'm looking for.

Cheers
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)