Romhacking.net

Romhacking => Programming => Topic started by: justin3009 on April 11, 2011, 10:57:08 am

Title: Getting Started on a VWF?
Post by: justin3009 on April 11, 2011, 10:57:08 am
I'm looking to start learning more on adding VWF's to games, most notably right now would be Mega Man X3.

I know the font is refreshed non-stop throughout the game but it never gets overwritten by anything else.  I remember reading that the font area could be used as the VWF storage for taking a whole sentence and setting it up?  If I remember correctly.

How exactly would I get started on this though?  I've found in the game where the letters get written to and that's about it so far, minus where the dialogue loads and how they choose font colors and whom speaks, the basic stuff.  I've seen a couple of guides on here but I get so lost in how it's explained that it throws me through a loop.

I guess, what exactly DOES a VWF do besides the usual understanding of adding specific spacing between each letter?
Title: Re: Getting Started on a VWF?
Post by: KingMike on April 11, 2011, 12:20:08 pm
On SNES, you're pretty much creating "squishy tiles" at runtime.
You read the font data, squeeze the letters together across several tiles, then transfer the condensed tiles to VRAM, and also updating the tilemap accordingly.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on April 11, 2011, 01:13:54 pm
Letters are written to the screen two ways on the SNES. The first is static reference via the tilemap. The full font is loaded once into VRAM. From then on, when the game wants to print text, it alters the screen's tilemap entries to reference those tiles. The second is dynamically drawing them. No font is loaded. It pulls letters when needed from the ROM (or RAM) and creates a tile, or set of tiles, and uploads to VRAM. The tilemap is then changed to reference those new tiles. For every letter, processing is needed to create and load in VRAM a new tile or tiles, rather than simply updated a tilemap.

The differences between them are speed, VRAM usage, and processing. The first is very quick, requires virtually no processing, and uses little VRAM. However, you're confined to having your letters exactly an even tile width (8x8 8x16, 16x16).  Also, the larger the font, the more VRAM you need to take up. It may become less practical if you have a large font like a Japanese game with thousands of Kanji. The second is much more flexible. You can have letters of any size. However, processing is greater and code complexity is greater. VRAM usage is usually greater because new tiles are needed each time a letter is made. Many copies of the letter 'a' will exist in VRAM each time it is used unlike the former method where it is there only one time.

You will need to use the dynamic method in order to do a VWF. So, if your game uses the static reference via tilemap method, you'll need to do a a larger modification to both convert it to dynamic and then be VWF per character. If your game is already dynamic, but uses a fixed width font, you'll need to modify it to simply use variable width, which is much less work as the game was already drawing tiles dynamically.

It really helps if you understand how the screen is put together with backgrounds, tilemaps, and VRAM. Then the concept becomes much easier to grasp. I suggest using VSNES as a good visual learning tool and documentation by Anomie to understand the details of any hardware registers that come up during your investigations.

Here is a little overview of the mechanics of what a VWF routine actually does:
http://transcorp.parodius.com/forum/YaBB.pl?num=1124688575/1#1

It may sound somewhat difficult, but it's not. Break it into baby steps and learn one thing at a time. :)

Extra Note: What you've heard about using the font are being used for VWF storage applies to converting the static tile map reference to dynamic. You will then be able to use the space that used to be for the font as it is no longer needed. Instead, it will store your new tiles dynamically created by your VWF.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 11, 2011, 04:59:38 pm
I was hoping the game would have fixed-width but it doesn't so that makes things much more complicated than what I was hoping.  Though this is a good time to start learning how to do it from the basics.

The dynamic option is the best bet on this, which I believe you stated as well.  The font's 8x8 so I think that makes it a little easier, though there's more than enough room I believe for 8x16 or 16x16.  Though I'd probably just stick with 8x16 at the most if I ever had to go that far.  But yea, ranting aside there 8x8 is the main choice right now.

I also remember reading that little tidbit of yours on the forum Night.  It makes things more clear than before, but as you said I'll be taking baby steps.  This is rather confusing for me at first site but I understand it a bit more.  I'll be attempting to start on it or at least use VSNES like you said and get a better visual look.  (Did you mean BSNES or is it literally VSNES?)
Title: Re: Getting Started on a VWF?
Post by: Dragoon ZERO on April 11, 2011, 06:30:38 pm
vSNES (http://www.romhacking.net/utils/274/)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 12, 2011, 04:42:41 pm
Looking at BSNES and the most obvious piece of info is that the dialogue was on Layer Background 3, though that's pretty easily seen if you remove layers in any emulator.

Should there be something specifically that I look get a better look?
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 12, 2011, 06:31:57 pm
The only two pieces of information you really need to get started is where the tilemap is in VRAM and where the tiles associated with that tilemap are stored in VRAM. VSNES can tell you both. From there you just set break points and work your way backwards until you've found the text routine. :)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 12, 2011, 08:08:44 pm
Oh woops, I meant to say VSNES.  But ohh okay I see where you're going with that!  That makes a lot more sense :)  I'll take a whack at that right now while I have the time.
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 12, 2011, 08:13:27 pm
Keep in mind bsnes is the only emulator that will let you set breakpoints on VRAM addresses. :thumbsup:
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 12, 2011, 08:21:06 pm
Oh good thing you just noted that too.  I was about to get a head start on this.

I'll keep that in mind and try to work with it.  BSNES is rather interesting to work with so I'll be getting a nice learning experience from that as well.

Edit: How exactly do breakpoints work with BSNES?  Better yet, is there a guide for BSNES debugging anywhere?
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 12, 2011, 09:34:38 pm
Debugging is debugging regardless of the emulator. Make sure you have the debugger build then open the debugger window and set a breakpoint from the menu.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 12, 2011, 09:42:25 pm
Edit:  I had this listed in one of my files and it seems these two addresses are always written to whenever a letter is shown on screen.

Code: [Select]
$00/E672 89 80       BIT #$80                A:0145 X:0001 Y:000B D:0000 DB:06 S:01FF P:envMXdIzC HC:0788 VC:078 FC:20 I:00
$00/E674 F0 03       BEQ $03    [$E679]      A:0145 X:0001 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0812 VC:078 FC:20 I:00
$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
$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
$00/E683 A9 80       LDA #$80                A:0108 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzC HC:0998 VC:078 FC:20 I:00 - Text color
$00/E685 9D 00 06    STA $0600,x[$06:0600]   A:0180 X:0000 Y:000B D:0000 DB:06 S:01FF P:eNvMXdIzC HC:1022 VC:078 FC:20 I:00
$00/E688 C2 21       REP #$21                A:0180 X:0000 Y:000B D:0000 DB:06 S:01FF P:eNvMXdIzC HC:1068 VC:078 FC:20 I:00
$00/E68A A5 6A       LDA $6A    [$00:006A]   A:0180 X:0000 Y:000B D:0000 DB:06 S:01FF P:eNvmXdIzc HC:1098 VC:078 FC:20 I:00
$00/E68C 65 6C       ADC $6C    [$00:006C]   A:0886 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1172 VC:078 FC:20 I:00
$00/E68E 18          CLC                     A:0888 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1212 VC:078 FC:20 I:00
$00/E68F 69 20 00    ADC #$0020              A:0888 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1234 VC:078 FC:20 I:00
$00/E692 29 FF 07    AND #$07FF              A:08A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1266 VC:078 FC:20 I:00
$00/E695 09 00 08    ORA #$0800              A:00A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1298 VC:078 FC:20 I:00
$00/E698 9D 01 06    STA $0601,x[$06:0601]   A:08A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:1330 VC:078 FC:20 I:00
$00/E69B E6 6C       INC $6C    [$00:006C]   A:08A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:0020 VC:079 FC:20 I:00
$00/E69D E2 20       SEP #$20                A:08A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envmXdIzc HC:0082 VC:079 FC:20 I:00
$00/E69F A9 02       LDA #$02                A:08A8 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0112 VC:079 FC:20 I:00
$00/E6A1 9D 03 06    STA $0603,x[$06:0603]   A:0802 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0136 VC:079 FC:20 I:00
$00/E6A4 8A          TXA                     A:0802 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0182 VC:079 FC:20 I:00
$00/E6A5 18          CLC                     A:0800 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0204 VC:079 FC:20 I:00
$00/E6A6 69 06       ADC #$06                A:0800 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0226 VC:079 FC:20 I:00
$00/E6A8 85 A5       STA $A5    [$00:00A5]   A:0806 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0250 VC:079 FC:20 I:00
$00/E6AA AD 49 1F    LDA $1F49  [$06:1F49]   A:0806 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0282 VC:079 FC:20 I:00
$00/E6AD F0 38       BEQ $38    [$E6E7]      A:0800 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0322 VC:079 FC:20 I:00
$00/E6E7 AD 4A 1F    LDA $1F4A  [$06:1F4A]   A:0800 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0352 VC:079 FC:20 I:00
$00/E6EA 30 08       BMI $08    [$E6F4]      A:0801 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0392 VC:079 FC:20 I:00
$00/E6EC CE 4A 1F    DEC $1F4A  [$06:1F4A]   A:0801 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0416 VC:079 FC:20 I:00
$00/E6EF F0 03       BEQ $03    [$E6F4]      A:0801 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0470 VC:079 FC:20 I:00
$00/E6F4 A6 6F       LDX $6F    [$00:006F]   A:0801 X:0000 Y:000B D:0000 DB:06 S:01FF P:envMXdIZc HC:0500 VC:079 FC:20 I:00 - Text speed
$00/E6F6 F0 2D       BEQ $2D    [$E725]      A:0801 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0532 VC:079 FC:20 I:00
$00/E6F8 E0 01       CPX #$01                A:0801 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIzc HC:0596 VC:079 FC:20 I:00
$00/E6FA F0 1C       BEQ $1C    [$E718]      A:0801 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIzC HC:0620 VC:079 FC:20 I:00
$00/E6FC AD B3 1F    LDA $1FB3  [$06:1FB3]   A:0801 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIzC HC:0644 VC:079 FC:20 I:00
$00/E6FF D0 17       BNE $17    [$E718]      A:0800 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0684 VC:079 FC:20 I:00
$00/E701 5A          PHY                     A:0800 X:0004 Y:000B D:0000 DB:06 S:01FF P:envMXdIZC HC:0708 VC:079 FC:20 I:00
$00/E702 AD 49 1F    LDA $1F49  [$06:1F49]   A:0800 X:0004 Y:000B D:0000 DB:06 S:01FE P:envMXdIZC HC:0738 VC:079 FC:20 I:00
$00/E705 F0 0B       BEQ $0B    [$E712]      A:0800 X:0004 Y:000B D:0000 DB:06 S:01FE P:envMXdIZC HC:0778 VC:079 FC:20 I:00
$00/E712 A9 1E       LDA #$1E                A:0800 X:0004 Y:000B D:0000 DB:06 S:01FE P:envMXdIZC HC:0808 VC:079 FC:20 I:00 - SFX to use each time a letter is written
$00/E714 20 79 85    JSR $8579  [$00:8579]   A:081E X:0004 Y:000B D:0000 DB:06 S:01FE P:envMXdIzC HC:0832 VC:079 FC:20 I:00

Out of those, these couple areas are important.  These are written too whenever a letter appears on screen.

$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
$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

Those values are either in the CX4 chip or VRAM since they cannot be accessed by normal means.  Relates back to the 'ole life bar glitch.
Title: Re: Getting Started on a VWF?
Post by: Mauron on April 15, 2011, 12:35:39 am
According to Anomie’s C4 Chip Doc, $6000-$6bff(?) (Sorry, it cleared the text when I checked the spelling of Anomie) is generic ram on the chip.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 15, 2011, 09:07:40 am
Ick.. you're right.  Back to the drawing board again.  I'll try vSNES again.  How exactly do you know you've found the right area though?  Especially with BSNES.  I've put a breakpoint for VRAM and it just says "Breakpoint x hit (x)".  Not really sure what that's supposed to do for me ._.

Edit: Looking at vSNES again.  2109 seems to effect layer 3 which is where the font is on.  It says it's 7 bits and a value of 09.  I'm guessing that's the info I needed, but I'm not sure what to do with it now.

Edit 2: Set a breakpoint in SNES9X for the heck of it and it led me to.

$7E/212D A5 CE       LDA $CE    [$00:00CE]   A:00E1 X:0000 Y:6000 P:eNvMxdIzc - Removing this will destroy Layer 3 completely.
$7E/212F 8D 09 21    STA $2109  [$06:2109]   A:000A X:0000 Y:6000 P:envMxdIzc
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on April 15, 2011, 01:21:19 pm
Start with what you know and work backwards and expand your knowledge. VSNES will show you where the background layer tile tilemap data is in VRAM. This is an effective address. The actual address that would be written to $2116 is half of that because it's word addressed (instead of byte). You can verify yourself in the VRAM viewer that the data is there. You can even edit it if you want and see the results occur instantly in VSNES. (Remember that VSNES is limited in it's abilities to display HDMA (scanline) effects.) If you look at the tilemap there, you'll also know what actual byte values to be looking for to confirm you've found the right code later.

Now, you know the place of interest in VRAM. Now you need to start looking for how data gets there. Most of the time it's going to be a DMA transfer to the area or manual write to $2118/$2119. Remember VRAM address is set in $2116 for either method, so that should clue you in to relevant code. You can use breakpoints, you can list active DMA transfers in Geiger's debugger real time, or you can use a tracelog and look for DMA routines. Whatever works for you to start finding some relevant code that writes to the area of VRAM you found earlier. You'll find it either comes from somewhere in RAM or ROM. If it's RAM, you continue on and find out how the data got to where it is in RAM. Continue farther back if you need. You'll eventually end up at the relevant code.

I think you're on the right track:
In your case where you've mentioned the whole font is in VRAM, you'll most likely find a copy of the tilemap in RAM (or C4 RAM ) that gets sent to VRAM each frame. That's how most games do a static tilemap based font routine.

From the code you posted, it looks like you've probably found the right code. There is probably a copy of the tilemap in that $06:0600 region. Verify by seeing if the tilemap in VSNES has tile data with the bytes you see being written there. Or, edit them in a debugger that allows you to access that RAM (I think we had that discussion in another topic. I forget what the end result was.)

Once you've confirmed you've found the tilemap data and text routine and understand how it works, you can start making a sensible plan on modification. :)

These are the most difficult mechanics to pick up in ROM hacking. Nobody can really teach you how to be good at reverse engineering. You will improve with experience and time. Also, the more knowledge you gain about the platform you're working with, the easier it will be.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 15, 2011, 06:59:28 pm
I'm slowly speaking with someone to help assist some of the areas that I'm getting lost at, but here's some more information I think.

