News:

11 March 2016 - Forum Rules

Main Menu

Getting Started on a VWF?

Started by justin3009, April 11, 2011, 10:57:08 AM

Previous topic - Next topic

RedComet

bsnes should've come up with something like this: Link

From there you just use the Step button (make sure you have S-CPU Step checked) to step into the code at the breakpoint.

Also, I think I might've given you the wrong advice earlier. It seems like you already know where the data is coming from:


DMA[0]: CPU->PPU Mode:1 0x000604->0x2118 Bytes:34 (inc) V:232 VRAM: 0984 (1,0) word


At least, if $984 ($1308) in VRAM is where the font is being stored. You got the next piece of the puzzle right there: it's coming from $604 in RAM. So figure out when the data at $604 is written. I'm a really horrible teacher. I know how to do what I can do but I'll be damned if I can explain how I do it.  :-[
Twilight Translations - More than just Dragonball Z. :P

justin3009

#21
Edit:
DMA[0]: CPU->PPU Mode:1 0x000604->0x2118 Bytes:2 (inc) V:235 VRAM: 08A6 (1,0) word
The actual dialogue where you first talk to Zero in-game starts at $114C in VRAM.

7E0604 in RAM is where each letter's getting written which ends up being loaded from:


This is for actual in-game dialogue:
$00/E679 A6 A5       LDX $A5    [$00:00A5]   A:0145 X:0001 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0842 VC:078 FC:20 I:00
$00/E67B 9D 04 06    STA $0604,x[$06:0604]   A:0145 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0874 VC:078 FC:20 I:00 - Storage for Letter being written
$00/E67E A5 6E       LDA $6E    [$00:006E]   A:0145 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0920 VC:078 FC:20 I:00
$00/E680 9D 05 06    STA $0605,x[$06:0605]   A:0108 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzC HC:0952 VC:078 FC:20 I:00


But the first letter/actual text actually gets loaded at:

$40/0034 B1 68       LDA ($68),y[$12:E827]   A:0A3E X:0010 Y:0006 P:envMXdIzC
$40/0036 C8          INY                     A:0A49 X:0010 Y:0006 P:envMXdIzC
$40/0037 AB          PLB                     A:0A49 X:0010 Y:0007 P:envMXdIzC


The game uses US-ASCII for it's text.  So the starter text in game, "In the year" it'd be: 49 6E 20 74 68 65 20 79 65 61 72

The first letter loads here though because there's a split in the dialogue to load a custom table up for certain text areas.  The code was split into two things as well, one for X and one for Zero.


Edit: Ohhh so that's what I was suppose to do with bSNES.  That makes more sense now.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Nightcrawler

It sounds like you've figured it out and know what's going on now.  :cookie:

The next step would be plotting out how you can turn that into a dynamic routine. Don't even worry about VWF for now, plan on doing a dynamic routine with the same static font. The game will load the dialog character. You'll want to add new code to take that and load the appropriate font character from ROM into free location in RAM. Then, you want to load that into VRAM at either a free space or over the existing font. Remember that other non VWF portions of the screen may still need it. I don't know what screens you're doing or if that applies, but if it does, you'll need to use some other free VRAM area rather than your font. You can get it in VRAM by adding transfer yourself in code there, trying to tap into some existing game DMA queues in the NMI routine, or adding your own NMI hooks to do it. It's your choice, but it's probably simplest (not necessarily smartest or most efficient) for learning purposes to add the transfer yourself in normal code. Then, you'll want to alter the part of the routine that stores the tilemap data in RAM. You'll want to change it to point to the new tile you loaded in VRAM.

The game used to have a font in VRAM and change the screen tilemap to reference those characters. After modifications, you will be drawing characters in RAM as they are loaded, transferring them to VRAM and changing the on screen tilemap to reference those. Rather than map to specific font letters in VRAM, the tilemap is basically just going to be incrementing now, pointing to tile 1, 2, 3, then 4 etc. as you draw them along. There's no more font in VRAM. It's just you drawing new tiles on demand, and referencing those tiles in the tilemap.

I'd probably have a few smaller objectives:
1. Successfully load and draw a single font character in RAM in the text routine. Verify this works.
2. Successfully transfer that single tile from RAM to VRAM at desired new location. Verify in VSNES via savestate that it works.
3. Now work on the mechanics of looping where for each letter, you draw to the same area in RAM and transfer to the next space in VRAM, and increment the next tilemap entry.
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

justin3009

