Commodore 64 (C64) Forum Index
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
UGH! Double buffer driving me nuts!

 
Post new topic   Reply to topic    Commodore 64 (C64) Forum Index -> Scene
View previous topic :: View next topic  
Author Message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Sat Nov 19, 2011 4:27 am    Post subject: UGH! Double buffer driving me nuts! Reply with quote

OK, so I am creating my scroller and for grins and giggles, I thought I would render the map to the SCRBUFFER (characters displayed) and then render to my DBLBUFFER (hidden buffer).

Once maps were rendered on both, I would then flip the two. Granted, nothing appears to happen at that point because both buffers are the same.

I am working on some scroll/copy code but wanted to get these two buffers rendered correctly and able to flip.

Here's the deal. I can render to SCRBUFFER *ONLY* and it looks great. OR, I can render to DBLBUFFER *ONLY* and it renders great. But if I render to BOTH, it shifts the entire screen over as you can see in the shots.

I have attached my entire folder if anyone cares to fire up KickAss and give it a look. Would love some input. I'm still learning the ins/outs of the VIC but I am pushing hard every day to get better.

Ignore the blue border, btw.

I am attempting to use $2000 for chars, $3800 for SCRBUFFER and $3C00 for DBLBUFFER.

However, when I change things around, it gets worse or crashes. Guess I'm too tired to figure out what I'm doing wrong. I appreciate any tips.

I guess I will start again in the AM. Smile

Thanks.

(MAIN FILE IS IN SCROLL CALLED test01.asm)
http://dl.dropbox.com/u/471665/code.7z







PS, just for fun, here is my Ridley that uses four sprites:

Back to top
View user's profile Send private message Visit poster's website
THEWIZ
Forum Junkie
Forum Junkie


Joined: 17 Jun 2006
Posts: 525

PostPosted: Sat Nov 19, 2011 8:19 am    Post subject: Re: UGH! Double buffer driving me nuts! Reply with quote

cbmeeks wrote:

I have attached my entire folder if anyone cares to fire up KickAss and give it a look. Would love some input. I'm still learning the ins/outs of the VIC but I am pushing hard every day to get better.


In general it is a good idea to try to create the minimal repro case that shows your problem. Or at least mention where in the code you think the problem is. For example I'm looking at your code, is the problem in scroll\test01 or in goofs\scroll01?

Looking at your code...SetScreenAndCharLocation changes $d018. D018 should be set at the top of an IRQ, when you want to display the screen, not just prior to setting up data.

You do a LDA var/CMP #0. If you do a LDA you can immedaitely do a BEQ or BNE, you don't need to do a CMP #0. Saves a couple of cycles

lax (MAP_PTRH), y; personally I don't think it is a good idea to use undocumented opcodes. Why not just do ldx (MAP_PTRH),y? Ohh never mind I see thats zp.

DrawMap:
What is the initial lda/ldx for? If the first thing you do in the loop is lda and ldx?

So I don't really know what your problem is. BUT if the problem happens when you call DrawMap twice in a row, my suspicions are that you aren't initializing things properly. Like ColumnNumber and RowNumber and any other variables. You only set CURBUFFER_PTRH/L before calling DrawMap, and the other values are whatever they were before.
_________________
Back to top
View user's profile Send private message
Mogwai
Über Groupie
Über Groupie


Joined: 20 Oct 2011
Age: 48
Posts: 342
Location: Netherlands

PostPosted: Sat Nov 19, 2011 10:33 am    Post subject: Reply with quote

Okay, what I think could be the cause is: you forget to initialize ColNumber and Rownumber. After the 1st call Rownumber is left at 12...
So the next time you use that var it starts at 12, then you inc it and it becomes 13. that is not equal to 12... so it will draw 256 rows before it wraps around and reaches 12 again.

Another thing:
You use a macro. By doing so you will actually generate the loop-code twice. If you use a subroutine, you will only get the screendraw code once:

Code:

   :SetScreenAndCharLocation(SCRBUFFER, CHARSET)
   lda #<SCRBUFFER
   sta CURBUFFER_PTRH
   lda #>SCRBUFFER
   sta CURBUFFER_PTRL
   jsr DrawMap

   :SetScreenAndCharLocation(DBLBUFFER, CHARSET)
   lda #<DBLBUFFER
   sta CURBUFFER_PTRH
   lda #>DBLBUFFER
   sta CURBUFFER_PTRL
   jsr DrawMap

.
.
.