Code: [Select]
    These appear once the letters do
        DMA[0]: CPU->PPU Mode:1 0x000604->0x2118 Bytes:34 (inc) V:232 VRAM: 0984 (1,0) word
        DMA[0]: CPU->PPU Mode:1 0x00063C->0x2118 Bytes:2 (inc) V:233 VRAM: 0984 (1,0) word
        DMA[0]: CPU->PPU Mode:1 0x000642->0x2118 Bytes:34 (inc) V:234 VRAM: 09C4 (1,0) word
        DMA[0]: CPU->PPU Mode:1 0x00067A->0x2118 Bytes:2 (inc) V:235 VRAM: 09C4 (1,0) word
        DMA[0]: CPU->PPU Mode:1 0x000680->0x2118 Bytes:28 (inc) V:235 VRAM: 0A04 (1,0) word
        DMA[0]: CPU->PPU Mode:1 0x0006AC->0x2118 Bytes:28 (inc) V:236 VRAM: 0A44 (1,0) word
   
   
    $00/E67B 9D 04 06    STA $0604,x[$06:0604]   A:012E X:0000 Y:0016 P:envMXdIZC
    DMA[0]: CPU->PPU Mode:1 0x000604->0x2118 Bytes:2 (inc) V:235 VRAM: 0BB4 (1,0) word
    $7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc

0984 in VRAM in Geiger's literally shows nothing, but going to 604 and it's partially the letters in the tilemap.  I knocked a chunk of it out and a mass horde of the letters went missing.  So I'm guessing around 300-900 is where the tilemap is.
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 15, 2011, 07:09:25 pm
Try checking at $1308. Like NC said, it's word addressed. Anytime you see a VRAM address in Geiger's DMA log double it to get the address to look at in the hex editor.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 15, 2011, 07:17:46 pm
Oh duh, right.  Completely bypassed that.  The screen I've been looking at is the Capcom Copyright screen right when the game starts.  Ends up being 1308 IS where it's all being stored correctly.  I thought maybe this wasn't the right area to check but that area loads the font as well so it's generally okay.  So yep, 1308 is the right spot.

Would my next step to trace it backwards?  If so, how do you work backwards from VRAM?  I've never done it with that but I've done it multitudes of times with regular code.
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 16, 2011, 11:28:03 am
Oh duh, right.  Completely bypassed that.  The screen I've been looking at is the Capcom Copyright screen right when the game starts.  Ends up being 1308 IS where it's all being stored correctly.  I thought maybe this wasn't the right area to check but that area loads the font as well so it's generally okay.  So yep, 1308 is the right spot.

Would my next step to trace it backwards?  If so, how do you work backwards from VRAM?  I've never done it with that but I've done it multitudes of times with regular code.

You can set a breakpoint on VRAM with bsnes and go from there.

What I like to do is open up VRAM in the hex editor (I typically use Geiger's SNES9x simply because it supports savestates and switch to bsnes when Geiger's debugger falls short), jump to the address where the data is ($1308 in your case) and run the game until the data appears so I have some idea when the data is written to VRAM. Then I reset the game (or load a savestate to a point before the data is put in VRAM) and turn on DMA logging while the data is loaded and hope for a bite.

If I find the data is being sent to VRAM via DMA, I either use the source address as my next point of interest (usually RAM) or make a trace and try to catch the write to $420b that starts the DMA transfer. Then you just keep working backwards.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 16, 2011, 11:41:16 am
DMA[0]: CPU->PPU Mode:1 0x7E2622->0x2118 Bytes:1000 (fixed) V:232 VRAM: 5000 (1,0) word
DMA[0]: CPU->PPU Mode:1 0x7E2622->0x2118 Bytes:1000 (fixed) V:257 VRAM: 5800 (1,0) word
DMA[0]: CPU->PPU Mode:1 0x7E2622->0x2118 Bytes:1000 (fixed) V:020 VRAM: 0800 (1,0) word

This is what comes up in SNES9X whenever it gets hit so that's probably where I should work backwards from in RAM is my guess.

In BSNES when I set a Write Breakpoint to 1308 with VRAM, it just says this.

Breakpoint 0 hit (1).
Breakpoint 0 hit (2).
Breakpoint 0 hit (3).

I'm not entirely sure how BSNES helped in that cause ._.

Edit: Maybe that isn't right on SNES9X's case.  All that leads me to is nothing at all, so not really sure what's up there.

Edit 2:
Saw this at the top of the log buuuut
Code: [Select]
..ffcf nop                    A:00 X:00 Y:00 SP:01ef YA:0000 nvpbhizc
008106 beq $8103     [008103] A:0100 X:00ff Y:0001 S:02ff D:0000 DB:06 nvMXdIZc V:241 H:  18
008103 lda $09ce     [0609ce] A:0100 X:00ff Y:0001 S:02ff D:0000 DB:06 nvMXdIZc V:241 H:  40
..ffd2 nop                    A:00 X:00 Y:00 SP:01ef YA:0000 nvpbhizc
001ff3 jml $7e2000   [7e2000] A:0100 X:00ff Y:0001 S:02fb D:0000 DB:06 nvMXdIZc V:225 H: 104

7e22ba lda #$01               A:0006 X:0004 Y:0000 S:02ee D:0000 DB:06 nvMXdIzc V:232 H:1126
7e22bc sta $420b     [06420b] A:0001 X:0004 Y:0000 S:02ee D:0000 DB:06 nvMXdIzc V:232 H:1142

NOPing these out will remove all traces of the font in game, but layer 3 will still okay.  I believe this is what I was needing to find?
Title: Re: Getting Started on a VWF?
Post by: RedComet on April 16, 2011, 08:11:23 pm
bsnes should've come up with something like this: Link (http://archive.rpgclassics.com/subsites/twit/other/bsnes_example.png)

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:

Code: [Select]
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.  :-[
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 16, 2011, 08:28:02 pm
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:


Code: [Select]
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:

Code: [Select]
$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.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on April 18, 2011, 10:44:50 am
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.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 18, 2011, 04:43:49 pm
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 ._.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on April 19, 2011, 10:18:54 am
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?
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 19, 2011, 12:40:24 pm
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.
Title: Re: Getting Started on a VWF?
Post by: KingMike on April 19, 2011, 03:29:42 pm
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.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 19, 2011, 03:41:21 pm
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

Code: [Select]
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.
Title: Re: Getting Started on a VWF?
Post by: 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.
Title: Re: Getting Started on a VWF?
Post by: Spikeman on January 13, 2013, 09:36:40 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?)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 13, 2013, 11:21:22 pm
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.
Title: Re: Getting Started on a VWF?
Post by: LostTemplar on January 14, 2013, 02:08:48 am
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.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 14, 2013, 10:07:53 am
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.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on June 17, 2013, 01:46:12 am
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?
Title: Re: Getting Started on a VWF?
Post by: Spikeman on June 19, 2013, 06:48:14 pm
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:

(http://i.imgur.com/CEfXJUN.png)

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.
Title: Re: Getting Started on a VWF?
Post by: KingMike on June 20, 2013, 01:34:06 am
(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)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on June 20, 2013, 12:09:49 pm
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.

Quote
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.)

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

Code: [Select]
$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.

Quote
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.

Code: [Select]
$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?

Quote
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:

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

Quote
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.

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.
Title: Re: Getting Started on a VWF?
Post by: LostTemplar on June 20, 2013, 01:24:52 pm
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

Code: [Select]
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

Code: [Select]
         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.
Title: Re: Getting Started on a VWF?
Post by: Spikeman on June 20, 2013, 07:03:20 pm
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. :)

---

Quote
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.

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).

Quote
Modifying 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.

Quote
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?

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.

Quote
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:

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.

Quote
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?

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.

Quote
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.

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!
Title: Re: Getting Started on a VWF?
Post by: justin3009 on June 21, 2013, 01:24:18 pm
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.

(http://i39.tinypic.com/2m5f51h.png):

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).

Code: [Select]
$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.
Title: Re: Getting Started on a VWF?
Post by: Spikeman on June 22, 2013, 12:29:49 am
Strange. Perhaps you could post a patch? It's kind of hard to tell what's going on without looking at it in an emulator. (Actually you should post patches of both cases, so we can compare them.)

My first thought is maybe it is drawing the characters as sprites, or maybe there is some weirdness going on in the tilemap. Hard to tell exactly without looking at it actually running.

In that third picture, is that how the VRAM is actually laid out when the game is running? Or how you are storing the graphics in the ROM?

Also, there are really pointers to each character? That sounds a little unnecessary...

(Also, I assume you know about the translation that has already been done? Apparently it has a VWF implemented. Might be helpful for you to take a look at how they implemented it.)

Edit:

I'm looking at the game in no$sns right now (what debugger have you been using?), and I think I answered my own questions.

The font is being written to BG3, so the problem isn't due to sprites. I think my thought that it may be the tilemap is indeed the case. Now keep in mind I'm looking at the unmodified ROM. It looks like the tiles making up the first character are at 7E87, 7E88, 7EA7, 7EA8. If you look at the corresponding tile addresses, they are 6100, 6108, 6110, 6118. This explains the problem you're having -- the tilemap is still laid out like it is an 16x16 font, but it looks like you're trying to do an 8x8 font.

First, are you trying to do an 8x8 font or an 8x16 font? I thought an 8x16 is what you were aiming for.

Next, it looks like you are only modifying the behavior of the game when it comes to loading the VRAM tiles. You're also going to need to figure out how to modify the tilemap. It's probably the case that the tilemap is just set once, and you can just edit it somewhere in the ROM.

BTW, feel free to contact me on MSN or AIM, maybe I can help out better that way.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on June 22, 2013, 01:05:21 am
http://www32.zippyshare.com/v/14973755/file.html - Patch is here.

Code: [Select]
$80/B8AF 69 20 00    ADC #$0020              A:0000 X:0002 Y:0420
- The code here is what's doing the odd storage.  Currently it's 08 so the letters are side by side.  The normal value is 20.  This is the VRAM Storage/Spacing of letters type.. thing.

The third image: Yep, that is how they get thrown into VRAM.  Though it's two separate images pasted together (They both appear on the top line with the 'works' bit).  It's just show casing a comparison between the VRAM storage that occurs with a simple change of a byte from 08 to 20.  The graphics in ROM are directly side by side, which is more or less how it'd be represented with the 'Doesn't work' bit.

Yeah, there.. really is.  It's pretty strange.  This game does a lot of unnecessary things from what I've seen.