Every screen uses the same font except for the menu screen which uses it's own, but it's loaded separately if I remember correctly.

So the first step would be to take the letter from ROM and put into a free spot in RAM.
Then take what's in RAM and transfer it to VRAM.
Then write a loop.

I'm going to ignore the last two steps for now as the first one already has me caught.  So would taking the letter from ROM consist of where the paragraphs of text originate from?  Like the, "In the year" text, it'd take the I and then throw into RAM?  I thought it was technically already doing that since 7E0604 was the storage place for the letters as it's taking the letters directly from the paragraph then storing them there, then writing it on the screen.

Or am I missing the main point on that first step already ._.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Nightcrawler

There's the text character and then there's the graphical font data. If I'm not misunderstanding, we've established your game loads the text character, and alters a tilemap entry to reflect it on screen. The graphical font data for the entire font appears in VRAM one time.

You're jumping in after the game loads the text character and dynamically rendering the graphical font data for that text character in RAM. Clear? Does the game already do that?
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

justin3009

#25
Ah okay.  The game just loads the Tilemap and that's it, not the entire string.  I'll try and see if I can get the text string itself to load in VRAM.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

KingMike

Like if you open a ZSNES savestate (since they're uncompressed), made while text is on screen, is the entire text string visible in a tile viewer?
If not, then it's tilemap based, and what NC is suggesting as practice is to make the string visible in a tile viewer.
Each time the game reads a letter of the font, you copy the entire graphics tile for that font character to RAM/VRAM.
"My watch says 30 chickens" Google, 2018

justin3009

#27
Oh no, not the entire string.  It's just the entire font itself is loaded and that's it.  And ohhh okay! I get it now.  I'll see what I can do.

Edit: I was speaking with someone about what to do exactly for it to load the text string into VRAM and all confusion went afoot.

There was talk of DMAing and this code came up from a site: http://wiki.superfamicom.org/snes/show/Making+a+Small+Game+-+Tic-Tac-Toe

ldx #UntitledData   ; Address
lda #:UntitledData  ; of UntitledData
ldy #(15*16*2)      ; length of data
stx $4302           ; write
sta $4304           ; address
sty $4305           ; and length
lda #%00000001      ; set this mode (transferring words)
sta $4300
lda #$18            ; $211[89]: VRAM data write
sta $4301           ; set destination

ldy #$0000          ; Write to VRAM from $0000
sty $2116

lda #%00000001      ; start DMA, channel 0
sta $420B


The UntitledData I was told is possibly the tiles?

So from the looks of it, it's:
1. Loading the tiles into X
2. ???
3. Sets the length?
4. Stores to X/A/Y
5. Sets the mode (?)
6. Stores A.
7. Loads the data from a high/low address from VRAM
8. Stores it to a destination in the VRAM (I'm guessing where the font is located in VRAM goes here)
9. LDY's to the start of VRAM

I'm not even sure if this code is correct or not, or if what I'm looking at in general is correct.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

justin3009

Sorry to necropost but I've been looking at VWF routines a bit more.

I noticed and just realized when re-looking this: It actually LOADS the font character's graphics itself (From what I saw anyway) and copies that into RAM.  Then.. does it store that into VRAM?  Then when doing so, it does basically the same thing for the next letter but it loads a value before hand to dictate how much space is between each letter?

I'm so sorry if I'm not getting this after all this time.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Spikeman

Quote from: justin3009 on December 22, 2012, 09:40:22 PM
Sorry to necropost but I've been looking at VWF routines a bit more.

I noticed and just realized when re-looking this: It actually LOADS the font character's graphics itself (From what I saw anyway) and copies that into RAM.  Then.. does it store that into VRAM?  Then when doing so, it does basically the same thing for the next letter but it loads a value before hand to dictate how much space is between each letter?

I'm so sorry if I'm not getting this after all this time.

Are you talking about what the game already does? Or the potential VWF?

Just to clear things up, it sounds like this is what the game is doing:

1) At some time before text is written, the entire font graphics are loaded to VRAM
2) When a character is written, the value corresponding to the correct letter in the font is written to the tilemap

This is what you need to make it do:

1) Scrap the entire routine that loads the font to VRAM (you can use the space for your new routine)
2) When a character is going to be written:
a) Load the appropriate graphics tile to an open space in VRAM (start at the beginning of where the font gfx were, and increment the pointer each time you need a new tile)
b) Set the tilemap to the tile you wrote to

