News:

11 March 2016 - Forum Rules

Main Menu

Getting Started on a VWF?

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

Previous topic - Next topic

tryphon

I never made SNES hacking but I've been told that, precisely, its cpu wasn't exactly a 16 bits one :)

justin3009

Now I'm even more confused  :(
'We have to find some way to incorporate the general civilians in the plot.'

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

tryphon

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

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

BlackDog61

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

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

BlackDog61

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

henke37

Except that some tricky characters are supposed to overwrite others.

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

Gemini

If anything, you could write some simple PC program to shift SNES tiles around and see the result with an editor.

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

Normmatt


KingMike

#112
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".
"My watch says 30 chickens" Google, 2018

justin3009

#113
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?
'We have to find some way to incorporate the general civilians in the plot.'

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

Gemini

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

Nightcrawler

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.
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

KingMike

#117
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.
"My watch says 30 chickens" Google, 2018

justin3009

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.
'We have to find some way to incorporate the general civilians in the plot.'

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

Gemini

Quote from: KingMike on July 11, 2015, 03:39:03 PMI 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.