// .macro DrawMap() {
DrawMap
        lda #12                  // so we can use dec and bne instead of inc and compare
        sta RowNumber
        lda #20                  // so we can use dec and bne instead of inc and compare
        sta ColNumber
       
   draw:
   
      lda #0
      ldx #0

   !loop:
      ldy #0
      lax (MAP_PTRH), y            // X now contains tile number (from Map Data)         $AF
      lda TileCharLookupA, x      // A now contains upper left char from tile

      sta (CURBUFFER_PTRH), y      // draw upper-left of tile
      lda TileCharLookupB, x      // A now contains upper-right char from tile
      iny                        // instead of ldy #1
      sta (CURBUFFER_PTRH), y      // draw upper-right char from tile
      lda TileCharLookupC, x       // A now contains lower-left char from tile
      ldy #40                      // jump down to next line in screen buffer
      sta (CURBUFFER_PTRH), y      // draw lower-left char from tile
      lda TileCharLookupD, x       // A now contains lower-right char from tile
      iny                      // instead of ldy #41
      sta (CURBUFFER_PTRH), y      // draw lower-right char from tile
      lda CURBUFFER_PTRH            // screen buffer

   // you could do the dec ColNumber here, and depending on its
   // outcome do an add with 2 and a jmp, or add 42 and dec
   // column, depending on the outcome to prevent a double
   // addition at the end of a row (add 2 then add 40).
   // may gain a few cycles when speed is needed :-)

      clc                          
      adc #2                     // add 2 to screen buffer  (since our tiles are 2x2)
      sta CURBUFFER_PTRH         // update the screen buffer pointer
      bcc *+4
      inc CURBUFFER_PTRL
      inc MAP_PTRH
      dec   ColumnNumber
      bne !loop-
      lda   #20
      sta   ColumnNumber   
      lda   CURBUFFER_PTRH
      clc
      adc   #40
      sta   CURBUFFER_PTRH
      bcc   *+4
      inc   CURBUFFER_PTRL   
      dec   RowNumber
      bne draw
      rts
//}

Disclaimer: I have no assembler/emulator at hand at the moment, so I can't verify/test and may be completely wrong!


Last edited by Mogwai on Sat Nov 19, 2011 9:55 pm; edited 1 time in total
Back to top
View user's profile Send private message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Sat Nov 19, 2011 2:24 pm    Post subject: Reply with quote

Thanks guys! Both of you helped me out.

First of all, being really tired makes me do dumb things. lol. Working 10+ hours in Java and coming home to 6502 for 4-5 hours is tough sometimes. But the wife and kids were watching the new Twilight movie so I had time alone. Smile

THEWIZ wrote:
In general it is a good idea to try to create the minimal repro case that shows your problem.


Right, I generally try not to do a complete code dump but I was thinking that since I had chars, sprites, etc that it would be easier to give it all. Eventually, I'm going to do a real Github project and report tickets. Smile

THEWIZ wrote:
Looking at your code...SetScreenAndCharLocation changes $d018. D018 should be set at the top of an IRQ, when you want to display the screen, not just prior to setting up data.


Yep. That was an excellent point. I have removed that logic. What I'm doing now is setting a doublebuffer/flip routine at position 0 on every frame. So that I start the frame out with the doublebuffer and flip it next frame.

THEWIZ wrote:
You do a LDA var/CMP #0. If you do a LDA you can immedaitely do a BEQ or BNE, you don't need to do a CMP #0. Saves a couple of cycles


AH! Yeah that's right. Thanks. I fixed that.

THEWIZ wrote:
lax (MAP_PTRH), y; personally I don't think it is a good idea to use undocumented opcodes. Why not just do ldx (MAP_PTRH),y? Ohh never mind I see thats zp.


I remember seeing that opcode for the first time and thinking how it was really cool. But after reading more about them, I will probably get rid of it. I want my stuff to work on real hardware.

THEWIZ wrote:

DrawMap:
What is the initial lda/ldx for? If the first thing you do in the loop is lda and ldx?


The first lda wasn't needed so I removed it. The ldx was to start the initial position in my TileCharLookup tables so that I can grab the correct char out of the 2x2 tiles.

THEWIZ wrote:

So I don't really know what your problem is. BUT if the problem happens when you call DrawMap twice in a row, my suspicions are that you aren't initializing things properly. Like ColumnNumber and RowNumber and any other variables. You only set CURBUFFER_PTRH/L before calling DrawMap, and the other values are whatever they were before.


That's a good point. I now reset the col/row number correctly.


Mogwai wrote:
Okay, what I think could be the cause is: you forget to initialize ColNumber and Rownumber. After the 1st call Rownumber is left at 12...
So the next time you use that var it starts at 12, then you inc it and it becomes 13. that is not equal to 12... so it will draw 256 rows before it wraps around and reaches 12 again.


Yeah, I can't believe I missed that. lol

Mogwai wrote:

Another thing:
You use a macro. By doing so you will actually generate the loop-code twice. If you use a subroutine, you will only get the screendraw code once:


Right on. That was dumb. Now my draw map is a subroutine. I guess I got too caught up in the ease of macros but I have to remember it duplicates code. So I am going to make sure macros are only for small things where a subroutine wouldn't make sense (like setting a background color).

Also, instead of drawing the map twice I simply draw it to the screen buffer first and do a simple copy to the doublebuffer on the setup.

Thanks guys. I now have a real doublebuffered map drawing routine that is properly flipping the buffers on each frame. Now on to the scroll like before. Smile
Back to top
View user's profile Send private message Visit poster's website
Mogwai
Über Groupie
Über Groupie


Joined: 20 Oct 2011
Age: 48
Posts: 342
Location: Netherlands

PostPosted: Sat Nov 19, 2011 9:53 pm    Post subject: Reply with quote

Good to hear that you're back to adding to the game!
Did you also notice my small optimizations and comments in the sourcecode I posted earlier?
Back to top
View user's profile Send private message
THEWIZ
Forum Junkie
Forum Junkie


Joined: 17 Jun 2006
Posts: 525

PostPosted: Sun Nov 20, 2011 6:13 am    Post subject: Reply with quote

I think some people in the community have differing views on undocumented opcodes. My opinion is they should be avoided. If you want to write a demo that plays with them, fine. But if you are trying to write a game, stay away from them. Chances are you really won't be gaining much from using them, at the risk of having your code not run.

Macros, as you pointed out are great for small things. Like suppose you have a lot of LDA/STA combos. Or maybe setting the IRQ (you know LDA/STA $314/LDA/STA $315) but try not to use macros for things that a routine would be better off for. BUT also be mindful of the fact that a JSR/RTS take up 12 cycles. Sometimes it might be worth having the code duplicated to save the cycles.

Another point in posting code. Make sure the code you are posting exhibits the bug you are asking about. The code you posted had the bug commented out.

Have fun!
_________________
Back to top
View user's profile Send private message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Tue Nov 22, 2011 1:07 am    Post subject: Reply with quote

OK, going insane again. Don't know what I'm doing wrong. But I've run into a problem calling my flip routine based on a counter. Basically, I don't want the screen to flip SCRBUFFER to DBLBUFFER every frame but instead, every 4th frame.

So here is what I have:

Code:

flipbuffer:
   :BeginInterrupt()
   
   lda FLIP_COUNTER
   beq !start+
   dec FLIP_COUNTER
   jmp !exit+

!start:   
   lda #FLIP_BUF_COUNT
   sta FLIP_COUNTER
....


FLIP_COUNTER is in ZP ($40). FLIP_BUF_COUNT is the number of frames I would like to happen before the flip takes place. Currently, I've set it to 200 just to really slow things down. But it runs at full speed. Flipping every frame. So basically, I should:

1) Load the value of FLIP_COUNTER into A
2) If 0, then start flip (and then RESET)
3) If not 0, then decrement FLIP_COUNTER and exit flip routine.

What am I doing wrong?

Thanks.
Back to top
View user's profile Send private message Visit poster's website
THEWIZ
Forum Junkie
Forum Junkie


Joined: 17 Jun 2006
Posts: 525

PostPosted: Tue Nov 22, 2011 4:11 am    Post subject: Reply with quote

It doesn't look like you've got anything wrong with the code.
But what does exit do? Does it exit the IRQ properly? That is you aren't immediately calling back into the IRQ are you?

By the way, you can rewrite the code:

dec FLIP_COUNTER
beq start
jmp exit

start
lda #flip_buf_count
sta flip_counter

Not that you'll need to store 5 into the counter to skip 4 times.
_________________
Back to top
View user's profile Send private message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Wed Nov 23, 2011 1:55 am    Post subject: Reply with quote

THEWIZ wrote:
But what does exit do? Does it exit the IRQ properly? That is you aren't immediately calling back into the IRQ are you?


Yeah, the exit properly returns from the IRQ. I use the same code elsewhere. I basically pull the registers back off the stack and return.

THEWIZ wrote:

By the way, you can rewrite the code:

dec FLIP_COUNTER
beq start
jmp exit

start
lda #flip_buf_count
sta flip_counter

Not that you'll need to store 5 into the counter to skip 4 times.


Ah. Yeah. Dur. Thanks, that looks nicer.

BTW, I found the problem.

My FLIP_COUNTER used $42 in ZP. But I had another variable DBLBUFFER_PTRH that used $44 and DBLBUFFER_PTRL that used $45.

For some reason, it doesn't like that address. I change DBLBUFFER_PTRH/L to $46/$47 and it works! WTF?

Looking at Mapping the 64, it appears that I was using INPPTR and VARNAM from basic. But what would cause that problem? I verified that nothing else was using $44/$45 so I don't believe there should have been an overlap?