It sounds like what you're being told to do (and I agree, it's a good first step) is to first just change the routine so it loads (the graphics of) each character "on demand" instead of all at once, writing the text one tile at a time. The next step would then be to implement the shifting of all the graphics (so you can have multiple letters in one time), and adjusting it to only use a new tile when the previous tile is full.

Does that clear anything up?

(Also, I'm not entirely sure why you're trying to load the graphics from ROM->RAM->VRAM. Is this a peculiarity of the SNES? Or is it just to save time so it's not doing too much during Vblank?)
Open Source Hacking Projects: Guru Logic Champ, Telefang 2, (Want more? Check out my GitHub!)

justin3009

I was looking at Chrono Trigger and Tales of Phantasia slightly for the VWF.  I noticed that it was loading the font graphics directly from ROM when going through the routine to load each letter.  Then storing it to RAM or something along those lines.

But that explanation actually sounds a lot more simple so I may try doing that.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

LostTemplar

On the SNES, if you're doing a VWF you basically have to write it to RAM first because you have to shift and OR all characters' graphics together (well, you could write to VRAM and read it back for the shifting and OR'ing, but then you could only do it in vblank, which is too short usually). What Spikeman's describing is a fixed-width font if I understand him correctly.

justin3009

A fixed-width is a good step to a VWF in general.  I'd honestly have a fixed-width first just so I can see how it works then go from there.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

justin3009

Alright, back to this again except with a new game.  Though it's been translated, I'd rather try to stick with something I've written... HOPEFULLY I can make this work.

I'm working on Sailor Moon - Another Story at the moment.  Planning to revamp a horde of this mess into something less throw uppish.  Besides sprites/voices being worked on, the dialogue system is now heavily in the works.

The game has nothing except just a portrait along with Layer 3 being thrown into the screen with no background color or anything to it.  Figured out how to actually pull HDMA up onto the screen so I can start making a pretty little dialogue box.  But before I do that I want to try and get a VWF going.

The game is farther ahead in the steps than what MMX1-3 were.  The font IS loaded directly from rom staring at C00000 (Literally right at the start of the game).  It's a 16x16 font that gets pulled from ROM then stored directly into VRAM.  I've found the base area for where it stores into VRAM, how it loads the graphics I believe and all that fun stuff.  There's even a fun thing that after a certain byte is hit, it jumps 180 for a new line and such.

But now that the basis of this is already there (It's not fixed width per se), where would be the next step to start to make this into a VWF?
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Spikeman

Quote from: justin3009 on June 17, 2013, 01:46:12 AM
The game is farther ahead in the steps than what MMX1-3 were.  The font IS loaded directly from rom staring at C00000 (Literally right at the start of the game).  It's a 16x16 font that gets pulled from ROM then stored directly into VRAM.  I've found the base area for where it stores into VRAM, how it loads the graphics I believe and all that fun stuff.  There's even a fun thing that after a certain byte is hit, it jumps 180 for a new line and such.

But now that the basis of this is already there (It's not fixed width per se), where would be the next step to start to make this into a VWF?

When you say the font is loaded directly from the ROM, you mean that when each character is printed it is loaded from ROM and copied directly to the proper spot in VRAM tile? (Instead of loading the font to VRAM and printing chars by altering the tilemap.) I'll assume this is the case. And btw, if every character is the same width, it is fixed-width. What I was talking about before was a fixed-width font, but it was about changing the routine so that it'd be easier to modify into a VWF, not changing from __ to a fixed-width. If you're starting with something similar to what I described, good, that should be easier to work with. Although, it being a 16x16 font will add slightly more complexity.

Here are the next few steps I would do:

1a) Relocate the section of code that copies data to VRAM. Modify the original code so that it calls this routine to copy the data. (Note: for a 16x16 font, this routine should draw a half the character - an 8 px wide strip. So you will need to call the routine once for the first half and once for the second half. You'll see why this is in a bit.)

1b) Instead of copying directly from the ROM, copy the data from the ROM to some unused RAM area. Then use the a call to the routine from 1a to copy from RAM to VRAM. After this step, you'll have code that copies the left half of the character from ROM->RAM-> VRAM, then does the same with the right half.

2) Modify the code so that it draws each half twice. You'll need to modify the part of the code that increments the tile number that is printed to for this. This is why we relocated the code in 1a - it's easy to add another call. I made a diagram to see why you do this:



3) The first time the character (or half of character) is drawn, shift each row of pixels right by X. (On this step I usually leave X as a hardcoded value, like 3 or 4, so it's obvious if it works.) The second time each half is drawn, shift left by 8-X. Shifting should be done on the data in ROM, so it can be done outside of vblank. Copying must be done in vblank.

(Note: I'm not sure exactly how bitshifting works on SNES, but you'll need to pay attention to the bit depth of the graphics. If it were 1bpp, an 8 pixel row would be one byte, and you could just shift right once per pixel you wanted to shift. But if it were 2bpp, you'd have two bytes, and you'd need to shift twice, making sure to shift the leftover from the first byte into the second byte. I can post more details on the shifting if you have trouble.)

At this point you should have something similar to the diagram, but you'll only see the second half of the character, because we still have it overwriting the previously drawn data.

4) Now, we'll make it combine the two halves. The first time the character is drawn, notice how it is already shifted over. In reality, there would be another half of the previous character there which we don't want to overwrite. So instead of just copying the character, you should load the data that is already written to the tile (or just keep this in RAM) and OR in the new, shifted-over data. A single OR is all you need if the BG color is represented by zero bits only. If it's something else, you'll need to do some masking, which I can post about more if needed.

The second time each half is drawn, you'll want to increment the tile number, since theses halves represent the "overflow" - the pixels that have spilled over into the next tile. Again, OR in the data.

At this point you should have the font printing normally, except everything is shifted over 4 pixels.

5) Now, replace the hardcoded X value from before with a calculated value (I would just devote some RAM byte for this use). You'll want to initialize the value to 00 every time a new string is going to be printed, or when there is a line break. Then after each character is printed, you'll want to calculate the amount of pixels left over, and store them here. For example, if the first character was 11 wide, you'd have 5 left over. Then if the next char was also 11 wide, the first 5 px of it would be drawn in those 5, the second 6 pixels in the next tile, and you'd have 2 left over. [So I think the formula for this is: 8 - ( ((previous overflow) + (char width)) mod 8 )]

