Does anyone have the files that come with Gbaguy's tutorial

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Does anyone have the files that come with Gbaguy's tutorial
by on (#29888)
I am trying to learn NES programming by reading Gbaguy's tutorial. I know from browsing the forum it is not the ideal doc to learn from. But I am stuck with using a bmp file as background and I can't make headways out of the other tutorials (NES ASM Tutorial - it doesn't cover using a BMP as background; joker21's 8-bit beast doc; etc)

However the links to the files used in the tutorial are broken. So I was wondering if anyone has copies of those files and would be willing to provide them.

TIA.

by on (#29890)
I just went to the page and was able to download it.

http://patatersoft.info/gbaguy/day1n.htm

If you click on the "here" that's highlighted first, you should be able to download it.

EDIT: Also, just use a NES graphics editor such as YY-CHR to make graphics, and make a .nam file with a tile laying program to make a background.

by on (#29892)
Thanks so much for the quick response.

Sorry for the confusion. I meant the files used for the tutorial (such as our.pal, etc.). I was able to download the tutorial itself. In going through it, I found out some of the hyperlinks were broken, particularly those for the graphic files. Unfortunately, this is exactly where I am having problems.

I think I got the header and setting up the PPU. The NES ASM tutorial has a very good tutorial on that.

My problem is converting an existing BMP file (say 72 dpi, 242 x 242) into CHR. I was able to use YY-CHR to convert it to 128 x 128.

So to create the nam file, I merely load the CHR file into TLP and save it with the extension NAM or do I have to do something specific first?

Also, are there any good tutorials for YY-CHR and TLP?

Again, I really appreciate the prompt response. Thanks so much.

by on (#29893)
I don't think there are many tutorials for either, there's not much to them. All you do in YY-CHR is draw using any of the four colors you have selected. You have to set it to 2BPP (2 bits per pixel) NES mode.

As for the pallete and the name file, I know what you're talking about now. When I first started, I didn't have access to those files either. You can make a pallete easily with .DB statements. You should also just make your own .nam file with a tile laying program. The code provided should work with any .nam file and any pallete.

EDIT: About TLP, you don't save it as a .nam extension. You need a tile laying program, I think there's one on the main page.

by on (#29894)
HI Celsius,

I think I understand doing the palette part using .db. But I still have problems with name tables and attributes.

I was able to modify Chris Covell's Amiga demo program to compile using NESASM3. In doing so I renamed the file AmigaLogo_CHR-ROM to Amiga.chr and did an .incbin.

The resulting program runs just fine using FCEUXDSP. But when I replace the amiga.chr with my own 128x128.chr the graphics in the modified program come out distorted. While the 128x128.chr loads fine in YY-CHR, the amiga.chr comes out distorted and I am not able to set it properly.

Also, I thought TLP is a tile laying program?

Any suggestions? TIA

by on (#29895)
There is more than one kind of program, and I think Celius might be confusing their names:
  1. Tile editors, or primitive paint programs that produce .chr files. These include Tile Layer Pro, Tile Molester, YY-CHR, and 8TED.
  2. Map editors, used to lay out tiles in patterns. Some are specialized to make .nam files (such as NSA and 8name), some are specialized to make maps in some other format (such as Mario Improvement and Lunar Magic), and some are more general (such as Open tUME).
  3. Programs that have both a tile editor and map editor in one executable.

by on (#29904)
Isn't TLP just a tile editing program? That's what I was thinking. I didn't think that you could actually lay tiles in a NAM file like the title suggests.

If nothing else, you can make a NAM file with .db statements. What you'd have to do is define all the tile data, and then at the end, you'd have to define the attribute data. Use the same routine to load it, and it'll work fine.

And also, are you following GBAguy's setup? If so, I'm pretty sure he .incbins 2 4k CHR files. If you're using YY-CHR, you'll probably want to do away with that and just incbin 1 8k file, because that's the size YY-CHR saves the files at.

by on (#29906)
tepples wrote:
Tile editors, or primitive paint programs that produce .chr files. These include Tile Layer Pro, Tile Molester, YY-CHR, and 8TED.


I loaded the amiga logo file (renamed amiga.chr) from Chris Covell's demo program in Tile Layer Pro but was not able to display it properly. Yet it displays properly when the program is executed.

On the other hand, I converted a bitmap into a 128x128 chr that displays properly in TLP but when I replaced the amiga.chr with this chr, the display is broken up. (Disregarding for now the difference in the palette.)

What am I doing wrong here?

by on (#29907)
Uh-oh. Sorry - the post above is from me. I forgot my friend was logged on to the site and went ahead and posted while using his account. Sorry about that.

by on (#29908)
Celius wrote:
If nothing else, you can make a NAM file with .db statements. What you'd have to do is define all the tile data, and then at the end, you'd have to define the attribute data. Use the same routine to load it, and it'll work fine.


That is where I am having problems. javascript:emoticon ':cry:' Anyways, I will give it a try again.

But in terms of modularity and re-usability, wouldn't it be more efficient to basically include binaries?

Quote:
And also, are you following GBAguy's setup? If so, I'm pretty sure he .incbins 2 4k CHR files. If you're using YY-CHR, you'll probably want to do away with that and just incbin 1 8k file, because that's the size YY-CHR saves the files at.


I will check this out, too.

I wish there was a tutorial that provides for a step-by-step instructions on developing a demo program that would include all the common features - backgrounds, sprites, collision detection, levels, maps, high scores, etc.

I guess some people (like me) are more used to learning from a well-documented demo program and using that as a base to develop from. Kinda like being brainwashed too much from a Hello, World learning approach.

Again, my thanks to you and tepples.

by on (#29909)
You're not doing anything wrong. The display is broken up in the CHR file because what's being displayed on screen is 256 pixels wide, and it has to somehow be broken up to fit into the 128x128 CHR file. The reason it's broken up if you replace the CHR file with a different one is because the ROM is putting tiles on the screen assuming that the incbined CHR file is broken up in the same way that the amiga logo file is. Do you understand?

About the tutorial you were talking about. It would be good to have a good tutorial about the basics of the NES, but high scores and maps are entirely different. Those sorts of things have way more than one answer. It really depends on what type of game you want to make. Once you understand the basics of the NES itself, making levels and whatnot will be SO much easier. You need to understand what the outcome needs to be before designing levels. If you really think about what needs to be done, doing what needs to be done will be alot easier.

by on (#29948)
Celius wrote:
You're not doing anything wrong. The display is broken up in the CHR file because what's being displayed on screen is 256 pixels wide, and it has to somehow be broken up to fit into the 128x128 CHR file. The reason it's broken up if you replace the CHR file with a different one is because the ROM is putting tiles on the screen assuming that the incbined CHR file is broken up in the same way that the amiga logo file is. Do you understand?


Yes, I understand - it is a very clear explanation. My question then is I read in one of the tutorials bitmaps in chr should be 128x128. But why is the Amiga.chr bitmap 256x256? Also, isn't the NES screen closer to 256x256 than 128x128, so why is the bitmap of the chr file 128x128 instead of 256x256?

I went through most of the tutorials again but can't seem to find one that includes a lesson on converting a bitmap file suitable for inclusion as a background in a nes file. I have managed to convert a graphic file into a 128x128 chr but it ends up displaying twice in the screen (side by side) with the right display having some color problems.


Quote:
About the tutorial you were talking about. It would be good to have a good tutorial about the basics of the NES, but high scores and maps are entirely different. Those sorts of things have way more than one answer. It really depends on what type of game you want to make. Once you understand the basics of the NES itself, making levels and whatnot will be SO much easier. You need to understand what the outcome needs to be before designing levels. If you really think about what needs to be done, doing what needs to be done will be alot easier.


True, maps might be an advanced topic but high scores can be included even in the simplest games like hangman or even pong. Since the algorithm for this is the basically the same for all, it would be nice to include it in a tutorial to develop a simple game. Just my 2 cents though.

Thanks.

by on (#29953)
sebanonis wrote:
Yes, I understand - it is a very clear explanation. My question then is I read in one of the tutorials bitmaps in chr should be 128x128. But why is the Amiga.chr bitmap 256x256? Also, isn't the NES screen closer to 256x256 than 128x128, so why is the bitmap of the chr file 128x128 instead of 256x256?

I went through most of the tutorials again but can't seem to find one that includes a lesson on converting a bitmap file suitable for inclusion as a background in a nes file. I have managed to convert a graphic file into a 128x128 chr but it ends up displaying twice in the screen (side by side) with the right display having some color problems.


The reason CHR files are 128x128 is because it's broken up into 256 8x8 pixel tiles. Only one byte is required to define Tile IDs. If a CHR file was 256x256, it would require 2 bytes to define a tile, so you would have to write to $2007 twice. So the NES without doing some sort of trickery would not allow you to have every tile on screen be different. You have to use at least one tile more than one time.

How are you writing information to the background? Please clarify a little more what exactly you're doing in your code.

by on (#29958)
HI Celius,

Below is the code. Basically it is a mishmash of a couple of demo programs.

Code:

;console2.asm

PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
OAMADDR = $2003
OAMDATA = $2004
PPUSCROLL = $2005
PPUADDR = $2006
PPUDATA = $2007

   .inesprg 1   ; 1x 16KB PRG code
   .ineschr 1   ; 1x  8KB CHR data
   .inesmir 0   ; mapper 0 = NROM, no bank swapping
   .inesmap 1   ; background mirroring

   .bank 0   
   .org $C000       

RESET:
  SEI             ; disable IRQs
  CLD             ; disable decimal mode
  LDX #$40
  STX $4017       ; disable APU frame IRQ
  LDX #$FF
  TXS             ; Set up stack
  INX             ; now X = 0
  STX PPUCTRL   ; disable NMI
  STX PPUMASK       ; disable rendering by settings 3 and 4 to 0
  STX $4010       ; disable DMC IRQs

vblankwait1:      ; First wait for vblank to make sure PPU is ready
  BIT PPUSTATUS
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT PPUSTATUS
  BPL vblankwait2

  LoadPalettes:
  LDA PPUSTATUS   ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006       ; write the high byte of $3F00 address
  LDA #$00
  STA $2006       ; write the low byte of $3F00 address
  LDX #$00
LoadPalettesLoop:
  LDA palette, x
  STA $2007
  INX
  CPX #$20
  BNE LoadPalettesLoop



;********* Initialize Palette to specified colour ********

   lda   #$21
   sta   $2006
   lda   #$00
   sta   $2006         ;Point 8 rows down in Name Table.

   ldx   #$00          ;-
   txa                 ; \

DefMap0:
   ldy   #$10
   tax

DefMap1:
   stx $2007
   inx                 ;This part sets up two identical columns
   dey                 ;Of Pattern Tables $00-$FF
   bne   DefMap1
   ldy   #$10
   tax

DefMap2:
   stx $2007
   inx
   dey
   bne   DefMap2
   txa
   cpx   #$00         ; /
   bne   DefMap0      ;-

;------------------------------
;Set up Attribute Table
   lda   #$23
   sta   $2006
   lda   #$D0
   sta   $2006        ;Point to right spot in Attr. Map

   ldy   #$02
DrawAtt:
   lda   #$00
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   lda   #$55        ;Palette #1
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   dey
   bne   DrawAtt
;------------------------------

   lda   #$00
   sta   $2006
   sta   $2006       ;Reset PPU
   sta   $2005
   sta   $2005       ;Reset Scroll

;Enable vblank interrupts, etc.
   lda   #%00011000
   sta   $2000
   lda   #%00011110  ;Screen on, sprites on, show leftmost 8 pixels, colour
   sta   $2001
;  cli               ;Enable interrupts(?)

Forever:
  JMP Forever        ;jump back to Forever, infinite loop

NMI:
   RTI
IRQ:
   RTI

   .bank 1
   .org $E000
palette:
   .db $0F,$20,$0F,$16,$15,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$0F
   .db $0F,$1C,$15,$14,$31,$02,$38,$3C,$0F,$1C,$15,$14,$31,$02,$38,$3C


   .org $FFFA
   .dw NMI
   .dw RESET
   .dw IRQ   

   .bank 2
   .org $0000
   .incbin "jb.chr"   ; jb.chr is a 128x128 bitmap converted into chr


The resulting screen shows the bitmap twice, side by side, with the right image partially covered with red transparent color.

Would really appreciate any help. TIA.

by on (#29959)
The second portion of your pallete consists of orange and red colors. In the attribute section of your code, you tell it to make the right half use the second pallete by storing $55 in $2007. What other problems are there?

EDIT: Just as an exersise, look at the loop that stores the tiles on the background, and try figure out why it stores the data side by side. Try work out the loop, and keep track of the values of the X, Y and A registers. You should be able to see why it stores it that way. If you really are having trouble, I'll explain.

by on (#29961)
Thanks.

Will check it out.

BTW, Happy New Year!

by on (#29998)
HI Celius

I reread the tutorials on the 6502 opcodes -

Code:
 lda   #$21
   sta   $2006
   lda   #$00
   sta   $2006       ;Point 8 rows down in Name Table.

   ldx   #$00          ;-
   txa                 ; \

 DefMap0:
   ldy   #$10        ; set Y to 16
   tax         ; xfer A to X   

DefMap1:
   stx $2007
   inx               ; Increment X
   dey               ; Decrement Y
   bne   DefMap1     ; If Y not 0, go back to DefMap1
   ldy   #$10        ; Else restart Y
   tax

 DefMap2:
   stx $2007
   inx
   dey
   bne   DefMap2

   txa
   cpx   #$00          ; /
   bne   DefMap0      ;-



Is the above code the part that draws the two images? Just wanted to make sure I am on the right track. I am still grappling with how graphics is generated via the PPU, whether the tiles are written sequentially or via nested loops for rows and columns.

Re the palette -

Code:
DrawAtt:
   lda   #$00
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   lda   #$00       ;Palette #0
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   dey
   bne   DrawAtt


The second LDA is used for the second image, right? So if I am able to get rid of the second image, I won't need the second LDA. Is this right?
Code:


TIA.[/code]

by on (#29999)
You are correct about that being the code that displays the two images. What happens is this:

The loop starts off with A being 0, and X being 0. The first loop stores X into $2007 16 times, each time it stores, X increases by 1. After that first loop, A, or 0, is transfered into X. That is the cause of the two contiguous images. The first loop stores tiles until it reaches the middle of the row. The loop on the bottom basically stores whatever was stored in the first half in the second half.

About the attributes, you don't need to load #$00 again if A is already #$00. But you'll still need to store data into $2007 8 times per row, unless you manually reset the pointer.

by on (#30005)
HI Celius,

I commented out the nested loop as shown below:

Code:
   lda   #$21
   sta   $2006
   lda   #$00
   sta   $2006       ;Point 8 rows down in Name Table.

   ldx   #$00          ;-
   txa                 ; \

DefMap0:
   LDY #$10          ; set Y to 16

   TAX         ; xfer A to X   
DefMap1:
   STX $2007
   INX               ; Increment X
   DEY               ; Decrement Y
   BNE DefMap1       ; If Y not 0, go back to DefMap1
;  LDY #$10          ; Else restart Y

;  TAX
; DefMap2:
;  STX $2007
;  INX
;  DEY
;  BNE DefMap2

   TXA
   CPX #$00          ; /
   BNE DefMap0       ;-


But in doing so, I still get the two images, albeit they are both distorted. What am I doing wrong?

As for the attribute, am I right in concluding I don't need to do the loop?

Code:
;   ldy   #$02      ; No need to do a loop   
; DrawAtt:           ; No need to do a loop
   lda   #$00
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
  ; dey              ; No need to do a loop 
  ; bne   DrawAtt    ; No need to do a loop


As always, thanks for your patience in helping me.

by on (#30020)
sebanonis wrote:
But in doing so, I still get the two images, albeit they are both distorted. What am I doing wrong?.


Okay, I should've asked earlier. What exactly are you wanting on screen? Just one 128x128 display in the center of the screen?

sebanonis wrote:
As for the attribute, am I right in concluding I don't need to do the loop?

Code:
;   ldy   #$02      ; No need to do a loop   
; DrawAtt:           ; No need to do a loop
   lda   #$00
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
   sta   $2007
  ; dey              ; No need to do a loop 
  ; bne   DrawAtt    ; No need to do a loop


Actually, I was trying to say that in general, you don't NEED a loop to store information to the background. I wasn't referring to your code. But you'll want to do the loop in your case.

If I were you, I'd scrap the whole mishmash of code, and right a demo from scratch. That way, you should know what's going on. But explain what you want to happen please.

by on (#30021)
Hi Celius,

Basically I am starting with just a simple program - to put a logo in the background. I have converted the logo into a 128x128 bmp, then converted that to a CHR. That's all.

I discovered the old message board and saw some old threads on backgrounds. I am presently reading these and hopefully should learn something from them.

I agree, writing a simple demo from scratch would be the preferred way and I started out doing that but soon hit a wall with the graphics. At least, using a base demo program, I can experiment by changing the values and studying the result. Admittedly it is not the most scientific way, but I am beginning to learn bits and pieces from doing so.

Thanks.

by on (#30056)
Well, if you want a 128x128 logo on the background, I'm assuming you want it in the center of the screen. How about I just do this. This should copy the whole thing to the background in the center of the screen:

Code:
   lda #$20      ;Here we tell the PPU to start putting tiles on the name table
   sta $2006   ;At location $20E8.
   sta PPUPointerH   ;We save the value of the starting pointer
   lda #$E8
   sta $2006
   sta PPUPointerL
   ldy #0      ;Start with $0
-
   sty $2007.w   ;Store Y in $2007
   iny      ;Increase Y by one to get the next tile value
   tya      ;Here we check if Y is a multiple of $10 by seeing if the low
   and #$0F      ;4 bits are $0
   bne -      ;If Y is not equal to zero after eliminating the upper 4 bits,
         ;Do the loop again (It will loop 16 times)
   clc      ;We take the previous PPU address, and we tell it to point to
   lda PPUPointerL   ;The next row.
   adc #$20      ;Add #$20, because that's how many tiles are in a row
   sta PPUPointerL   ;If you don't know, this is an example of 16-bit addition. If
   lda PPUPointerH   ;PPUPointerL wraps around, the Carry flag will be set. Here
   adc #0      ;We tell it to add #0 + the Carry flag to PPUPointerH. If the carry flag
   sta PPUPointerH   ;is set, it will add one to PPUPointerH.
   lda PPUPointerH   ;Store the new PPU pointer values in $2006
   sta $2006
   lda PPUPointerL
   sta $2006
   cpy #0      ;See if Y is #0. If it is, that means we've wrapped around, and thus,
         ;reached the end.
   bne -      ;If not, go back to do the loop.


You'll need to assign variables in RAM to PPUPointerL and PPUPointerH. I tested it and it works. It should work for you.

by on (#30061)
Hi Celius,

Thanks so much.

Will study it first to make sure I fully understand everything before proceeding to the next phase.

Spent the last few days reading on name tables, pattern tables, and attribute tables.

I have to admit it is really frustrating trying to learn NES programming without a comprehensive structured tutorial.

You don't have any idea how appreciative I am with your patience and willingness to provide guidance.

Thanks again!

by on (#30071)
Oh also, delete the ".w" at the end of "sty $2007" if you're not using WLA-DX. For some reason, there's a bug where you need to put ".w" at the end of $2007 if you're storing X or Y into that register.

I am happy to be of help, because I know how frustrating it can be. I came without any programming experience, and for about 6 months, I didn't really know what I was doing. It just takes time and patience, and not getting frustrated. You should see SNES programming. The only thing you really have to go by is the documentation out there, because not many people program for the SNES anymore. Thankfully, the NESdev scene is really active in comparison.

by on (#30085)
Hi Celius,

It works!

I set the PPUPointer to $2100, labeled the loop and everything came out okay. But I still need to digest everything to make sure I fully understand everything before proceeding. Will also experiment with some of the values.

Thanks so much. Really appreciate it.

by on (#30086)
Hi Celius,

There is a short green horizontal bar right at the upper left corner of the screen. What could be causing it? TIA

by on (#30099)
Most likely you have sprites turned on, and you haven't assigned proper values to them. Are you using sprite DMA? If so, that's probably it if you aren't doing anything with the sprites. If you're not using the sprites, make sure you clear whatever page ($100 byte section in RAM) with any value between $F0-$FF. This will render them off screen, and they will not be visible.

Example:
Code:
    ldx #0        ;pretend you're assigning $300 to sprite DMA
    lda #$FF
-
    sta $300,x   ;This will store $FF in that whole page.
    inx
    bne -

    blah code

nmi:
    lda #3        ;Store #3 (For $[b]3[/b]00) in $4014
    sta $4014     ;To let it know to use that page for sprite data


If sprites are turned on, you want all unused sprites off screen, so you can do this by making the Y coordinate any value between $F0-$FF. That I'm pretty sure will solve your problem.

by on (#30107)
Hi Celius,

Yup, I had sprites turned on. Set D4 to 0 and everything turned out okay. Actually I played around with the palette table and managed to make the bar disappear by matching the background color. Of course I know this is a cheat and is not a feasible solution but I took the opportunity to learn more about the palette table. :)

Again, thanks!

by on (#30108)
Hi Celius,

It works!

I set the PPUPointer to $2100, labeled the loop and everything came out okay. But I still need to digest everything to make sure I fully understand everything before proceeding. Will also experiment with some of the values.

Thanks so much. Really appreciate it.