C64...what a strange beast she is. Smile
Back to top
View user's profile Send private message Visit poster's website
THEWIZ
Forum Junkie
Forum Junkie


Joined: 17 Jun 2006
Posts: 525

PostPosted: Wed Nov 23, 2011 5:36 am    Post subject: Reply with quote

Is this on a real 64? Can you verify the problem on VICE?
I wonder if you have some bad RAM?
_________________
Back to top
View user's profile Send private message
Mogwai
Über Groupie
Über Groupie


Joined: 20 Oct 2011
Age: 48
Posts: 342
Location: Netherlands

PostPosted: Wed Nov 23, 2011 12:43 pm    Post subject: Reply with quote

cbmeeks wrote:
BTW, I found the problem.

My FLIP_COUNTER used $42 in ZP. But I had another variable DBLBUFFER_PTRH that used $44 and DBLBUFFER_PTRL that used $45.


Shouldn't that be DBLBUFFER_PTRL in $44 and DBLBUFFER_PTRH in $45?
As long as you don't call BASIC rom code or have BASIC switched out, all those basic-related ZP locations are freely at your disposal, AFAIK.
Back to top
View user's profile Send private message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Wed Nov 23, 2011 2:34 pm    Post subject: Reply with quote

@THEWIZ
This is VICE.


Mogwai wrote:

Shouldn't that be DBLBUFFER_PTRL in $44 and DBLBUFFER_PTRH in $45?
As long as you don't call BASIC rom code or have BASIC switched out, all those basic-related ZP locations are freely at your disposal, AFAIK.



I tried doing that. Making ZP pointers LOW/HIGH and nothing worked. Not even my render code. So I believe pointers need to be in a HIGH/LOW arrangement?
Back to top
View user's profile Send private message Visit poster's website
Mogwai
Über Groupie
Über Groupie


Joined: 20 Oct 2011
Age: 48
Posts: 342
Location: Netherlands

PostPosted: Wed Nov 23, 2011 3:17 pm    Post subject: Reply with quote

Indirect indexed addressing works like this:
If $40 contains $06, $41 contains $04 and Y contains $50 then
LDA ($40),Y will access memory location $0456:
base address is
HIBYTE (from $41 = $04) LOBYTE (from $40 = $06) = $0406
Added to this is the contents of y ($50). That results in $0456.

Note that LDA($40,X) (or Indexed Indirect addressing)does a completely different thing.
Back to top
View user's profile Send private message
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Thu Nov 24, 2011 1:47 am    Post subject: Reply with quote

Thanks again.

I'm going to ask another question here and hopefully you (or someone else) might be so inclined to help everyone like me out. I'm having a hard time totally getting all of these addressing modes.

Thanks.
Back to top
View user's profile Send private message Visit poster's website
THEWIZ
Forum Junkie
Forum Junkie


Joined: 17 Jun 2006
Posts: 525

PostPosted: Thu Nov 24, 2011 8:47 am    Post subject: Reply with quote

cbmeeks wrote:

I tried doing that. Making ZP pointers LOW/HIGH and nothing worked. Not even my render code. So I believe pointers need to be in a HIGH/LOW arrangement?


Addressing on the 64 is low byte/high byte. The low byte always comes first.

If you are having a problem using $44/$45 (I thought I saw a message where you solved the problem) then post some code, as it sounds like you are doing something wrong somewhere.
_________________
Back to top
View user's profile Send private message
voult4r
Newbie


Joined: 27 Nov 2011
Age: 26
Posts: 10
Location: Corbin, KY

PostPosted: Sun Nov 27, 2011 9:23 pm    Post subject: Re: UGH! Double buffer driving me nuts! Reply with quote

cbmeeks wrote:


PS, just for fun, here is my Ridley that uses four sprites:



You sir, are a master...

Research and Development 1 & Intelligent Systems FTW!!
_________________
Keepin' it real since 1987.
Back to top
View user's profile Send private message Yahoo Messenger
cbmeeks
Master of C64
Master of C64


Joined: 22 Oct 2004
Age: 39
Posts: 1070
Location: Hixson, TN USA

PostPosted: Thu Dec 01, 2011 7:01 pm    Post subject: Re: UGH! Double buffer driving me nuts! Reply with quote

Thanks. Been pleased at what I've been able to copy with the limited colors of the C64. Kraid is looking good and should be able to get a pixel perfect (almost) copy of mother brain. 1/4 th done with her. Hi-res to boot.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Commodore 64 (C64) Forum Index -> Scene All times are GMT
Page 1 of 1

 
Jump to:  
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
Tip: Get C64 Forever for super-comfy C64 emulation with pre-installed games, demos and other goodies!


Powered by phpBB © 2001, 2005 phpBB Group