To get the width of the character, make a "width table" somewhere in the ROM, and just use the value of the character being drawn to look up the width.

6) Now you should have a legitimate VWF, but there may be some bugs you need to handle. For example, if a character doesn't need to be shifted at all (ie. X is zero) you can just draw it normally. There might be some other edge cases you forgot to handle - for example, line breaks, or starting a new page of dialog.


---

Hopefully that helped, I can be more detailed if any point didn't make sense.
Open Source Hacking Projects: Guru Logic Champ, Telefang 2, (Want more? Check out my GitHub!)

KingMike

Quote from: Spikeman on June 19, 2013, 06:48:14 PM
(Note: I'm not sure exactly how bitshifting works on SNES, but you'll need to pay attention to the bit depth of the graphics. If it were 1bpp, an 8 pixel row would be one byte, and you could just shift right once per pixel you wanted to shift. But if it were 2bpp, you'd have two bytes, and you'd need to shift twice, making sure to shift the leftover from the first byte into the second byte. I can post more details on the shifting if you have trouble.)
I'd generate a 1bpp VWF (including the shifting) and then convert it when the tiles are copied to VRAM, usually that conversion is just simply a matter of writing the 1bpp tile multiples, or with zeros depending on which palette entry the game uses for "drawn" pixels.
(or convert the finished VWF tile to 2/4bpp in RAM if you need to do something fancy like a gradient afterwards)
"My watch says 30 chickens" Google, 2018

justin3009

#36
I do plan to cut the font down to 8x16 after I get a VWF in place.  16x16 is just way too ridiculously big for a semi-text heavy game.  Rather fit as much dialogue as I can while still making it not and not a thousand boxes.

And yes, I should have explained further.  It does exactly that.  ROM --> VRAM being a 2bpp 16x16 font.