And yes, I've taken a look at FuSoYa's VWF and I couldn't exactly follow it well.  It seemed to flow with the normal code but then it broke into a HUUUGEE section of code that I couldn't even exactly begin to follow correctly.  (Doing it this way is much more of a hassle but it's a perfect example of a learning experience I NEED to do).
Title: Re: Getting Started on a VWF?
Post by: Spikeman on June 22, 2013, 01:14:15 am
Sounds good. After a little bit more investigation, it seems that your problem is definitely the tilemap. It looks like it is being set once, and then only the VRAM is modified. You'll need to modify the tilemap so it interprets the VRAM the way you want it to.

Right now it's laid out like this: (lines are the boundaries between characters)

Code: [Select]
6100  6108  |  6120  6128  | ...
6110  6118  |  6130  6138  | ...

For an 8x16 you'd want this:

Code: [Select]
6100  |  6110  |  6120  |  6130  | ...
6108  |  6118  |  6128  |  6138  | ...

For an 8x8 you'd want this:

Code: [Select]
6100  |  6108  |  6110  |  6118  | ...  | 61B8  (this is the rightmost tile of the first row)
--------------------------------------------
61C0  |  61C8  |  61D0  |  61D8  | ...

Does this make sense? Your next goal should be to find the tilemap in the ROM and modify it appropriately.

Also, don't know if you saw, but I can help you out over IM or IRC if you'd like.

Edit: Just tried your patch, I'm getting a blank screen at the beginning of the game (sound plays fine though)... is Bisyoujyo Senshi Sailor Moon - Another Story (J).smc the right ROM?
Title: Re: Getting Started on a VWF?
Post by: justin3009 on June 22, 2013, 09:10:22 am
I totally didn't see that one bit.  Over IM or IRC would work fine if it's a possibility.  I'll try to see if I can modify the tilemap as needed.

And yes, it should be.  It's an unheadered ROM as well, probably should have stated that before I hopped into bed.

Edit: Well got home later than I thought I would due to the flooding going on everywhere up here.  But I'm.. having issues even finding the Tilemap or what does all that placement.  Or rather, I'm not exactly sure what's causing the placement.

Edit 2: I haven't actually worked on this much the past few days.  Really trying to get used to my new job.  Sucks getting home at 2AM.  But I decided to try copy/pasting from FuSoYa's translation to see if I can get a VWF and such to work.  I did.  But it's.. yeah I have to figure out what everything is.  I think the translation has a DTE in it (I think I'm using the incorrect term.  It's basically the single byte that loads up a specific word from a table to print).  But this would explain WHY there's so much more code.  So essentially if I want to borrow from Fusoya's (Which I really, really don't want to do if I don't have to), I'll have to start dissecting every piece to figure out what is what.

Also, I still have no idea about that Tilemap issue before hand :/  I'm not really sure 'how' you can find it.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 01, 2013, 05:56:25 am
I know I'm jumping around on so many projects but I keep coming back to this and working with VRAM.  I'm REALLY understanding it more and more.  I'm almost certain at this point I could get a decent start on coding it a bit but I feel like I'm missing something still when it comes to Mega Man X3, rather, I have all the pieces of the puzzle but I'm just not clearly seeing everything.

I've found the locations on how it stores the font into VRAM (Really stupidly obvious routine that's used everywhere, not sure how I didn't notice that) and can easily remove it.  That's a no-brainer.  I've also noticed that the letter values correspond to how they're written in VRAM.

So for example, 'I' is letter 49.  It's location in VRAM was '0490'.  And then this is where I get lost.  I still have no clue how it's dragging that letter value, doing what it needs to do, and picking out the spot in VRAM to do so.  I can't honestly seem to get a good trace, step, or anything to see how that occurs.  I'm trying to figure it out completely so I can have it read from ROM for the font (For fixed width needs) but it's like there's something clearly missing or I'm oblivious to it.

7E00C7 may have something to do with it as well.  It's always 00 for VRAM junk.  Altering it I think changes which '1000' section in VRAM to read from but I'm not 100% sure.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 01, 2013, 11:22:33 am
You can't transfer anything to VRAM on the SNES (DMA or otherwise) without setting the VRAM write location to $2116/$2117. That's where the start location of writes will be. From there it either DMA a block of data or manually write to $2118/$2119. Once you find the starting location there, you can work backwards to see where it came from.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 01, 2013, 01:27:10 pm
It's not writing TO VRAM at this point (That I know of).  Writing the font to VRAM happens right away at the very beginning of the game.  That's easily removeable.  The issue I'm having now is how it's technically 'reading' from VRAM to get the correct letter from the tilemap and paste it onto Layer 3 screen.

I can't seem to find that bit at all.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 01, 2013, 05:18:38 pm
The tilemap is in VRAM as well. There are registers to tell the hardware where in VRAM the tilemap is for a specific layer. The text routine will come up with a tilemap entry for each letter. In most cases, it will store those entries in in RAM and then the entire tilemap RAM block will be DMA'd to the appropriate place in VRAM each frame (usually during NMI). Although it's possible to write each tilemap entry individually.

So, all you need to do is capture the transfer of the tilemap to VRAM. It's the same steps as capturing the font (or anything) to VRAM.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 02, 2013, 06:07:54 pm
Code: [Select]
$7E/2296 BD 01 06    LDA $0601,x[$06:0601]   A:0080 X:0000 Y:0000 P:eNvMXdIzc - Location to write on Layer 3
$7E/2299 8D 16 21    STA $2116  [$06:2116]   A:00A1 X:0000 Y:0000 P:eNvMXdIzc
$7E/229C BD 02 06    LDA $0602,x[$06:0602]   A:00A1 X:0000 Y:0000 P:eNvMXdIzc
$7E/229F 8D 17 21    STA $2117  [$06:2117]   A:000A X:0000 Y:0000 P:envMXdIzc

Code: [Select]
$7E/22A2 BD 03 06    LDA $0603,x[$06:0603]   A:000A X:0000 Y:0000 P:envMXdIzc
$7E/22A5 8D 05 43    STA $4305  [$06:4305]   A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22A8 9C 06 43    STZ $4306  [$06:4306]   A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AB E8          INX                     A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AC E8          INX                     A:0002 X:0001 Y:0000 P:envMXdIzc
$7E/22AD E8          INX                     A:0002 X:0002 Y:0000 P:envMXdIzc
$7E/22AE E8          INX                     A:0002 X:0003 Y:0000 P:envMXdIzc
$7E/22AF 8E 02 43    STX $4302  [$06:4302]   A:0002 X:0004 Y:0000 P:envMXdIzc
$7E/22B2 A9 06       LDA #$06                A:0002 X:0004 Y:0000 P:envMXdIzc
$7E/22B4 8D 03 43    STA $4303  [$06:4303]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22B7 9C 04 43    STZ $4304  [$06:4304]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BA A9 01       LDA #$01                A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc
$7E/22BF 8A          TXA                     A:0001 X:0004 Y:0000 P:envMXdIzc
$7E/22C0 7D FF 05    ADC $05FF,x[$06:0603]   A:0004 X:0004 Y:0000 P:envMXdIzc
$7E/22C3 B0 FE       BCS $FE    [$22C3]      A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C5 AA          TAX                     A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C6 E4 A5       CPX $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIzc
$7E/22C8 D0 C6       BNE $C6    [$2290]      A:0006 X:0006 Y:0000 P:envMXdIZC
$7E/22CA 64 A5       STZ $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIZC

Not sure what the rest of it is but it's reading the location on where to place it on screen from there.  Then I think it sets DMA channel or something.  I THINK that's on the right track?

Edit: Sigh, it just leads back to the original junk found from the text.  42A6B9 is where it's loading the coordinates from, color, etc..  Thus the 'storage' from the VRAM bit there.

Edit 2: Letter is stored to 7E0604.. usual stuff I had before.  I'm falling back into that loop.

Edit 3: Setting a read breakpoint on 7E0604 does this.

DMA[0]: CPU->PPU Mode:1 0x000604->0x2118 Bytes:2 (inc) V:235 VRAM: 0AA1 (1,0) word
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 D:0000 DB:06 S:02EE P:envMXdIzc HC:0192 VC:235 FC:29 I:00
Title: Re: Getting Started on a VWF?
Post by: KingMike on September 02, 2013, 09:09:49 pm
Code: [Select]
$7E/22A2 BD 03 06    LDA $0603,x[$06:0603]   A:000A X:0000 Y:0000 P:envMXdIzc
$7E/22A5 8D 05 43    STA $4305  [$06:4305]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size (low byte)
$7E/22A8 9C 06 43    STZ $4306  [$06:4306]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size high byte to 0
$7E/22AB E8          INX                     A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AC E8          INX                     A:0002 X:0001 Y:0000 P:envMXdIzc
$7E/22AD E8          INX                     A:0002 X:0002 Y:0000 P:envMXdIzc
$7E/22AE E8          INX                     A:0002 X:0003 Y:0000 P:envMXdIzc
$7E/22AF 8E 02 43    STX $4302  [$06:4302]   A:0002 X:0004 Y:0000 P:envMXdIzc    ;X+4 = low byte of source address
$7E/22B2 A9 06       LDA #$06                A:0002 X:0004 Y:0000 P:envMXdIzc          ;high byte of source address = 6
$7E/22B4 8D 03 43    STA $4303  [$06:4303]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22B7 9C 04 43    STZ $4304  [$06:4304]   A:0006 X:0004 Y:0000 P:envMXdIzc  ;bank byte of source = 0 (so read from RAM 00:06XX
$7E/22BA A9 01       LDA #$01                A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc    ;do transfer
$7E/22BF 8A          TXA                     A:0001 X:0004 Y:0000 P:envMXdIzc     ;this is effectively increasing X by the amount of transferred data
$7E/22C0 7D FF 05    ADC $05FF,x[$06:0603]   A:0004 X:0004 Y:0000 P:envMXdIzc
$7E/22C3 B0 FE       BCS $FE    [$22C3]      A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C5 AA          TAX                     A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C6 E4 A5       CPX $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIzc   ;I'm assuming $A5 is the total amount of data to transfer
$7E/22C8 D0 C6       BNE $C6    [$2290]      A:0006 X:0006 Y:0000 P:envMXdIZC
$7E/22CA 64 A5       STZ $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIZC
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 02, 2013, 10:13:54 pm
Quote
;bank byte of source = 0 (so read from RAM 00:06XX

So would that effectively make it read from 7E:0604 since X is 04? (It ALWAYS stays 4 apparently)
Title: Re: Getting Started on a VWF?
Post by: KingMike on September 02, 2013, 11:07:48 pm
Yes, since I believe the first 8K of WRAM (0000-1FFF) is mirrored across most LoROM banks.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 02, 2013, 11:24:32 pm
Code: [Select]
$7E/22A2 BD 03 06    LDA $0603,x[$06:0603]   A:000A X:0000 Y:0000 P:envMXdIzc
$7E/22A5 8D 05 43    STA $4305  [$06:4305]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size (low byte)
$7E/22A8 9C 06 43    STZ $4306  [$06:4306]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size high byte to 0
$7E/22AB E8          INX                     A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AC E8          INX                     A:0002 X:0001 Y:0000 P:envMXdIzc
$7E/22AD E8          INX                     A:0002 X:0002 Y:0000 P:envMXdIzc
$7E/22AE E8          INX                     A:0002 X:0003 Y:0000 P:envMXdIzc
$7E/22AF 8E 02 43    STX $4302  [$06:4302]   A:0002 X:0004 Y:0000 P:envMXdIzc    ;X+4 = low byte of source address
$7E/22B2 A9 06       LDA #$06                A:0002 X:0004 Y:0000 P:envMXdIzc          ;high byte of source address = 6
$7E/22B4 8D 03 43    STA $4303  [$06:4303]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22B7 9C 04 43    STZ $4304  [$06:4304]   A:0006 X:0004 Y:0000 P:envMXdIzc  ;bank byte of source = 0 (so read from RAM 00:06XX) [ Makes it read from 7E0604)
$7E/22BA A9 01       LDA #$01                A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc    ;do transfer
$7E/22BF 8A          TXA                     A:0001 X:0004 Y:0000 P:envMXdIzc     ;this is effectively increasing X by the amount of transferred data
$7E/22C0 7D FF 05    ADC $05FF,x[$06:0603]   A:0004 X:0004 Y:0000 P:envMXdIzc
$7E/22C3 B0 FE       BCS $FE    [$22C3]      A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C5 AA          TAX                     A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C6 E4 A5       CPX $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIzc   ;I'm assuming $A5 is the total amount of data to transfer

Okay.  So basically this huge chunk of area (OR at least the top portion) sets it to read from 7E0604 which gets the letter value.  In this case, the letter value is 49 for 'I' reading from 0490 in VRAM.

I'm starting to get a bit lost again, no surprise there.  Pretty much RIGHT away after though this whole thing gets overwritten in general by the next letters/backgrounds etc.. so I'm lost now on where to go from here.

But now, since that's figured out that the whole area section there is reading from 7E0604, does it load the data there as 49 then... just pick the right selection in VRAM (0490)?  I'm.. really not sure.

Edit: 7E00A5 isn't the length as far as I know of.  Looks like it's actually used for Layer 1/2 scrolling if it's being used.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 03, 2013, 07:01:30 pm
Do you know what a tilemap is, it's format, and how it works on the SNES? I'm not sure you understand exactly what you're looking for sometimes. A tilemap entry is always 2 bytes per tile. So, your single byte text letter is going to turn into a 2-byte tilemap entry. It's a simple conversion here as the game uses $49 $08 as the entry for the tilemap. I highly suggest using VSNES (http://www.romhacking.net/utilities/274/) to play around. It will tell you precisely where in VRAM the tilemap is for a given layer in any savestate with text on it. You can then edit the VRAM bytes of said tilemap to see what happens. If you understand how a screen is put together, this stuff is much simpler.

Your text is on layer 3. The tilemap is stored at effective VRAM location 0x1000. This DMA transfer handles transfer of a single 2-byte tilemap entry of 'I' from 7E:0604 to the specific address this tile entry goes at in the tilemap in VRAM. In this game, each tilemap entry gets transferred individually it seems.

I assume your actual text string has 0x49 only, right? If so, there's a small routine that turns that into 0x49 0x08 that gets stored at 7E:0604 for the tilemap entry. For VWF purposes, you're going to hijack that routine. You're no longer going to do that simple conversion anymore, and you won't be using the static font anymore that is stored in VRAM. You'll be building new dynamic tiles and make the tilemap entries point to those new tiles.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 04, 2013, 01:41:58 am
Do you know what a tilemap is, it's format, and how it works on the SNES? I'm not sure you understand exactly what you're looking for sometimes. A tilemap entry is always 2 bytes per tile. So, your single byte text letter is going to turn into a 2-byte tilemap entry. It's a simple conversion here as the game uses $49 $08 as the entry for the tilemap. I highly suggest using VSNES (http://www.romhacking.net/utilities/274/) to play around. It will tell you precisely where in VRAM the tilemap is for a given layer in any savestate with text on it. You can then edit the VRAM bytes of said tilemap to see what happens. If you understand how a screen is put together, this stuff is much simpler.

Your text is on layer 3. The tilemap is stored at effective VRAM location 0x1000. This DMA transfer handles transfer of a single 2-byte tilemap entry of 'I' from 7E:0604 to the specific address this tile entry goes at in the tilemap in VRAM. In this game, each tilemap entry gets transferred individually it seems.

I assume your actual text string has 0x49 only, right? If so, there's a small routine that turns that into 0x49 0x08 that gets stored at 7E:0604 for the tilemap entry. For VWF purposes, you're going to hijack that routine. You're no longer going to do that simple conversion anymore, and you won't be using the static font anymore that is stored in VRAM. You'll be building new dynamic tiles and make the tilemap entries point to those new tiles.

I didn't completely realize it was 2 bytes until a couple days ago.  Forgot about the palette byte that comes right after.  The palette byte is loaded directly AFTER the letter is loaded (When it gets stored to 7E0604)

I've known how the screen's been put together for the most part, or so I thought anyway.  I thought that was mostly covered in the previous pages.

The tiles start at right at the beginning of VRAM (The letters and everything included).  Isn't the Tilemap basically just how the letters are arranged on screen, rather how it sets them up?

I know I have to hijack the routine and such.  I'm most likely missing the most obvious thing that's been already mentioned by you and others.  I'm literally trying to figure out how it's picking the value from the Tiles.  It gets 7E0604 values for color/letter but then I'm not sure HOW it takes that value from VRAM and uses it to get the actual tile from VRAM.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 04, 2013, 05:45:01 pm
I'm not sure HOW it takes that value from VRAM and uses it to get the actual tile from VRAM.

That's exactly what the tilemap does. It indexes other tiles in VRAM and maps where to put them on the screen. That's a function of the hardware. In other words, the tilemap in VRAM references other tiles also in VRAM. There will be no game code that reads any map from VRAM and fetches tiles from VRAM. That's a hardware function (defined by the related hardware registers) acting on the tile map and tile data in VRAM at any given time.

Again, I recommend using VSNES to play around with the registers and VRAM hex data to understand how it works.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 05, 2013, 02:26:11 am
THAT'S what I didn't know.  I didn't know it was a hardware function at all.

Okay, I'm checking out VSNES.  It's making a little bit more sense to a point.  The 'name base address' I'm pretty sure I've messed with before to a point.

The tilemap address.. I didn't know altering the byte changed tilemap size as well.  That whole thing is a new bit of information to me.

Code: [Select]
$7E/212D A5 CE       LDA $CE    [$00:00CE]   A:009F X:0000 Y:0200 P:eNvMxdIzc - Load tilemap data (Sets as $1000)
$7E/212F 8D 09 21    STA $2109  [$06:2109]   A:000A X:0000 Y:0200 P:envMxdIzc - Stores
$7E/2132 A5 C7       LDA $C7    [$00:00C7]   A:000A X:0000 Y:0200 P:envMxdIzc - Load tile base data
$7E/2134 8D 0C 21    STA $210C  [$06:210C]   A:0000 X:0000 Y:0200 P:envMxdIZc - Stores tile base data

Traced this bit now as well.

All that's setting the Tile Base to $0000 in VRAM and then the tilemap to $1000.  I think that's what I've seen anyway.

So it picks the letter '49' (I) from 7E0604.  It's 49 08 now and that gets used as the index for tilemap entry and placement on screen basically?

Edit: Semi off topic in a way, but isn't Tilemap editing for a sprite basically it's Sprite Assembly?  So isn't this essentially just a background layer assembly/construction to put into other terms?
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 05, 2013, 06:07:13 pm
All that's setting the Tile Base to $0000 in VRAM and then the tilemap to $1000.  I think that's what I've seen anyway.

So it picks the letter '49' (I) from 7E0604.  It's 49 08 now and that gets used as the index for tilemap entry and placement on screen basically?

Yes, that's correct. Read the section 'Tile Maps and Character Maps' from Anomie's register doc (http://www.romhacking.net/documents/196/). You'll see how to interpret the tile index/number from the two byte entry. That indexes into the tile base area to the tile with the 'I' on it.

Quote
Edit: Semi off topic in a way, but isn't Tilemap editing for a sprite basically it's Sprite Assembly?  So isn't this essentially just a background layer assembly/construction to put into other terms?

Not really. These tilemaps are for background layers. None of this applies to OAM sprites. They're very different and have their own format and tables (which also can be tinkered with in VSNES to learn).
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 06, 2013, 02:08:03 am
Quote
The tile character data is stored at the address pointed to by registers
$210b-c, starting at byte address:
  (Base<<13) + (TileNumber * 8*NumBitplanes)

210B/210C gets stored twice it seems.  Each resulting in '11' as the byte.

So would it be like Tile Number = 49 * 8 * 2 = 490 (Which is actually where 'I' is stored in VRAM)

Quote
Starting at the tilemap address, the first $800 bytes are for tilemap A. Then
come the $800 bytes for B, then C then D. Of course, if only A is required
something else could be stuck in the empty space.


Does this apply to all background layers?
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 06, 2013, 07:48:23 pm
210B/210C gets stored twice it seems.  Each resulting in '11' as the byte.

There is an $11 in $210b and $210C  is $00. If you look at the details on those registers, you'll see there is a nibble for each of the 4 background layers tile bases. That's why BG3 and 4 have a base of $0000 and BG 1 and 2 have $2000.

Quote
So would it be like Tile Number = 49 * 8 * 2 = 490 (Which is actually where 'I' is stored in VRAM)
That part is correct.

Quote
Does this apply to all background layers?

Yes. That whole paragraph is a fancy way of saying the tilemap will vary in the size it takes in VRAM depending on the tilemap size you use for the background. Toggle the last two bits of $2109 to see the tilemap effects on that layer. The background size will change from 1 to 4 maps to make up the entire layer.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 07, 2013, 02:20:21 am
Quote
There is an $11 in $210b and $210C  is $00. If you look at the details on those registers, you'll see there is a nibble for each of the 4 background layers tile bases. That's why BG3 and 4 have a base of $0000 and BG 1 and 2 have $2000.

Ah okay, that makes more sense now then.  Got it!

Quote
Yes. That whole paragraph is a fancy way of saying the tilemap will vary in the size it takes in VRAM depending on the tilemap size you use for the background. Toggle the last two bits of $2109 to see the tilemap effects on that layer. The background size will change from 1 to 4 maps to make up the entire layer.

Yep, I was taking a look at that earlier.  It does some really crazy things to the tilemap when it expands on sizes like that.

Okay, I'm starting to understand this bit by bit.

So what I need to do is hijack the routine that basically loads 7E0604 and gets the Tilemap data, correct?  So would I have to drop how it gets the value from VRAM and make it read from ROM instead.  Then transfer that from ROM to RAM to VRAM?
-------------------------------------------
Edit: This is on topic but I had to take a test run

Code: [Select]
$7E/22A2 BD 03 06    LDA $0603,x[$06:0603]   A:000A X:0000 Y:0000 P:envMXdIzc
$7E/22A5 8D 05 43    STA $4305  [$06:4305]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size (low byte)
$7E/22A8 9C 06 43    STZ $4306  [$06:4306]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size high byte to 0
$7E/22AB E8          INX                     A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AC E8          INX                     A:0002 X:0001 Y:0000 P:envMXdIzc
$7E/22AD E8          INX                     A:0002 X:0002 Y:0000 P:envMXdIzc
$7E/22AE E8          INX                     A:0002 X:0003 Y:0000 P:envMXdIzc
$7E/22AF 8E 02 43    STX $4302  [$06:4302]   A:0002 X:0004 Y:0000 P:envMXdIzc    ;X+4 = low byte of source address
$7E/22B2 A9 06       LDA #$06                A:0002 X:0004 Y:0000 P:envMXdIzc          ;high byte of source address = 6
$7E/22B4 8D 03 43    STA $4303  [$06:4303]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22B7 9C 04 43    STZ $4304  [$06:4304]   A:0006 X:0004 Y:0000 P:envMXdIzc  ;bank byte of source = 0 (so read from RAM 00:06XX) [ Makes it read from 7E0604)
$7E/22BA A9 01       LDA #$01                A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc    ;do transfer
$7E/22BF 8A          TXA                     A:0001 X:0004 Y:0000 P:envMXdIzc     ;this is effectively increasing X by the amount of transferred data
$7E/22C0 7D FF 05    ADC $05FF,x[$06:0603]   A:0004 X:0004 Y:0000 P:envMXdIzc
$7E/22C3 B0 FE       BCS $FE    [$22C3]      A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C5 AA          TAX                     A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C6 E4 A5       CPX $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIzc   ;I'm assuming $A5 is the total amount of data to transfer

I removed this entire routine, rather, hijacked it and did a test run at 409FB0 and copied/pasted Sailor Moon - Another Story's screwed up routine to get the font/vram and junk.  It WORKED.  It actually read the letter from ROM and stored it into VRAM accordingly.  But the issue being is I don't understand HOW it worked nor do I want to use that games as it's just an ugly screwed up mess from hell.

But I now know that the routine that's been quoted is INDEED what needs to be replaced.  So that's a big step!
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 08, 2013, 10:43:27 am
So what I need to do is hijack the routine that basically loads 7E0604 and gets the Tilemap data, correct?  So would I have to drop how it gets the value from VRAM and make it read from ROM instead.  Then transfer that from ROM to RAM to VRAM?

What are you going to read from ROM? For a VWF, you're going to create dynamic tiles in RAM (since you no longer will have one letter per tile). You will be copying those tiles to VRAM and then altering the tilemap to now point to those tiles.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 08, 2013, 10:09:31 pm
I apologize heavily for having so many troubles with understanding all of this :|

Code: [Select]
$7E/2283 A9 01       LDA #$01                A:0006 X:0031 Y:0000 P:envMXdIzc
$7E/2285 8D 00 43    STA $4300  [$06:4300]   A:0001 X:0031 Y:0000 P:envMXdIzc
$7E/2288 A9 18       LDA #$18                A:0001 X:0031 Y:0000 P:envMXdIzc
$7E/228A 8D 01 43    STA $4301  [$06:4301]   A:0018 X:0031 Y:0000 P:envMXdIzc
$7E/228D 18          CLC                     A:0018 X:0031 Y:0000 P:envMXdIzc
$7E/228E A2 00       LDX #$00                A:0018 X:0031 Y:0000 P:envMXdIzc
$7E/2290 BD 00 06    LDA $0600,x[$06:0600]   A:0018 X:0000 Y:0000 P:envMXdIZc
$7E/2293 8D 15 21    STA $2115  [$06:2115]   A:0080 X:0000 Y:0000 P:eNvMXdIzc
$7E/2296 BD 01 06    LDA $0601,x[$06:0601]   A:0080 X:0000 Y:0000 P:eNvMXdIzc
$7E/2299 8D 16 21    STA $2116  [$06:2116]   A:00EA X:0000 Y:0000 P:eNvMXdIzc
$7E/229C BD 02 06    LDA $0602,x[$06:0602]   A:00EA X:0000 Y:0000 P:eNvMXdIzc
$7E/229F 8D 17 21    STA $2117  [$06:2117]   A:0008 X:0000 Y:0000 P:envMXdIzc
$7E/22A2 BD 03 06    LDA $0603,x[$06:0603]   A:0008 X:0000 Y:0000 P:envMXdIzc
$7E/22A5 8D 05 43    STA $4305  [$06:4305]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size (low byte)
$7E/22A8 9C 06 43    STZ $4306  [$06:4306]   A:0002 X:0000 Y:0000 P:envMXdIzc     ;set transfer size high byte to 0
$7E/22AB E8          INX                     A:0002 X:0000 Y:0000 P:envMXdIzc
$7E/22AC E8          INX                     A:0002 X:0001 Y:0000 P:envMXdIzc
$7E/22AD E8          INX                     A:0002 X:0002 Y:0000 P:envMXdIzc
$7E/22AE E8          INX                     A:0002 X:0003 Y:0000 P:envMXdIzc
$7E/22AF 8E 02 43    STX $4302  [$06:4302]   A:0002 X:0004 Y:0000 P:envMXdIzc    ;X+4 = low byte of source address
$7E/22B2 A9 06       LDA #$06                A:0002 X:0004 Y:0000 P:envMXdIzc          ;high byte of source address = 6
$7E/22B4 8D 03 43    STA $4303  [$06:4303]   A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22B7 9C 04 43    STZ $4304  [$06:4304]   A:0006 X:0004 Y:0000 P:envMXdIzc  ;bank byte of source = 0 (so read from RAM 00:06XX) [ Makes it read from 7E0604 ]
$7E/22BA A9 01       LDA #$01                A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22BC 8D 0B 42    STA $420B  [$06:420B]   A:0001 X:0004 Y:0000 P:envMXdIzc    ;do transfer
$7E/22BF 8A          TXA                     A:0001 X:0004 Y:0000 P:envMXdIzc     ;this is effectively increasing X by the amount of transferred data
$7E/22C0 7D FF 05    ADC $05FF,x[$06:0603]   A:0004 X:0004 Y:0000 P:envMXdIzc
$7E/22C3 B0 FE       BCS $FE    [$22C3]      A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C5 AA          TAX                     A:0006 X:0004 Y:0000 P:envMXdIzc
$7E/22C6 E4 A5       CPX $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIzc - Check for background scroll
$7E/22C8 D0 C6       BNE $C6    [$2290]      A:0006 X:0006 Y:0000 P:envMXdIZC
$7E/22CA 64 A5       STZ $A5    [$00:00A5]   A:0006 X:0006 Y:0000 P:envMXdIZC

This is the full routine for everything that's been labeled and such from the heavy help of everyone thus far.

Removing this whole routine.. actually does some extensive damage to the game per se.  No text shows up anymore, icon palettes don't update, text doesn't update, some graphics load incorrectly etc..



September 13, 2013, 03:18:48 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Okay, sorry about the double post, but this is getting.. frustrating.

Here's what I had in mind doing:

1. When the text pointers are being picked out, set a VRAM location storage for transferring. [ Which would be at $0100 ]

2. When the text picks an actual letter to print, it takes that value and multiplies it 4 times, which results in the correct area in ROM. (IE: 49 * 2 * 2 * 2 * 2 = 490.  Location of font is at 3E:8000 so adding it would result in 3E:8490)  It'd store the value say at: 7E0200 for 9084 then 7E0202 would be 3E: Thus being 3E8490 for 'I'

3. It'd count how many bytes to store (Being a fixed width of 08 at the moment).  So it'd load two bytes at a time, start storing them at 7E0210.  It'd decrease the width by one byte at a time while increasing the graphic counter by two at a time resulting in a 16 byte transfer to RAM.

4. At 7E2290, I'd remove all the code essentially and then:

Load $0100 for VRAM location and store that to $2116
Store $0080 to $2115 (Which I think is a trigger for VRAM writing?)
Store $0001 to $4370 (I think this has something to do with DMA)
Store $0018 to $4371 (Same as above I think)
Store $0210 to $4372 so it has a base of xx:0210 for reading from RAM
Store $007E to $4374 so it reads 7E:0210 for reading from RAM
Store $0016 (?) to $4375 so it knows how many bytes to read? (I think)

Gah.  I'm just confused on how to get this all going.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 13, 2013, 08:26:30 pm
The only way to tackle anything complex is to break it down into simpler achievable steps. Try step one (Basically your step 2).

Change the text routine to figure out where to pull a character from ROM. Debug that routine until it works as expected and you have the correct location at 7E0200.

If you get that done, try the next small step which is to retrieve that character from ROM and store in RAM somewhere. Put that code immediately after. Again, debug until you get it right.

Ok, so now you know you can pull characters from ROM and write them to RAM. Now you need to work understanding how to transfer that data to VRAM. Don't worry about what the game does. Just slap a DMA transfer or a manual transfer immediately after the code you wrote to store the character in RAM. Put a infinite loop right after that so it freezes so it doesn't even advance. Then debug this code until you can successfully figure out how to transfer a tile to VRAM yourself! You can debug this by seeing if the DMA triggers correctly in Geiger's debugger, taking a savestate and examining it in VSNES, or checking VRAM in an emulator that might allow you to view it.

Lastly, directly after your transfer (continue to forget about the game), you'll want to go for some tilemap changing code to reference the tile you just placed in VRAM. You can check for a successful tilemap change using savestate, VRAM hex viewer etc.

Summary
The idea here to to take the game out of the equation so you understand the fundamentals. The way it is now what the game does is confusing you on top of struggling with the fundamentals. So, separate the two for now. By the end of this exercise you'll have figured out how to retrieve a character from ROM, copy it to RAM, and then get that into VRAM. Then change the tilemap to reference your character on screen.

Finally, when you've figured out the basic mechanics of printing a letter to the screen, you can worry about what the game is doing.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 14, 2013, 02:10:59 am
Got it so far!  Stores the letter perfectly in RAM and now I'm working on transfering to VRAM.

DMA[0]: CPU->PPU Mode:1 0x7E0210->0x2118 Bytes:10 (inc) V:075 VRAM: 0100 (1,0) word

It's definitely triggering and says it's storing to 0100 in VRAM (And there is DEFINITELY data from RAM), but for some reason it's not showing up at all in VRAM at all.  Like, purely 00 00 00 00 keeps getting written when it's clearly taking from 7E0210 where there's data constantly there.

Code: [Select]
$40/A010 A9 18       LDA #$18                A:0000 X:0000 Y:000B P:envMXdIZc
$40/A012 8D 01 43    STA $4301  [$06:4301]   A:0018 X:0000 Y:000B P:envMXdIzc
$40/A015 A9 01       LDA #$01                A:0018 X:0000 Y:000B P:envMXdIzc
$40/A017 8D 00 43    STA $4300  [$06:4300]   A:0001 X:0000 Y:000B P:envMXdIzc
$40/A01A A9 80       LDA #$80                A:0001 X:0000 Y:000B P:envMXdIzc
$40/A01C 8D 15 21    STA $2115  [$06:2115]   A:0080 X:0000 Y:000B P:eNvMXdIzc
$40/A01F C2 21       REP #$21                A:0080 X:0000 Y:000B P:eNvMXdIzc
$40/A021 A9 00 01    LDA #$0100              A:0080 X:0000 Y:000B P:eNvmXdIzc ;VRAM store location
$40/A024 8D 16 21    STA $2116  [$06:2116]   A:0100 X:0000 Y:000B P:envmXdIzc
$40/A027 A9 10 00    LDA #$0010              A:0100 X:0000 Y:000B P:envmXdIzc ;How many bytes to transfer
$40/A02A 8D 05 43    STA $4305  [$06:4305]   A:0010 X:0000 Y:000B P:envmXdIzc
$40/A02D A9 10 02    LDA #$0210              A:0010 X:0000 Y:000B P:envmXdIzc ;2-byte Base Pointer to read from
$40/A030 8D 02 43    STA $4302  [$06:4302]   A:0210 X:0000 Y:000B P:envmXdIzc
$40/A033 E2 20       SEP #$20                A:0210 X:0000 Y:000B P:envmXdIzc
$40/A035 A9 7E       LDA #$7E                A:0210 X:0000 Y:000B P:envMXdIzc ;Bank to read from (Results in 7E:0210)
$40/A037 8D 04 43    STA $4304  [$06:4304]   A:027E X:0000 Y:000B P:envMXdIzc
$40/A03A A9 01       LDA #$01                A:027E X:0000 Y:000B P:envMXdIzc
$40/A03C 8D 0B 42    STA $420B  [$06:420B]   A:0201 X:0000 Y:000B P:envMXdIzc
$40/A03F 6B          RTL                     A:0201 X:0000 Y:000B P:envMXdIzc

Code: [Select]
02 7E 1C 7C 7A 06 7C 1C 70 10 02 7E 7E 7E 00 00 - This is what's currently at 7E:0210 as an example.  But VRAM just consistently keeps storing 00 00 00 00 00 00
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 14, 2013, 10:12:37 am
You can only transfer to VRAM during vblank or it will fail. Do a quick test and try it on ZSNES and it will probably work as-is.

You'll need to wait for vblank by using register $4212 and bit 7 (vblank flag).

Something like this should get you going right before your DMA code starts:

Code: [Select]
waitforvblank:
lda $4212
bpl waitforvblank

For actual final code, you'd probably want to do some fancier code to either wait for a fresh frame, or determine if you're already in vblank and how much time is left to know if you complete the transfer. These types of things will avoid periodic timing glitches that could occur with the simple check. That's a topic for another day though!
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 14, 2013, 12:14:18 pm
(http://i43.tinypic.com/anll1.png)

Success!  The only thing now is trying to get the Tilemap/base to construct properly. (I'm still really confused on what these are/how they work)

Get that going properly and I'll still re-organizing all the code to be proper/clear out when new dialogue, etc..

Edit: Oh.  I went to VRAM at $1000 to edit the tilemapping and had it go sequential at like 21 08 22 08 23 08 etc.. Well THAT makes sense on the construction.  Just need to figure out how to make it NOT do that.

Edit 2: WAIT! I think I found a method though it's not absolutely perfect!

It uses the reading from 7E0604 to read dialogue and tilemap.  So what I did was force a hardcoded setting of $20 for a value there and each letter it increases by 1.  So it reads 20 08 21 08 22 08 etc as it goes :) MAY not be the best coding and it has a couple bugs, but it's working!  It's almost a decent dynamic tile reading!

Do you have any pointers on making it look more.. cleaned up?
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on September 15, 2013, 10:13:48 am
Congrats. :) That sounds like a reasonable approach to me. To clean it up, you'd probably want as few game hooks as possible. So, you can think about how to more smartly integrate it with the game code. Also things like if you're still using your new DMA transfer, perhaps you want to figure out how to get the game's original transfer to handle what you want. Or, sometimes it's a cleaner approach to disable several of the games routines and replace with your own replacements. There's more than one right answer. ;)

I'd say get it working perfectly and worry about optimization and cleanliness later.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 15, 2013, 02:24:46 pm
I still plan to VWF this but right now just dynamic tiles takes an importance.

Edit: Fixed an issue, though I need to move everything to a new ROM soon.

I had to incorporate a new text command which set the VRAM value back to $100 and then set the letter value back to $20.  Then altered a 00 command to hit ABOVE 7E0604 and reduced the counter by two bytes.

The value to set VRAM and such again would be '84' (Which goes completely unused along with about 4-5 other values) in the English ROM.  So once I port the code over to a regular ROM, I can start modifying the text with the new value to see if it causes any discrepancies in the game itself.  If not, then onto the next step of actually implementing a VWF!


Edit 2: Moved everything to a fresh MMX3 Rom.

Erased the 'new' command and am trying to rework it so it uses no commands and does the storage/loading automatically.

The issue right now is that when the letters scroll, 7E0604 MUST be 00 00 otherwise it'll result in writing letters to the side of the screen.  So at this point I'm trying to store the letter value to another area in RAM before it scrolls then load it after it scrolls.  It's pretty.. iffy right now.  Once I can get this to be automatic it should solve basically every problem I've ran into.  I just hope I can get this working right.

Edit 3: Got most of it!  All dialogue in game seems to work.  Just when you swap characters it.. gets weird.  If you let the game run normally it'll bug up, but if you do a breakpoint then it prints the letters correctly (What the heck is up with that?)

And 'GET WEAPON' text is bugged as well.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on September 25, 2013, 03:35:33 pm
I think Mega Man was almost a bad choice to use this style of dialogue writing with how it scrolls Layer 3 and writes over it.  Keeping the original style really creates a ridiculous challenge, though, not completely impossible.  It's just a pain in the butt to work around.  Otherwise if it was removed to go with the Mega Man & Bass+ system, it'd just wipe it clean and write over which would remove every single problem.

But onto the previous project I had!  Sailor Moon: Another Story.

(http://i44.tinypic.com/24m9q8x.png) - Temporary tilemap editing in action! (Placeholder font!)

Edit: Quick question.  I'm trying to have the game pull the font from ROM without using pointers like the original system.. but the font is 8x16.  It works fine for 8x8 but I have no clue what I should do for 8x16.  Do I really need to use pointers for each letter?
Title: Re: Getting Started on a VWF?
Post by: henke37 on September 30, 2013, 07:17:14 pm
What is a pointer? It is a variable storing a memory address. What address space does the memory address use? Is it even measured in bytes?
Title: Re: Getting Started on a VWF?
Post by: KingMike on September 30, 2013, 08:32:39 pm
The pointer is a memory address.

As to why 8x16 doesn't work for you, justin, well that's an issue with that game's code.
You will have to look at the code. So, an 8x8 works. What is so different about an 8x16? What does an 8x16 do?
How can it be changed?
If the font is uncompressed, then that would mean each character is the same size. Then rip out that part where it reads the pointer table to each character (probably something like FONT_POINTER = POINTER_TABLE[ CHARACTER_HEX_VALUE ]) and replace it with that does like NEW_FONT_POINTER = CHARACTER_HEX_VALUE * SIZE_OF_A_FONT_CHARACTER + BASE_ADDRESS_OF_FONT in whatever is necessary with the code.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on October 01, 2013, 01:32:44 pm
That's what I've been trying to do, but right now I'm just going to have to redo the entire code in general.

What the game does is use pointers to get each letter.  It uses that to load the graphics and then stores it into VRAM.  It's a literal ROM --> VRAM transition for this games dynamic tiles.

I cheated a little and looked at Chrono Trigger's routine for handling it's letter size and kind of hijacked that.  It loads all letters but it loads a chunk of excess (Which is to be expected without any alterations to the routine).  So I'm going to pick out an empty RAM spot and start storing the graphics there to get everything sorted out first.  After that, I'll need help fully understanding VWF implementation.  Though, I do think I have a general idea.  I'll post that once I get the basics working as I don't want to overwhelm myself.

Edit: Actually, Chrono Trigger's method works amazingly well if I'm understanding this right.

What it does is store each letter into a location in RAM, like the usual junk.  VRAM doesn't store it letter per letter basis, but rather, it stores it by a block of RAM.  A whole line of text essentially gets stored into 7EF000 in RAM with Chrono Trigger.  Each time a new letter is written, that block gets transferred to VRAM.  Now when it needs to update a location in VRAM, it updates whenever it does a new line.  The RAM location stays the same, just the location gets shifted in VRAM.

So it's not letter per letter but rather block per block (Same block).  Not sure how efficient this is but I think it's actually quite nice and makes it a lot easier to deal with.

Edit: Got most of it working.  Still a couple errors now since I updated the routine.  Font/Tilemap error.  Fix that then I can start putting in the VWF values.  Hopefully that'll solve the issues then!
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 18, 2014, 09:24:53 pm
Bringing this up again, but I have another question on VWFs.

http://board.byuu.org/viewtopic.php?f=9&t=3490

This topic states 'Dynamic Rendering' and 'Static Rendering', unfortunately, the article listed in that topic is gone.

What exactly are Dynamic/Static rendering?  From what he said, he uses static rendering in Bahamut Lagoon.  I'm wondering what exactly it is as I'd LOVE to try and port that into Tales of Phantasia.  TOP's VWF, even in little amounts, lag so ridiculously hard that it's just obnoxious.  I'm wondering if that'd be a way to per se 'fix' the issue.
Title: Re: Getting Started on a VWF?
Post by: BRPXQZME on January 18, 2014, 10:30:32 pm
Internet Archive’s got your back (http://web.archive.org/web/20130121234738/http://byuu.org/articles/hacking/proportional-fonts).
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 18, 2014, 11:06:12 pm
Quote
The biggest limitation is speed. Rendering an entire screen full of item names at 2bpp on a 2.68MHz CPU is indeed painful. Combined with limited Vblank time to transfer the tile data, you can find yourself needing up to 2000ms to render a full screen. And during this time, you will see the new items slowly replacing old items as you flip through screens, with significant lag.

Quote
When you are requested to write an item into the tile map, simply ensure that you are in Vblank, index into your block of all pre-rendered item names, and then DMA it over. This takes about one scanline per item.

Is he basically saying that instead of having the screen consistently writing to the screen, only have it update when needed and just replace the tile map instead of VRAM entirely?
Title: Re: Getting Started on a VWF?
Post by: Gemini on January 19, 2014, 09:05:21 am
Basically he says "screw real time rendering & shifting, prerender 8x8 tiles!", which sacrifices ROM space for speed and makes everything look shiny and nice. You're still going to need dynamic rendering somewhere, due to variables, counters, and such, but you gain a lot of speed due to not using the CPU for shifting tiles around every time. Byuu also suggests to use the SRAM as a scratchpad of sorts, so that WRAM doesn't get polluted by custom data the hacker needs. Of course, this approach won't work with anything like dialog with timed progression each 2-3 frames or so; it this case you're gonna have to use dynamic, but most games allow the hacker to do so thanks to canvas rendering.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 19, 2014, 10:05:25 am
Pre-render the 8x8 tiles?  (I'm not exactly sure what this means but I'll take a whack at understanding).

Do the tiles get spaced out and stored to RAM BEFORE VBlank or anything occurs, then it just transfers it over?  I'm pretty sure my understanding is lacking hard.
Title: Re: Getting Started on a VWF?
Post by: Gemini on January 19, 2014, 10:43:08 am
It's pretty much a simple DMA copy of the tile data from ROM to VRAM. You pre-assemble in ROM all the 8x8 stuff you need for menus and such and then copy whatever is necessary at runtime.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 19, 2014, 10:57:32 am
So it's basically doing everything in one swoop (For the most part) instead of going through a bunch of shifts trying to get what it needs during the transfer?

Edit: I just took a look at Bahamut Lagoon's code for the VWF a bit.

I guess it varies HEAVILY in terms of how it does it's graphic storage.  If I'm seeing this right, most other games go through a loop to store the graphics, while Bahamut Lagoon's just loads code after code after code storing each couple bytes in a consecutive sequence instead of using a loop.

Edit 2: Actually, it's pretty similar at points with Chrono Trigger's VWF if what I'm seeing is right.
Title: Re: Getting Started on a VWF?
Post by: tryphon on January 19, 2014, 12:37:22 pm
For semi-dynamic rendering, would it be possible to store in RAM the last rendered char, and when rendering a new char :

- adding the new pixels to the last rendered char in RAM
- then DMA from RAM to VRAM

It would permit to benefit both of the pre-shifted chars in ROM (you'll need 8 versions of each glyph), and use it for dialogs.

I think I'll take this approach for Genesis games (though I think the 68000 is fast enough to make the logical shifts at runtime), but I don't know if it's doable for SNES. Its processor is know to be slow, but I don't know to which extent...
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on January 19, 2014, 06:48:37 pm
What the article means is rendering all of the menus and items once ahead of time, and storing the results in ROM. Then you simply DMA them like pre-rendered graphics when you need them. That's how you could do a VWF 8x8 menu in 2 frames. The only things that need to be done dynamically are variables such as Gemini mentioned earlier. Even that can be worked around to some degree depending on the specific variables in question.

Dynamic rendering refers to combining the letters and drawing out the tiles in RAM on demand, while static rendering is simply copying the pre-rendered data from straight from ROM to VRAM. Dynamic text rendering vs. static graphics loading.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 19, 2014, 07:09:14 pm
What the article means is rendering all of the menus and items once ahead of time, and storing the results in ROM. Then you simply DMA them like pre-rendered graphics when you need them. That's how you could do a VWF 8x8 menu in 2 frames.

That almost sounds like 'faking' a VWF by using the graphics tiles in ROM as different 8x8 blocks.

I didn't think you could store the data straight INTO ROM though and use it from there.
Title: Re: Getting Started on a VWF?
Post by: tryphon on January 19, 2014, 07:32:25 pm
What's really so slow when doing static rendering ?
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on January 19, 2014, 07:44:29 pm
That almost sounds like 'faking' a VWF by using the graphics tiles in ROM as different 8x8 blocks.

There's nothing fake about it. A proportional font is a proportional font whether it is pre-rendered and static or dynamically rendered and done in real time. Regardless of what you think about it, that's simply what the article is about. I'm just explaining it to you.

Quote
I didn't think you could store the data straight INTO ROM though and use it from there.

Of course you can. Render all of the menus and grab the resulting tiles. Render ALL of the items in the game and gather those results. Do whatever you need to do to pre-render the text to get the results. Then, assemble a new ROM and store them all in the ROM. That's precisely what static rendering implies for this. It's pre-rendered, it's static. You are no longer dynamically rendering the text. You're not drawing to RAM, you're not drawing to anything but the tilemap, and even that can be statically stored in the ROM too. This the way it is done in 2 frames as demonstrated by the article.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 19, 2014, 07:53:54 pm
I'm wondering if it's similar or the 'same' thing I had going on Tales of Phantasia to a point?

(http://i43.tinypic.com/ykxlk.png)

I had all that pre-rendered then I just plopped it back into ROM.  It's using the empty tiles as a basis for it's text.

Is this basically what it is except it pulls the data from ROM instead when it needs it?  If so, I could easily see this work for item names.

The biggest thing I noticed was that Bahamut Lagoon's item descriptions were lightning fast while Tales of Phantasia's were ridiculously slow.  Were Bahamut Lagoon's descriptions also pre-rendered?  Even if I cut out all the excess on TOP, it's ridiculously slow regardless, which is what caught my eye.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on January 20, 2014, 07:54:29 pm
Yep, that's pretty much it. Now you're catching on. ;)

I hope I did not confuse you with the wrong idea about the ROM though. While all of this pre-rendered static data is in-fact in the ROM, you still must copy/DMA it all to available VRAM space and map the appropriate tiles to it so it shows up on screen. You can't display anything straight from the ROM. I'm sure you did just that with the example you've pictured though or it wouldn't have worked!

I can't comment on ToP or BL as I haven't played or looked at either in ages. There could be more than one reason why one would be speedier than the other. You'll have to dig deeper and see what's being done if you're interested.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on January 20, 2014, 08:13:52 pm
I've been digging through their routines on the item description and I'm just lost on why it's superior in every way.  Chrono Trigger's is the same way actually.  Though, that game just renders it tile by tile on screen, you CAN force it to draw the entire string at once and even then, it's a HELL of a lot faster than Tales of Phantasia's.  I'm really unsure why that's so. 

It seems it must be in the VWF code or something in general with it.  If I remove everything else, it's still laggy.  Cut out the entire way to write the description and you can fly through the items no problem.

----------------------------------------------------

Edit: If I were trace Tales of Phantasia's VWF routine, label as much as I can and post the code, would I be able to get some help on figuring out why it's so slow and ways to improve the code?
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 14, 2014, 12:02:37 pm
Popping this back up.. again (For like the eighth time) but this time about pre-rendered font!

Is there anyway to have a check to see where data is in VRAM or would it be better to go the route of 'manual' placement?

For example I mean in this image.
(http://i43.tinypic.com/ykxlk.png)

Would it be plausible to have it check for a certain 'end' of pixels and then the next item would be written directly next to it? Like, where HP and TP are.  It'd transfer 'HP' over until it hits '00 00 00 00' or something then stop.  After that, it'd hold the position it's at in VRAM, check if there's any slots left in the 8x8 tile, if so, add that to the next storage point.  It'd then store a 'blank' 8x8 tile then the next object you want to transfer would be stored directly AFTER that blank.  Is this a good idea, rather, a POSSIBLE idea?  It'd save a horrific amount of code and data while actually maintaining VRAM nicely.

This would especially help when it came to items, spells, etc..

Edit: The other method I can think of is to have the VRAM location be stagnant and it'd carry that over for each transfer.  Though there'd be a byte to dictate each transfers size that WOULDN'T transfer.  So it'd essentially be consecutive.
Title: Re: Getting Started on a VWF?
Post by: FinS on April 15, 2014, 11:30:49 am

Are you using a register map. This will all be in it. The register for reading VRAM data is $2139 and to set the address is $2116 and to set the address increment is $2115, but this would not be practical to use because VRAM can only be accessed during blanking. If you absolutely had to get values out of VRAM those are the registers you would use.

It sounds like you are planning a hybrid of static / dynamic rendering. This would probably be best accomplished using WRAM to assemble the tiles which would defeat some of the purpose of pre-rendering.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on April 15, 2014, 11:36:28 am
I'm using a mixture of both due to how the game handles it's data.

When I went flat out dynamic, it actually caused a significant amount of lag (Though that was probably my terrible coding).  Most of the data in-game will be static but certain things like PC Names will have to be dynamic due to being able to change them.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 05, 2015, 05:45:20 pm
...And we're back once more <3 (Anyone else noticed it's like on a yearly basis this pops up and seemingly around similar times?)

So I decided this is PROBABLY the best time to tackle a VWF since it's with a game that has a really, really simple routine to modify.  If anyone's been following my topics, you can probably guess that it's Sailor Moon SuperS - Fuwa Fuwa Panic!

The routine originally stored ALL the tiles it used for the font into VRAM (Which.. was really frikin horrendous for a game like this.  SO, SO MUCH wasted room).  It was a pretty basic routine.  Pick out from VRAM where it loads, update tilemap, blah.

I've altered the routine heavily so 'at this moment' it picks the letter from ROM and sends it into VRAM as it's needed.  I'm holding off with the ROM --> RAM --> VRAM bit until I've got the right idea of what's going on with a VWF, but I'm fairly confident I can get this working.  I took a test whack with the idea I thought was correct (Obviously was wrong), but I see that the only problem I technically had was how it was storing everything as I'm not sure exactly how to space things properly.

So basically, what the heck do I do from here after the ROM --> VRAM is altered to ROM --> RAM --> VRAM?

I think my biggest issue is understanding the whole shifting bit.  I really do not understand that aspect, even re-reading it, it doesn't click with me on how it works.  Do I load the location of the letter from ROM, store it then shift things or.. just what?  I KNOW I can get this now, I just really need help on understanding the main portion of what should be going on.
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 05, 2015, 06:45:57 pm
It depends entirely on what you need it for. Example: you need a dialog box with proportional rendering. You have a number of options, if your game prints characters in sequences, rather than a single pass. In this case, the simplest solution used by some games is to have a line of dialog stored in a region of RAM used like a canvas, and you DMA transfer every character update. Seek to next line? Clear the buffer and start over again, until you hit the end.

As for the actual execution of canvas code, it's nothing more than bit logic. You shift a lot and OR the result to your tile canvas. This is some old C code I had for a DS project, which works with canvas logic: http://pastebin.com/GFKQ1cZV
Check RenderCanvasChar from line 219, that's where the VWF magic happens. It should help you understanding a bit better the logic, although SNES graphics work a little differently.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 05, 2015, 07:06:05 pm
In this game's case, the RAM canvas would be completely blank and be written to as the dialogue is going.  After each letter, it'd send the whole section into VRAM and the tilemap would be updated accordingly (Which works fine with no noticeable lag)

But what exactly do I shift?  The C code looks like it just grabs the bits of the letter, shifts it right however then adds it back to the buffer.  (Would the buffer in this case be the RAM canvas or would it be essentially how many bytes are available to write to or..?).

If that's the case, would I just load the first couple bytes (maybe the first byte?) of the letter it calls from ROM, ROR it, send to RAM, load the next bit, ROR it then OR it with the last value there or.  I'm just lost on that aspect really.
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 05, 2015, 08:03:53 pm
The code shifts to the left and ORs when it needs a pixel merge, otherwise it shifts to the right when it needs to fill a new tile. In other words, left shift pushes the tile to right in terms of graphics, while right shift does the exact opposite. On SNES it's the opposite iirc and you also need to account for how planar works in representing scanlines.

Another solution to VWF with no shifting is represented by having multiple copies of the font with tiles already shifted, which drastically reduces overheat due to looping a lot per tile. In that case you'd only have to OR for a merge and assign for pushing a new tile.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 08, 2015, 11:19:26 am
I'd prefer to go the straight up route of having it pull the letters from one font set instead of multiples.

So then if I understand any of this correctly: It grabs the font graphics, shifts it to the left and repeats the process until it hits the end of the 'width'.  Once it does, if there's another letter or anything after, it ORs it so it can merge the two bits together after that space?
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 08, 2015, 11:53:13 am
I'd prefer to go the straight up route of having it pull the letters from one font set instead of multiples.
That would be only useful for screens with intensive lag due to shifting. Otherwise you probably don't need it.

Quote
So then if I understand any of this correctly: It grabs the font graphics, shifts it to the left and repeats the process until it hits the end of the 'width'.  Once it does, if there's another letter or anything after, it ORs it so it can merge the two bits together after that space?
It reads, left shifts, ORs and writes when you push a tile to merge, then it simply reads, right shifts and writes if you have graphics left from a previous tile. In other words: x%8 != 0 -> read+left shift+or+write, otherwise read and write; data left from tile? Read+right shift+write.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 08, 2015, 01:29:28 pm
Hm.. maybe I'm going about this the wrong way.  The original idea I had was to just have it sequentially keep writing to RAM and send the whole chunk into VRAM at once.

Would it be easier if I had just a very small section of RAM, maybe enough room for a one line sentence in itself (Relatively small chunk overall), and have that be like a scratchpad?  It'd write the letter first, if any space left, merge with the next letter via ROR/ORA otherwise just take that letter and send to VRAM?

Or would I need to have two sections essentially.  One for a scratchpad for the letter and another for the 'actual' area to be transferred into VRAM?
Title: Re: Getting Started on a VWF?
Post by: tryphon on July 08, 2015, 02:15:48 pm
data left from tile? Read+right shift+write.

It's slighter easier if you use 16 bits words. But maybe SNES has not 16 bits data registers ?
Title: Re: Getting Started on a VWF?
Post by: mziab on July 08, 2015, 02:22:24 pm
It's slighter easier if you use 16 bits words. But maybe SNES has not 16 bits data registers ?

The SNES does have 16-bit registers. Otherwise it would be a pretty poor 16-bit console :) And in fact that's a good trick I like to use to avoid left-shifts altogether.
Title: Re: Getting Started on a VWF?
Post by: tryphon on July 08, 2015, 02:24:57 pm
I never made SNES hacking but I've been told that, precisely, its cpu wasn't exactly a 16 bits one :)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 08, 2015, 02:34:46 pm
Now I'm even more confused  :(
Title: Re: Getting Started on a VWF?
Post by: tryphon on July 08, 2015, 02:47:44 pm
I can explain how I did it, but it was for Genesis. I don't know to which point it's transposable to SNES. Or else, forget my remark, its purpose wasn't to confuse :)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 08, 2015, 06:24:27 pm
I think I'm somewhat noticing a trend in a few games I've checked on with their routines, I think.

From what I see, it seems to get the letter first and draw it into RAM.  After that, it gets the width of the letter then does some other stuff (Not sure, seems like it variates a little here).  I think it ORS the result afterwards and what not even if nothing else is quite drawn.  That way it keeps doing the routine once the next letter is written.  I think anyway.
Title: Re: Getting Started on a VWF?
Post by: BlackDog61 on July 08, 2015, 06:58:11 pm
That makes sense. if I read you right, the games do:
- Check width for the next letter to add. If new_letter_width + total_width_so_far > line_max_width then stop the process (or go to the next line, if that is an option)
- Fetch letter
- Shift letter graphics by "total width so far"
- OR it into the current RAM buffer
- add the letter's width to total_width_so_far
- Repeat.

In a fixed-width font, the letter's width is constant. So it is not fetched - a simple constant is used.
Turning this into a VWF is as stupid as
- adding a width table somewhere
- reading the width table to fetch the letter width, instead of using a constant.
Done.

(Well, mostly done, as then screens layouts probablyneed adjustment.)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 08, 2015, 07:40:13 pm
Okay, I want to make sure I get an idea of how this process will work before I fully tackle it.  I feel like I'm getting it but then just get lost in mid-process as I type it out :<

1. Grab the letter that'll be printed.
2. Draw letter into an area into RAM (Scratchpad area)
3. Grab the width of the current letter
4. Shift the letter by the width.
5. OR the result into the actual RAM area that'll be sent to VRAM.

I think?

I'm lost on the left over width and stuff still.
Title: Re: Getting Started on a VWF?
Post by: BlackDog61 on July 09, 2015, 04:34:19 pm
Yep, you're getting there.
(I think you should just try stuff out - it will be easier to see it in action.)
You have to shift enough that you never overwrite a previous letter; that's the onlymissing bit.
AssumingI understand what we're talking about, that is. ;D
Title: Re: Getting Started on a VWF?
Post by: henke37 on July 09, 2015, 05:46:11 pm
Except that some tricky characters are supposed to overwrite others.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 09, 2015, 06:15:26 pm
If I can get a chunk of the routine done properly even that would greatly help.  It makes it really difficult to understand when I can't visually see it yet.  Makes it even harder when I'm still struggling to get the basic idea going.
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 09, 2015, 06:22:15 pm
If anything, you could write some simple PC program to shift SNES tiles around and see the result with an editor.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 09, 2015, 07:03:18 pm
I took a test drive on part of the routine with the shifting.  I kind of see what it's doing, but I'm still lost a bit.  I'm using Nightcrawler's board topic as a basis idea to get a test routine going.  I got the ROR segment going but it shifts everything enough to where it's actually a byte off on visibility.  Went ahead and tried the merge and it.. does some really weird stuff.  Not exactly sure what I'm doing wrong per se or what's going on fully.
Title: Re: Getting Started on a VWF?
Post by: Normmatt on July 09, 2015, 07:59:44 pm
Have you read this blog post (http://mother3.fobby.net/blog/2008/03/29/welcome-to-text-welding-102/)?
Title: Re: Getting Started on a VWF?
Post by: KingMike on July 10, 2015, 01:26:01 am
For an explanation why the shift.

OH AND ANOTHER THING BEFORE YOU START: although your game may store its original font in 2bpp or more, it is FAR easier to work on your VWF in 1bpp. Use a 1bpp font as your working font, and if the game is using 2 or 4bpp, write a function to up-convert your finished VWF tile as you load it into VRAM. (while I can't remember the converstions offhand, I recall it's usually something simple like writing each byte twice or adding a 00/FF before/after every byte. You can probably tell if you use WindHex and play around in the tile editor by drawing a few test tiles and then compare the resultant hex)
If you have to add a shadow that's a bit trickier but still far easier to do in the transfer phase.

You need variables: PixelOffset to store how displaced the current character is from the edge of the tile, and LetterWidth to store the width of the current character.
You will probably also need a scratch buffer at least two maximum width characters wide (your workspace for a VWF tile), as well as another buffer 2 characters wide to hold a single character for shifting. (though if you get more experienced at code you may be able to do clever coding to omit that. Though with only three registers on the SNES compared to 8 data registers on the Genesis, it may not be as feasible on SNES for that optimization)

Say you have the word "Abra".
Since it's the first letter, PixelOffset is 0 because you are storing at the (left) edge of the tile.
Say "A" is 7 pixels wide.
At this point you can just copy the A to your scratch buffer because you don't need any shifting. Note that since you started on pixel 0 of the tile and your character is 7 pixels, you have used (0+7) pixels width of your buffer, your PixelOffset is 7.

Next character. Say the "b" is 5 pixels.
Since the previous character was 7 pixels, you need to read the "b" from the font and then shift it 7 pixels right. Make one buffer simply that "b" shifted right 7. You need to shift it 7 because you're placing it to the right of the "A" that was 7 pixels wide.
Now merge (the ORs) that shifted "b" tile with the previous "A". So now you'll have a tile that says "Ab". Again, since you started the "b" on pixel column 7 of the buffer and the "b" was 5 pixels, you have used (7+5 or 12) pixels width of the buffer. Your PixelOffset is 12.
You'll need to copy that tile into VRAM, or into a canvas holding the entire message window. However your game is managing it.
Once that "Ab" tile has been copied, you can update your scratchpad. Maybe you can update it right away, maybe you'll have to wait until your VWF routine begins to process the next letter. Depends on how the game is coded.

But, say your font had a maximum with of 8 pixels per character. That means the first tile, with the "A" and some of the "b", has exceeded the 8-pixel tile size and thus the first 8-pixel tile is no longer needed (since you already transferred it to the window canvas. You should the clear out that left side of the tile, by copying the right side data to the left and then replacing the right side data with empty space. (so you'll have room to draw the next character) Since you cleared out 8 columns of your pixel buffer, you should reduce your PixelOffset by 8, from 12 to 4. Since you will then start drawing on column 4 of the updated scratchpad. Likewise, you will shift your next character "r" 4 pixels right before ORing it into your VWF tile.
If your "r" is 6 pixels, that'll fill up to column 10 (4+6) in the buffer and again you'll need to flush out the filled tile before the "a".
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 10, 2015, 04:46:27 pm
That's a heck of a lot more in-depth and easier to understand.  Okay, going to take a whack at the explanation again.  I'm ignoring the last paragraph at the moment because it's over my head at the moment but I think I got the idea.

I'll attempt using a 1BPP font.  I can probably look at Tales of Phantasia and see how it adds it's shadow.  It's just a tiny chunk of code from what I have labeled out.

1. PixelOffset would be set to 0 before the routine actually starts.  (I assume WELL before any text so that it doesn't get zero'd out repeatedly each time a letter appears).
2. Have two areas for scratchpadding the letters which can be used to later combine them. (Already got the areas figured out)
3. I assume I'd put a check at the beginning of the routine that specifically checks if PixelOffset > 0.  If so, VWF , otherwise, just write it straight into the buffer.
4. The letter width table is essentially the PixelOffset I believe.  So it'd load the letter, grab the width and store it to LetterWidth but ADC it to PixelOffset.

This is where I get a little lost but here goes.

Since A had nothing, it was written to the scratchpad, routine ended and it went to load the next letter, which in this case would be 'b'.

5. It grabs B and stores it into scratchpad #2.
6. Grab LetterWidth and shift scratchpad #2 that many times.
7. OR the scratchpads together and store it back thus creating 'Ab'. (Does this go to a new area that does get transfered or does it go back to a scratchpad?)
8. Send the tile into VRAM, update tilemap as needed.

Does that basically sum up the first portion?

Edit: Woop.  I can't get it to store 1bpp properly.  It keeps trying to load it as 2bpp.  Even then, for some reason when it stores into VRAM it actually MERGES with the data that was there instead of erasing it.  Would I need to clear out that entire section of VRAM first?
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 10, 2015, 05:40:24 pm
Don't add a shadow via code, it's only going to slow you down and you can manually draw a shadow anyway by storing your font as 2 BPP. Never use 1 BPP unless it's absolutely necessary for huge fonts that wouldn't fit otherwise, which isn't your case (and neither is for most western languages).
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on July 11, 2015, 01:19:21 pm
Speaking of Tales of Phantasia. Didn't already do this there? You had an 8x8 VWF there for the menus, right? To do that you had to draw tiles dynamically to RAM. It's the exact same concept here.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 11, 2015, 01:55:32 pm
I didn't do it actually.  I hijacked the routine they used for the weapon names, item descriptions etc..  and used that on certain aspects.  Though, most areas now are static rendered instead of dynamic rendered.  The only dynamic in the menu so far are just the PC names, item descriptions, spell descriptions and a few other minor things.
Title: Re: Getting Started on a VWF?
Post by: KingMike on July 11, 2015, 03:39:03 pm
My previous post, in visual form.
http://i55.photobucket.com/albums/g155/sahagin/vwfexplanation_zpsz41q0pf5.png

I do not agree with Gemini about 1bpp.
I always use 1bpp because I can make my VWF code simpler and more to-the-point without trying to combine (and debug!) two tasks together.
I don't even know if the "shadow" part applies to Justin's game, but even if it does, I'd ignore for the time being until the core problem is understood, and then we work out the other details later (such as the one at the end of my "Lesson 1" example).

I'd worry about getting a 1bpp font written to RAM/VRAM as the primary thing (even if that makes it show up wrong in game), and then worry about fixing it to 2bpp or whatever is needed as a separate learning step.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 12, 2015, 01:02:33 pm
Trying it in 1bpp atm just to keep it easier with the explanation.

I've got the letter storing into both workspaces properly and it ORs the first letter around, but then I get really screwed up later on.  It seems like right when I have to actually shift the letter and then merge it back is where the entirety just doesn't work.  I'm blatantly screwing something up but not quite sure what.  I'll finish writing the current code and then post what I have.
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 12, 2015, 01:12:14 pm
I do not agree with Gemini about 1bpp.
I always use 1bpp because I can make my VWF code simpler and more to-the-point without trying to combine (and debug!) two tasks together.
I don't even know if the "shadow" part applies to Justin's game, but even if it does, I'd ignore for the time being until the core problem is understood, and then we work out the other details later (such as the one at the end of my "Lesson 1" example).
Technically speaking 1 BPP is not that much useful, even for code simplicity reasons. Sure, you do less shifting as you only deal with one plane, but you still need to upscale to 2 BPP at some point, which is trivial and only required when your font is really huge with little room left for storage. In the end it doesn't provide any usefulness, it's only extra steps, more code, and slower performance when you need a huge bulk of stuff to be rendered at once.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 12, 2015, 01:38:14 pm
I'll worry about making the font 2bpp after I get a grasp of understanding on this at the moment.  It's not too big of a deal right now, more-so understanding is the key.

I've got a good idea of what's going on and I'm PRETTY sure I know the problem at the moment.  The error I'm seeing is that the 'b' is not being shifted correctly to the 'gray' area on that little explanation.  So when it ORS everything, it's literally combining the two letters onto one plane which is screwing everything up.  I'm not exactly sure why it's not storing there though.  I 'THINK' I have the code correct?  I'll start tracing it now and post what I have going on.

Code: [Select]
$83/99ED 22 40 ED 83 JSL $83ED40[$83:ED40]   A:001A X:9B73 Y:006D P:envMxdIzC


$83/ED40 85 02       STA $02    [$00:0002]   A:001A X:9B73 Y:006D P:envMxdIzC ;Store current letter to 7E:0002
$83/ED42 A9 7F       LDA #$7F                A:001A X:9B73 Y:006D P:envMxdIzC ;Set bank to be $7F
$83/ED44 48          PHA                     A:007F X:9B73 Y:006D P:envMxdIzC
$83/ED45 AB          PLB                     A:007F X:9B73 Y:006D P:envMxdIzC
$83/ED46 C2 30       REP #$30                A:007F X:9B73 Y:006D P:envMxdIzC
$83/ED48 A5 02       LDA $02    [$00:0002]   A:007F X:9B73 Y:006D P:envmxdIzC ;Load current letter
$83/ED4A 29 FF 00    AND #$00FF              A:001A X:9B73 Y:006D P:envmxdIzC ;AND value
$83/ED4D 85 02       STA $02    [$00:0002]   A:001A X:9B73 Y:006D P:envmxdIzC ;Store back to 7E:0002
$83/ED4F A0 00 00    LDY #$0000              A:001A X:9B73 Y:006D P:envmxdIzC ;Set Y to 0000
$83/ED52 20 70 ED    JSR $ED70  [$83:ED70]   A:001A X:9B73 Y:0000 P:envmxdIZC ;Load 'Letter Writing' routine


$83/ED70 A5 02       LDA $02    [$00:0002]   A:001A X:9B73 Y:0000 P:envmxdIZC ;Load current letter
$83/ED72 38          SEC                     A:001A X:9B73 Y:0000 P:envmxdIzC ;Set carry flag
$83/ED73 E9 10 00    SBC #$0010              A:001A X:9B73 Y:0000 P:envmxdIzC ;Subtract 10 from accumulator
$83/ED76 85 02       STA $02    [$00:0002]   A:000A X:9B73 Y:0000 P:envmxdIzC ;Store value back to 7E:0002
$83/ED78 0A          ASL A                   A:000A X:9B73 Y:0000 P:envmxdIzC ;Double accumulator
$83/ED79 0A          ASL A                   A:0014 X:9B73 Y:0000 P:envmxdIzc ;Double accumulator
$83/ED7A 0A          ASL A                   A:0028 X:9B73 Y:0000 P:envmxdIzc ;Double accumulator
$83/ED7B 0A          ASL A                   A:0050 X:9B73 Y:0000 P:envmxdIzc ;Double accumulator
$83/ED7C 18          CLC                     A:00A0 X:9B73 Y:0000 P:envmxdIzc ;Clear carry flag
$83/ED7D 69 00 F2    ADC #$F200              A:00A0 X:9B73 Y:0000 P:envmxdIzc ;Add #$F200 current accumulator value
$83/ED80 AA          TAX                     A:F2A0 X:9B73 Y:0000 P:eNvmxdIzc ;Transfer A to X
$83/ED81 BF 00 00 81 LDA $810000,x[$81:F2A0] A:F2A0 X:F2A0 Y:0000 P:eNvmxdIzc ;Load letter graphics
$83/ED85 99 00 FF    STA $FF00,y[$7F:FF00]   A:0606 X:F2A0 Y:0000 P:envmxdIzc ;Store to 7F:FF00 (Loops until Y is 8)
$83/ED88 E8          INX                     A:0606 X:F2A0 Y:0000 P:envmxdIzc ;Increase X
$83/ED89 E8          INX                     A:0606 X:F2A1 Y:0000 P:eNvmxdIzc ;Increase X
$83/ED8A C8          INY                     A:0606 X:F2A2 Y:0000 P:eNvmxdIzc ;Increase Y
$83/ED8B C8          INY                     A:0606 X:F2A2 Y:0001 P:envmxdIzc ;Increase Y
$83/ED8C C0 08 00    CPY #$0008              A:0606 X:F2A2 Y:0002 P:envmxdIzc ;Check if Y is 08
$83/ED8F D0 F0       BNE $F0    [$ED81]      A:0606 X:F2A2 Y:0002 P:eNvmxdIzc ;If not, send back to loading letter graphics.
$83/ED91 60          RTS                     A:2626 X:F2A8 Y:0008 P:envmxdIZC


$83/ED55 20 A0 ED    JSR $EDA0  [$83:EDA0]   A:2626 X:F2A8 Y:0008 P:envmxdIZC ;Load routine to grab the width of letter


$83/EDA0 A5 02       LDA $02    [$00:0002]   A:2626 X:F2A8 Y:0008 P:envmxdIZC ;Load current letter
$83/EDA2 AA          TAX                     A:000A X:F2A8 Y:0008 P:envmxdIzC ;Transfer A to X
$83/EDA3 BF 40 EE 83 LDA $83EE40,x[$83:EE4A] A:000A X:000A Y:0008 P:envmxdIzC ;Load width of letter from table
$83/EDA7 29 FF 00    AND #$00FF              A:FF07 X:000A Y:0008 P:eNvmxdIzC ;AND
$83/EDAA 85 02       STA $02    [$00:0002]   A:0007 X:000A Y:0008 P:envmxdIzC ;Store back to 7E:0002
$83/EDAC A2 00 00    LDX #$0000              A:0007 X:000A Y:0008 P:envmxdIzC ;Set X to 0000
$83/EDAF 60          RTS                     A:0007 X:0000 Y:0008 P:envmxdIZC


$83/ED58 20 B0 ED    JSR $EDB0  [$83:EDB0]   A:0007 X:0000 Y:0008 P:envmxdIZC ;Load routine to shift/merge letters.


$83/EDB0 A0 00 00    LDY #$0000              A:0007 X:0000 Y:0008 P:envmxdIZC ;Set Y to 0000
$83/EDB3 E2 20       SEP #$20                A:0007 X:0000 Y:0000 P:envmxdIZC
$83/EDB5 AD F0 FE    LDA $FEF0  [$7F:FEF0]   A:0007 X:0000 Y:0000 P:envMxdIZC ;Load PixelOffset
$83/EDB8 F0 36       BEQ $36    [$EDF0]      A:0000 X:0000 Y:0000 P:envMxdIZC ;Go to 83:EDF0 if value is 00
$83/EDF0 BD 00 FF    LDA $FF00,x[$7F:FF00]   A:0000 X:0000 Y:0000 P:envMxdIZC ;Load Font workspace
$83/EDF3 1D 10 FF    ORA $FF10,x[$7F:FF10]   A:0006 X:0000 Y:0000 P:envMxdIzC ;OR VWF workspace
$83/EDF6 9D 10 FF    STA $FF10,x[$7F:FF10]   A:0006 X:0000 Y:0000 P:envMxdIzC ;Store to VWF workspace
$83/EDF9 E8          INX                     A:0006 X:0000 Y:0000 P:envMxdIzC ;Increase X
$83/EDFA E0 10 00    CPX #$0010              A:0006 X:0001 Y:0000 P:envMxdIzC ;Check if X is 10, if not, send back to 'Load Font workspace'
$83/EDFD D0 F1       BNE $F1    [$EDF0]      A:0006 X:0001 Y:0000 P:eNvMxdIzc
$83/EDFF A5 02       LDA $02    [$00:0002]   A:0000 X:0010 Y:0000 P:envMxdIZC ;Load width of letter
$83/EE01 18          CLC                     A:0007 X:0010 Y:0000 P:envMxdIzC ;Clear carry flag
$83/EE02 6D F0 FE    ADC $FEF0  [$7F:FEF0]   A:0007 X:0010 Y:0000 P:envMxdIzc ;Add PixelOffset to current value
$83/EE05 8D F0 FE    STA $FEF0  [$7F:FEF0]   A:0007 X:0010 Y:0000 P:envMxdIzc ;Store back to PixelOffset
$83/EE08 60          RTS                     A:0007 X:0010 Y:0000 P:envMxdIzc


$83/ED5B A9 83       LDA #$83                A:0007 X:0010 Y:0000 P:envMxdIzc ;Set bank back to #$83 after the entire routine is done
$83/ED5D 48          PHA                     A:0083 X:0010 Y:0000 P:eNvMxdIzc
$83/ED5E AB          PLB                     A:0083 X:0010 Y:0000 P:eNvMxdIzc
$83/ED5F 6B          RTL                     A:0083 X:0010 Y:0000 P:eNvMxdIzc


$83/EDBA 85 04       STA $04    [$00:0004]   A:0007 X:0000 Y:0000 P:envMxdIzC (This is when 7F:FEF0 =/= 00) ;Stores Pixeloffset to 7E:0004
$83/EDBC 64 05       STZ $05    [$00:0005]   A:0007 X:0000 Y:0000 P:envMxdIzC ;Set 7E:0005 to 00
$83/EDBE 5E 00 FF    LSR $FF00,x[$7F:FF00]   A:0007 X:0000 Y:0000 P:envMxdIzC ;LSR 7F:FF00
$83/EDC1 7E 08 FF    ROR $FF08,x[$7F:FF08]   A:0007 X:0000 Y:0000 P:envMxdIzc ;Shift right to 7F:FF08
$83/EDC4 E8          INX                     A:0007 X:0000 Y:0000 P:envMxdIZc ;Increase X
$83/EDC5 C8          INY                     A:0007 X:0001 Y:0000 P:envMxdIzc ;Increase Y
$83/EDC6 C4 04       CPY $04    [$00:0004]   A:0007 X:0001 Y:0001 P:envMxdIzc ;Check if Y is == to Pixeloffset
$83/EDC8 D0 F4       BNE $F4    [$EDBE]      A:0007 X:0001 Y:0001 P:eNvMxdIzc ;If not, send back to LSR 7F:FF00
$83/EDCA A2 00 00    LDX #$0000              A:0007 X:0007 Y:0007 P:envMxdIZC ;Set X to 0000
$83/EDCD BD 00 FF    LDA $FF00,x[$7F:FF00]   A:0007 X:0000 Y:0007 P:envMxdIZC ;Load Font workspace
$83/EDD0 1D 10 FF    ORA $FF10,x[$7F:FF10]   A:0010 X:0000 Y:0007 P:envMxdIzC ;OR with VWF workspace
$83/EDD3 9D 1F FF    STA $FF1F,x[$7F:FF1F]   A:0016 X:0000 Y:0007 P:envMxdIzC ;Store to area to be transfered
$83/EDD6 E8          INX                     A:0016 X:0000 Y:0007 P:envMxdIzC ;Increase X
$83/EDD7 E0 10 00    CPX #$0010              A:0016 X:0001 Y:0007 P:envMxdIzC ;Check if X == 10
$83/EDDA D0 F1       BNE $F1    [$EDCD]      A:0016 X:0001 Y:0007 P:eNvMxdIzc ;If not, send back to 'Load Font workspace'
$83/EDDC 80 21       BRA $21    [$EDFF]      A:0016 X:0010 Y:0007 P:envMxdIZC ;Always Branch to 83:EDFF to set PixelOffset to what it should be

Hopefully this is understandable.  This is what I have going on right now.

Edit: When it stores the letters in their areas, this is the result.
(http://i57.tinypic.com/1zlspq1.png)

When it tries merging, this is the result.
(http://i62.tinypic.com/veyo9j.png)

Pretty sure it's because the 'b' is not being shifted properly. 
Title: Re: Getting Started on a VWF?
Post by: Gemini on July 12, 2015, 02:00:04 pm
You should post some code from your VWF assembly files. That trace dump doesn't exactly make things clear.

I'll worry about making the font 2bpp after I get a grasp of understanding on this at the moment.  It's not too big of a deal right now, more-so understanding is the key.
Barely a change. You simply loop twice the height of a tile in 2 BPP. SNES formats make it simple for you, so I guess you can even easily upgrade.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 12, 2015, 02:04:08 pm
Edit: It's working fully except for the big issue now.

Whenever my PixelOffset hits 0, it stops writing anything.  I can't seem to find a way around it since it'll happen quite often :/

Edit 2: Yeah, seems the only problem I'm technically seeing is that when it hits Pixeloffset 0, it's not actually ORing it and sending it to the proper area that'd be transferred to VRAM... But if I do anything else while it's 0, it'll completely screw up the Pixeloffset resulting in nothing working properly.  I'm really struggling with this bit.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on July 23, 2015, 05:44:44 pm
Edit: SUCCESS!  I GOT IT!

I decided to scrap the entire routine I had before and write my own!  As far as I can see, it's working flawlessly! :)  All that's left is to update VRAM and the tilemap, otherwise it's good to go!  I fully wrote out Abracadabra and it stored fine, even did a sentence of 'This is a test' and it came out perfectly!  I'll post a screenshot once I have it fully ready!

Edit 2: And we're ready to go! :)  Thank you so much for the help!  It's really not that complicated actually.  The only spot that was really killing me was the shifting.  I've never ever studied that nor really seen or understood how it worked.

(http://i59.tinypic.com/syqywj.png)
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on August 02, 2015, 12:05:59 pm
Congrats! Perseverance pays off in ROM hacking. Add another skill to your bag. :)
Title: Re: Getting Started on a VWF?
Post by: justin3009 on August 02, 2015, 01:59:36 pm
As far as I can see, the VWF itself works quite well.  There's a few kinks with the tilemapping still but otherwise I think it's okay.  The big issue I had with the VWF right now is when there was a constant string of big letters that were repeated, such as 'MMMMMMMMMMMMMMMMM', it'd actually start printing half letters per tile instead of the whole like it should.  I'll have to figure out some way to work around a few of these kinks.

August 08, 2015, 12:11:05 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
One more question!  It doesn't have anything to do with the VWF itself but moreso updating the Tile Map.

How would you handle updating the Tile Map when it comes to a VWF?  The first letter of the entire sentence structure I assume always updates the tile map right away just so there's something to display on that single letter.  Then should it update only when the 8x8 is full?  Right now it's ALWAYS two blocks ahead on the tile map no matter what I do but it's at least displaying one letter at a time like it should.  If I somehow manage to not display those two blocks, it cuts off the 2nd line's two blocks and starts desynching the writing where it's trying to display cut up letters and such.

Just struggling for some reason on how to get this properly working.  I know the VWF code itself is fine, no issue there at all.  Just the tile map is giving me serious troubles.
Title: Re: Getting Started on a VWF?
Post by: Nightcrawler on August 09, 2015, 11:20:07 am
There are a number of ways a VWF renderer can be 'glued' into the game. The best approach will vary depending on how you did your rendering, and what the game engine was already doing.

In general though, if you're doing dialog, and you're doing letter by letter display, then I'd probably suggest one of the following:

1.) Map a large region of RAM for rendering that can contain an entire dialog line or even full text window. Then, the tilemap doesn't change much. It's mapped once to the full line or window. It will reflect the letter by letter rendering in VRAM automatically that way. You don't have to do anything to tilemap during rendering.

2.) If you don't have the RAM to do that, you can write the tilemap each character iteration, advancing the index only when the tilespace is full. If you're doing 8x8 for example, you'd write the current tile, and second potential spillover tile to the tilemap each time. It would write the same two indexes until your tile was full, then it would increment to the next index and write the two tiles there.

You can do any variation of the above as well. You can write to the tilemap only when the tile is full, only after x number of tiles are done etc. There are lots of ways to handle it. I usually pick what I think is the easiest way to massage into the game with the least amount of code.
Title: Re: Getting Started on a VWF?
Post by: justin3009 on August 10, 2015, 08:24:15 pm
I'm actually trying as hard as I can on #2.

I prefer to go a tile by tile basis, feels more clean to me.  I have the RAM space in this game no problem but I don't want to force that on every other game.  I'd rather try to conserve as much space as possible and learn from that so I can apply it to other games that may have less.

#2 actually works quite well so far but it's not quite going as hoped for.

The output of the text overall is exactly right...but it's not updating the tilemap quick enough which causes the letters to appear in halves sometimes.  The whole tilemap is fully and properly written but I can't figure out how to update it properly.  It seems if I try adding anything else, either it writes too much tilemap updating, or it doesn't update enough.  It's always in a weird state of flux ;/  I'm really struggling with this.
Title: Re: Getting Started on a VWF?
Post by: cclh12 on September 06, 2015, 02:33:13 pm
Hello,

I figured asking for advise here instead of making a new thread would be the better option.

I am trying to write the hack that is the bane of all translations projects.  A variable width font. I cannot seem to find information on how it's done on PSX. The information I have read on the forum seems to strongly lean towards SNES and GBA. However, correct me if I'm wrong, isn't the process different since PSX deals with pixels instead of tiles? Could someone kind of 'break down' the process of how you go about doing it? For instance, on the game I'm working with, all characters are printed with the same width apart. Where in the world do I put a breakpoint to find the code responsible for that?

I have already managed to rewrite some of the routines in this game.
For some reason, it counts the Japanese text before its printed to screen but couldn't count ASCII characters. Although I'm not sure why... I rewrote that.
I also made the game accept 1-byte ASCII instead of 2-byte characters. But this variable width font is driving me nuts.  :banghead:


Hopefully I can follow justin3009 and be successful.
Title: Re: Getting Started on a VWF?
Post by: Gemini on September 06, 2015, 04:09:01 pm
There are several ways to hack a proportional font on the PSX, but it depends on the game and how it displays text. If it's a simple font already cached in VRAM and sprites to represent each character, then you find how it increments horizontal spacing and you're good to go. A similar case appears when the game caches text glyphs on demand and renders as individual sprites; again, you need to change the incremental spacing to be proportional and possibly hack in a static font rather than cache on demand. A final case is when a game uses a canvas to draw text as strips of sprites, like Xenogears or Castlevania: SOTN; there you gotta use an approach similar to what you'd have on tile-based consoles, so you do all the shifting and oring, upload, and let the game do the rest.
Title: Re: Getting Started on a VWF?
Post by: cclh12 on September 06, 2015, 04:51:50 pm
A similar case appears when the game caches text glyphs on demand and renders as individual sprites

Yes, this is my case exactly.

(http://puu.sh/k2gWQ.PNG)

On screen, this is what is displayed.
Code: [Select]
ABCDEFGHIJKLMNO
abcdefghijklmno
Except this massive spacing between the letters.

EDIT: Can anyone tell me if this font is the PSX's internal BIOS font? It sure does look like it to me...



you need to change the incremental spacing to be proportional and possibly hack in a static font rather than cache on demand.
It's the part of finding the code responsible for the spacing that is making this difficult for me.
I don't know where to start to find it. It could be either hardcoded or have data in a file controlling each characters spacing. (which I doubt for this case, since they all use the same spacing.)
Is there a place I should put a breakpoint that (in most cases) should take me to the code responsible for it? If so, where?

As of right now, I can't see why having the full font loaded into VRAM would be beneficial to this. Maybe I will find out as I investigate more. Could you explain the benefit of having it always in VRAM as oppose to having just what is currently needed?


EDIT: So, I have made some slight progress.
Unmodified
(http://puu.sh/k2Ow8.PNG)

Modified
(http://puu.sh/k2R8G.PNG)

Pretty sure I just nailed it...
Granted, it could be adjusted better. I just need to replicate it for every character...
Title: Re: Getting Started on a VWF?
Post by: Gemini on September 07, 2015, 11:20:28 am
EDIT: Can anyone tell me if this font is the PSX's internal BIOS font? It sure does look like it to me...
It looks like it to me.

Quote
It's the part of finding the code responsible for the spacing that is making this difficult for me.
I don't know where to start to find it. It could be either hardcoded or have data in a file controlling each characters spacing. (which I doubt for this case, since they all use the same spacing.)
Is there a place I should put a breakpoint that (in most cases) should take me to the code responsible for it? If so, where?
Usually you monitor primitives via pSX's debugger and GPU capture, find a text sprite primitive, and add a write breakpoint to its xy coordinates. Unless the game uses an abstraction layer such as libgs, that should give you the whereabouts of text sprite fillers and somewhere close by the spacing line.

Quote
As of right now, I can't see why having the full font loaded into VRAM would be beneficial to this. Maybe I will find out as I investigate more. Could you explain the benefit of having it always in VRAM as oppose to having just what is currently needed?
Using a precached font is the way to go with any English translation for three reasons:
1) you don't need to have the full font always stored in RAM ready for upload and you can reserve that RAM chunk for your extra code (unless it's done via the BIOS, but in that case you can strip those functions instead of the non-existing font);
2) you don't need to upscale the font from 1/2 BPP to 4 BPP or higher, which can be a mess sometimes;
3) caching imposes some limitations as to how many text sprites you can have at once on screen.
Title: Re: Getting Started on a VWF?
Post by: cclh12 on September 08, 2015, 12:20:10 am
Thanks for the help Gemini. I found the code I need to modify.

Right now I kinda have a Fixed Width Font effect going on.
It's still pretty ugly, but better is better.

Original
(http://puu.sh/k3QaK.PNG)


Modified
(http://puu.sh/k3Qao.PNG)


I should easily be able to adapt this into a Variable Width Font now. If I don't jinx myself, that is.  ;)
Right now, I see this being the only way I can think of coding it.

Code: [Select]
if((CurrentPrintedLetter == 'A') & (NextLetterToBePrinted == 'B'))
{

// Customize the 'B' coordinates to make it squeeze in close next to 'A'

}

Needless to say, this will get long very fast. I would have to make the game change how it will print each letter (and number) depending on which letter or number follows it.
Is this how most people code it? It feels kinda inefficient, but it is also the only way I can think of how to code it.
Title: Re: Getting Started on a VWF?
Post by: Gemini on September 08, 2015, 02:40:30 am
Make a table of nibbles, lower for width and higher for left adjustment. Use adjustment to move the sprite to the left (Sprt.x=x-adjust), width to increase global x when you're done adding a sprite (x+=width).
Title: Re: Getting Started on a VWF?
Post by: cclh12 on September 10, 2015, 07:32:38 pm
Got it fully working.  :beer:
Now I just need to fix this "18 characters per line" rule the game has. Which will be simple.
Thanks for the advice Gemini.

(http://puu.sh/k6Y8a.PNG)
Title: Re: Getting Started on a VWF?
Post by: obscurumlux01 on September 10, 2015, 11:26:49 pm
Gemini, you are fantastic with the assistance.  I'm learning a ton about how difficult a VWF is just from the info you posted!

We seriously need a 'kudos' or 'like' button on posts.  ^_^