Quote1a) Relocate the section of code that copies data to VRAM. Modify the original code so that it calls this routine to copy the data. (Note: for a 16x16 font, this routine should draw a half the character - an 8 px wide strip. So you will need to call the routine once for the first half and once for the second half. You'll see why this is in a bit.)

I'm assuming it would be this code that I just recently found.

$80/BB94 C2 20       REP #$20                A:0000 X:0000 Y:0200 P:envmxdIZc
$80/BB96 E2 10       SEP #$10                A:0000 X:0000 Y:0200 P:envmxdIZc
$80/BB98 AD B0 0F    LDA $0FB0  [$80:0FB0]   A:0000 X:0000 Y:0000 P:envmXdIZc - Loads font pointer
$80/BB9D 8D 02 43    STA $4302  [$80:4302]   A:0260 X:0000 Y:0000 P:envmXdIzc
$80/BBA0 A0 01       LDY #$01                A:0260 X:0000 Y:0000 P:envmXdIzc
$80/BBA2 8C 00 43    STY $4300  [$80:4300]   A:0260 X:0000 Y:0001 P:envmXdIzc
$80/BBA5 A0 18       LDY #$18                A:0260 X:0000 Y:0001 P:envmXdIzc
$80/BBA7 8C 01 43    STY $4301  [$80:4301]   A:0260 X:0000 Y:0018 P:envmXdIzc
$80/BBAA AC B2 0F    LDY $0FB2  [$80:0FB2]   A:0260 X:0000 Y:0018 P:envmXdIzc
$80/BBAD 8C 04 43    STY $4304  [$80:4304]   A:0260 X:0000 Y:00C0 P:eNvmXdIzc
$80/BBB0 AD B8 0F    LDA $0FB8  [$80:0FB8]   A:0260 X:0000 Y:00C0 P:eNvmXdIzc - Load VRAM storage
$80/BBB3 8D 16 21    STA $2116  [$80:2116]   A:6100 X:0000 Y:00C0 P:envmXdIzc
$80/BBB6 A9 20 00    LDA #$0020              A:6100 X:0000 Y:00C0 P:envmXdIzc - Load top right piece of font
$80/BBB9 8D 05 43    STA $4305  [$80:4305]   A:0020 X:0000 Y:00C0 P:envmXdIzc
$80/BBBC A0 01       LDY #$01                A:0020 X:0000 Y:00C0 P:envmXdIzc
$80/BBBE 8C 0B 42    STY $420B  [$80:420B]   A:0020 X:0000 Y:0001 P:envmXdIzc
$80/BBC1 A0 01       LDY #$01                A:0020 X:0000 Y:0001 P:envmXdIzc
$80/BBC3 8C 00 43    STY $4300  [$80:4300]   A:0020 X:0000 Y:0001 P:envmXdIzc
$80/BBC6 A0 18       LDY #$18                A:0020 X:0000 Y:0001 P:envmXdIzc
$80/BBC8 8C 01 43    STY $4301  [$80:4301]   A:0020 X:0000 Y:0018 P:envmXdIzc
$80/BBCB AC B2 0F    LDY $0FB2  [$80:0FB2]   A:0020 X:0000 Y:0018 P:envmXdIzc
$80/BBCE 8C 04 43    STY $4304  [$80:4304]   A:0020 X:0000 Y:00C0 P:eNvmXdIzc
$80/BBD1 AD B0 0F    LDA $0FB0  [$80:0FB0]   A:0020 X:0000 Y:00C0 P:eNvmXdIzc
$80/BBD4 18          CLC                     A:0260 X:0000 Y:00C0 P:envmXdIzc
$80/BBD5 69 00 01    ADC #$0100              A:0260 X:0000 Y:00C0 P:envmXdIzc - Loads bottom half of font
$80/BBD8 8D 02 43    STA $4302  [$80:4302]   A:0360 X:0000 Y:00C0 P:envmXdIzc
$80/BBDB AD B8 0F    LDA $0FB8  [$80:0FB8]   A:0360 X:0000 Y:00C0 P:envmXdIzc
$80/BBDE 18          CLC                     A:6100 X:0000 Y:00C0 P:envmXdIzc
$80/BBDF 69 10 00    ADC #$0010              A:6100 X:0000 Y:00C0 P:envmXdIzc - Load height of bottom half of font?
$80/BBE2 8D 16 21    STA $2116  [$80:2116]   A:6110 X:0000 Y:00C0 P:envmXdIzc
$80/BBE5 A9 20 00    LDA #$0020              A:6110 X:0000 Y:00C0 P:envmXdIzc - Loads bottom right of font
$80/BBE8 8D 05 43    STA $4305  [$80:4305]   A:0020 X:0000 Y:00C0 P:envmXdIzc
$80/BBEB A0 01       LDY #$01                A:0020 X:0000 Y:00C0 P:envmXdIzc
$80/BBED 8C 0B 42    STY $420B  [$80:420B]   A:0020 X:0000 Y:0001 P:envmXdIzc
$80/BBF0 9C B0 0F    STZ $0FB0  [$80:0FB0]   A:0020 X:0000 Y:0001 P:envmXdIzc


Modifying the 'A9 20 00' to 'A9 10 00' only loads the top/bottom left pieces of the font.  Essentially 'Half' of it.

Quote1b) Instead of copying directly from the ROM, copy the data from the ROM to some unused RAM area. Then use the a call to the routine from 1a to copy from RAM to VRAM. After this step, you'll have code that copies the left half of the character from ROM->RAM-> VRAM, then does the same with the right half.

$80/B87A 85 00       STA $00    [$00:0000]   A:000B X:0002 Y:0420 P:eNVmxdIzc
$80/B87C 29 F8 00    AND #$00F8              A:000B X:0002 Y:0420 P:eNVmxdIzc
$80/B87F 4A          LSR A                   A:0008 X:0002 Y:0420 P:enVmxdIzc
$80/B880 4A          LSR A                   A:0004 X:0002 Y:0420 P:enVmxdIzc
$80/B881 AA          TAX                     A:0002 X:0002 Y:0420 P:enVmxdIzc
$80/B882 BD BC B8    LDA $B8BC,x[$80:B8BE]   A:0002 X:0002 Y:0420 P:enVmxdIzc - Loads font graphic pointers
$80/B885 85 02       STA $02    [$00:0002]   A:0200 X:0002 Y:0420 P:enVmxdIzc
$80/B887 A5 00       LDA $00    [$00:0000]   A:0200 X:0002 Y:0420 P:enVmxdIzc
$80/B889 29 07 00    AND #$0007              A:000B X:0002 Y:0420 P:enVmxdIzc
$80/B88C 0A          ASL A                   A:0003 X:0002 Y:0420 P:enVmxdIzc
$80/B88D 0A          ASL A                   A:0006 X:0002 Y:0420 P:enVmxdIzc
$80/B88E 0A          ASL A                   A:000C X:0002 Y:0420 P:enVmxdIzc
$80/B88F 0A          ASL A                   A:0018 X:0002 Y:0420 P:enVmxdIzc
$80/B890 0A          ASL A                   A:0030 X:0002 Y:0420 P:enVmxdIzc
$80/B891 18          CLC                     A:0060 X:0002 Y:0420 P:enVmxdIzc
$80/B892 65 02       ADC $02    [$00:0002]   A:0060 X:0002 Y:0420 P:enVmxdIzc
$80/B894 18          CLC                     A:0260 X:0002 Y:0420 P:envmxdIzc
$80/B895 69 00 00    ADC #$0000              A:0260 X:0002 Y:0420 P:envmxdIzc - Loads pointer of font
$80/B898 8D B0 0F    STA $0FB0  [$80:0FB0]   A:0260 X:0002 Y:0420 P:envmxdIzc
$80/B89B A9 C0 00    LDA #$00C0              A:0260 X:0002 Y:0420 P:envmxdIzc - Loads bank of font
$80/B89E 8D B2 0F    STA $0FB2  [$80:0FB2]   A:00C0 X:0002 Y:0420 P:envmxdIzc
$80/B8A1 AD CC 0F    LDA $0FCC  [$80:0FCC]   A:00C0 X:0002 Y:0420 P:envmxdIzc
$80/B8A4 18          CLC                     A:0000 X:0002 Y:0420 P:envmxdIZc
$80/B8A5 6D CA 0F    ADC $0FCA  [$80:0FCA]   A:0000 X:0002 Y:0420 P:envmxdIZc - ADC VRAM storage
$80/B8A8 8D B8 0F    STA $0FB8  [$80:0FB8]   A:6100 X:0002 Y:0420 P:envmxdIzc - Store valuea gain
$80/B8AB AD CC 0F    LDA $0FCC  [$80:0FCC]   A:6100 X:0002 Y:0420 P:envmxdIzc
$80/B8AE 18          CLC                     A:0000 X:0002 Y:0420 P:envmxdIZc
$80/B8AF 69 20 00    ADC #$0020              A:0000 X:0002 Y:0420 P:envmxdIZc - ??? (Goes by intervals of 20)
$80/B8B2 8D CC 0F    STA $0FCC  [$80:0FCC]   A:0020 X:0002 Y:0420 P:envmxdIzc
$80/B8B5 A9 00 00    LDA #$0000              A:0020 X:0002 Y:0420 P:envmxdIzc
$80/B8B8 8D BA 0F    STA $0FBA  [$80:0FBA]   A:0000 X:0002 Y:0420 P:envmxdIZc
$80/B8BB 60          RTS                     A:0000 X:0002 Y:0420 P:envmxdIZc


When it's being copied to RAM instead, would it literally copy the entire piece of the font used into ram using a decent amount of space?  Or would it just be byte per byte transfer from RAM to VRAM?

Quote2) Modify the code so that it draws each half twice. You'll need to modify the part of the code that increments the tile number that is printed to for this. This is why we relocated the code in 1a - it's easy to add another call. I made a diagram to see why you do this:

I'm really not sure how to go about this nor do I think I quite understand it fully.

Quote3) The first time the character (or half of character) is drawn, shift each row of pixels right by X. (On this step I usually leave X as a hardcoded value, like 3 or 4, so it's obvious if it works.) The second time each half is drawn, shift left by 8-X. Shifting should be done on the data in ROM, so it can be done outside of vblank. Copying must be done in vblank.

(Note: I'm not sure exactly how bitshifting works on SNES, but you'll need to pay attention to the bit depth of the graphics. If it were 1bpp, an 8 pixel row would be one byte, and you could just shift right once per pixel you wanted to shift. But if it were 2bpp, you'd have two bytes, and you'd need to shift twice, making sure to shift the leftover from the first byte into the second byte. I can post more details on the shifting if you have trouble.)

At this point you should have something similar to the diagram, but you'll only see the second half of the character, because we still have it overwriting the previously drawn data.

Would bit shifting be using the ASL/LSR commands?  I've heard the term used a lot but never actually 'knew' what was being fully said.  Better to get it now while this is all in the works.  So if we had to shift right twice it'd be 4A 4A in just plain ASM?

I kind of got a gist of the rest of the post but I think it'd be better for the moment if I focused on the top portion so I can actually understand/see what's going on with some of the modified code.  It'd make it a lot easier to chunk everything together.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

LostTemplar

I don't think you have to do it as complicated as Spikeman explained on the SNES. You don't have to separate the tiles into halves even for 16x16 tiles; by using LSR/ASL and ROR/ROL you can shift each pixel row in two steps. That's because the LSB/MSB gets shifted into the carry flag by LSR/ASL, and ROR/ROL can get that into your destination. Let's assume A is #$FFFF and $00 is 0. Then


LSR A
ROR $00


yields A = #$7FFF (shifted right by one) and $00 is #$8000 (A's 1 got rotated in from the right). If you imagine that in bits, it's


         A              $00       c
1111111111111111 0000000000000000 ?
0111111111111111 0000000000000000 1 (after LSR)
0111111111111111 1000000000000000 0 (after ROR)


If you now try to imagine that these bits were pixels, it should be clear how you can shift a row of pixels to the right.

You always need more bits than your characters' maximum width because you still need room for shifting (that's why with 16px,1bpp characters you need at least 3 bytes). If your characters are at most 9 pixels wide you can do all the shifting in 16 bits and don't even need ROR/ROL because a pixel of your character will never be shifted out of 16-bit A.

If you want I can explain how I usually implement VWFs on the SNES and go into more detail. Sorry if this time was a bit confusing, it's just a quick write-up on the shifting part.

Spikeman

Yeah, you don't have to split it into halves, but I suggested that because I think it's easier than complicating the shifting portion more, trying to shift bits across tiles. Is $00 a register or a memory address? I guess my unfamiliarity with SNES is showing. :)

---

QuoteI do plan to cut the font down to 8x16 after I get a VWF in place.  16x16 is just way too ridiculously big for a semi-text heavy game.  Rather fit as much dialogue as I can while still making it not and not a thousand boxes.

And yes, I should have explained further.  It does exactly that.  ROM --> VRAM being a 2bpp 16x16 font.

If you plan on having no character being wider than 8 pixels, I'd suggest first doing a half width font hack. Making an 8 wide VWF will make things much less complicated. And like KingMike said earlier, it might be easier to store the font as 1bpp, then convert to a higher bit depth before it is drawn (but personally, I think just shifting twice is easier).

QuoteModifying the 'A9 20 00' to 'A9 10 00' only loads the top/bottom left pieces of the font.  Essentially 'Half' of it.

It looks like this would be changing it so it just stored half of the bytes. This might be an easy way to do a half width hack. So I'd suggest trying to get that working first. You'll probably also have to edit wherever it changes where the next char is drawn, so it's just 1 tile over instead of 2.

QuoteWhen it's being copied to RAM instead, would it literally copy the entire piece of the font used into ram using a decent amount of space?  Or would it just be byte per byte transfer from RAM to VRAM?

Yeah, you'd essentially want a buffer of 2x2 tiles in RAM (with an 8x16 font, the maximum number of tiles one character can occupy is 2x2). The idea here is because you can only modify VRAM during a short period called "vblank." Doing all the shifting and other math takes up a lot of cycles, so you do it outside of vblank, then on vblank it just copies the pre-made tiles from the buffer into VRAM.

I'm not actually sure if this is necessary on SNES, but I believe that is what LostTemplar was saying earlier in the thread. I know on the GBA (where I've coded most of my VWFs) it is not necessary.

Quote2) Modify the code so that it draws each half twice. You'll need to modify the part of the code that increments the tile number that is printed to for this. This is why we relocated the code in 1a - it's easy to add another call. I made a diagram to see why you do this:

I'm really not sure how to go about this nor do I think I quite understand it fully.

Sorry. It should be easier to understand with an 8 wide font. Each tile is 8 pixels wide, so imagine you want to draw the character 4 pixels over from the edge of a tile. That means that the left 4 pixels of the character would be in one tile, and the right 4 pixels would be in the next.

I suggested drawing each half twice because you could then reuse the shifting code (put it in a subroutine and call it for each half). With an 8x16, doing something like LostTemplar said would probably be easier.

In his example, one row of pixels (in A) is being shifted to the right, and the result is stored in $00. So in this case, you'd OR A with the first row of the left most tile in the buffer, and OR $00 with with first row of the right most tile in the buffer.

QuoteWould bit shifting be using the ASL/LSR commands?  I've heard the term used a lot but never actually 'knew' what was being fully said.  Better to get it now while this is all in the works.  So if we had to shift right twice it'd be 4A 4A in just plain ASM?

Right, its like LostTemplar said, there are two kinds of shifts, and they differ in how the use the carry flag. I'd suggest just looking at a document that describes what each opcode does and familiarizing yourself. I'd also familiarize yourself with the other bitwise operations, especially AND and OR.

Oh also, I'd suggest using a real assembler... modifying ASM manually is ok for small things, but for a VWF you're going to want a real assembler.

QuoteI kind of got a gist of the rest of the post but I think it'd be better for the moment if I focused on the top portion so I can actually understand/see what's going on with some of the modified code.  It'd make it a lot easier to chunk everything together.

Good plan. I think once you understand what exactly needs to happen for a VWF to work (graphics need to be shifted into place), you don't really need to follow the exact steps that I said. I was just breaking it down in the order that I have done it before. And a bunch of those steps might be different now because you're doing an 8x16 font, and because of differences between SNES and GBA. Good luck!
Open Source Hacking Projects: Guru Logic Champ, Telefang 2, (Want more? Check out my GitHub!)

justin3009

#39
Okay I've been working on the half font deal with a test font and it seems to be working out for the most part.  But there's an extremely annoying issue and I'm not really sure what's causing this to happen.

:

Image 1: Correct spacing of letters but coordinates are wrong every third letter it seems.
Image 2: Incorrect spacing of letters but the order stays perfect.
Image 3: Showing in VRAM the differences between the two.

I've gone forwards and backwards through the code and I honestly cannot for the life of me figure out why it would jump down a line for that third letter.  What would even cause this?

Edit: Appropriate changes have been made to make the letters be half width but still 16 height.  All letter pointers were changed to accommodate for it (Though not expanded yet until this works).

$80/BBB6 A9 20 00    LDA #$0020              A:6100 X:0000 Y:00C0
$80/BBE5 A9 20 00    LDA #$0020              A:6110 X:0000 Y:00C0 Loads top right/bottom right corner of letters (Both changed to A9 10 00 for half)

$80/B882 BD BC B8    LDA $B8BC,x[$80:B8BE]   A:0002 X:0002 Y:0420 Pointers to each letter (Changed to accommodate for half letters)

$80/B8AF 69 20 00    ADC #$0020              A:0000 X:0002 Y:0420 VRAM storage/Spacing of letters (Changed to 08 so they're next to each other)
$80/B88C 0A          ASL A                   A:0003 X:0000 Y:0420 Double's letter value (NOP'd)
$80/B895 69 00 00    ADC #$0000              A:0060 X:0000 Y:0420 ADC value for letter value (Changed to 69 10 00 to load correct letter value)


I really don't understand why this would occur.  It seems to occur every third letter for whatever reason.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'