Help wanted with 8×8 VWF algorithm

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Help wanted with 8×8 VWF algorithm
by on (#149882)
So I've been trying and trying to implement a VWF for the dialogue in Furry RPG, but without success so far. :(

Image

Note that I spent the last two weeks studying VWF source examples on RHDN (including this one) -- most of which are a pain to even read, or simply incomplete. Also, I stumbled across Stealth Translation's doc, and couldn't help but notice that it too is more than incomplete. Also, I looked at both tepples' Action menu and bisqwit's Chronotools 8×8 VWF engine, both of which only managed to confuse me even more. :?

Please note that the bit-shifting apparently works correctly -- the left half of the "2" appears shifted to the right just fine (albeit on the wrong tile), whereas the right half appears unnecessarily shifted, and shows up as garbage in an unwanted place. :|

Here's the code I came up with after studying all those other documents. Code executes during Vblank, variables starting with DP_ are direct page, vars starting with ARRAY_ are in the range of $0200-$1FFF (minus stack pointer) in WRAM:

Code:
ProcessVWFTiles:
   A16

   lda DP_TextASCIIChar         ; ASCII char no. --> font tile no.
   asl a               ; value * 16 as 1 font tile = 16 bytes
   asl a
   asl a
   asl a
   tax

   A8

   lda DP_VWFBitsRemaining
   and #$07
   sta DP_VWFBitsRemaining
   bne __UseOldVWFTile

   A16

   lda DP_VWFTileNew         ; new tile no. --> VWF buffer index
   bra +

__UseOldVWFTile:
   A16

   lda DP_VWFTileOld         ; old tile no. --> VWF buffer index
+   asl a
   asl a
   asl a
   asl a
   tay

   A8

   lda #16               ; loop through 16 bytes per tile
   sta DP_VWFLoop

-   lda.l GFX_FontMode5, x
   xba               ; move to high byte

   lda #$00

   jsr __VWFShiftBits         ; shift tile data if necessary

   ora ARRAY_VWFTileBuffer1+1, y
   sta ARRAY_VWFTileBuffer1+1, y

   xba

   ora ARRAY_VWFTileBuffer1, y
   sta ARRAY_VWFTileBuffer1, y

   iny
   inx

   dec DP_VWFLoop
   bne -

   ldx DP_TextASCIIChar         ; ASCII char no. --> font width table index

   lda DP_VWFBitsRemaining         ; adjust pixels remaining for shifting
   bne +

   inc DP_VWFTileOld
   inc DP_VWFTileNew
   inc DP_VWFTileNew
   lda #8               ; 8 = max. no. of bits

+   sec
   sbc.l SRC_FWTDialogue, x
   bpl +
   
   eor #$FF            ; handle overflow
   inc a
   sta DP_VWFBitsRemaining

   inc DP_VWFTileOld
   inc DP_VWFTileNew
   inc DP_VWFTileNew

   lda #8
   sec
   sbc DP_VWFBitsRemaining

+   sta DP_VWFBitsRemaining

rts
   

   
__VWFShiftBits:
   phx
   
   A16

   pha

   lda DP_VWFBitsRemaining
   bne +

   pla

   bra __VWFShiftBitsDone

+   dec a
   asl a
   tax

   pla

   jmp (__VWFShiftAmount, x)



__VWFShiftAmount:
   .DW _R1, _R2, _R3, _R4, _R5, _R6, _R7

_R1:
   lsr a

_R2:
   lsr a

_R3:
   lsr a

_R4:
   lsr a

_R5:
   lsr a

_R6:
   lsr a

_R7:
   lsr a



__VWFShiftBitsDone:

   A8

   plx
rts

Download:
http://manuloewe.de/snestuff/projects/furryrpg_build_00224.7z

Any substantial help is very much appreciated. Thanks! :)
Ramsis
Re: Help wanted with 8×8 VWF algorithm
by on (#149885)
I'm getting the impression the problem is calculating which byte to write into (note how the right half of the digits is shifted down by 1 pixel as well).

Also consider testing with letters, numbers are probably the one thing you want to keep fixed width (yes, this means extra spacing around the 1).
Re: Help wanted with 8×8 VWF algorithm
by on (#149886)
<tangent> Bring back text figures! (It turns out that monospaced numerals are a modern invention, to accommodate computers not needing to know the difference between tabular data and mid-text data)
Re: Help wanted with 8×8 VWF algorithm
by on (#149888)
It's more to do with the fact that if you have variable-width digits then use that font in a counter, the width of the number will go all over the place as the number changes - especially annoying when the value is changing constantly like with timers and such.
Re: Help wanted with 8×8 VWF algorithm
by on (#149889)
What's the first thing that confuses you about the VWF engine in the Action 53 menu? I'm willing to document everything more thoroughly.

Agreed about digit width, which is why the font shipped with my own VWF engine leaves an extra pixel of space on the sides of the glyph for '1'.
Attachment:
File comment: See the extra pixel of space on left and right sides of '1' glyph
vwf7_digits.png
vwf7_digits.png [ 462 Bytes | Viewed 4485 times ]


In any case, text figures (digit glyphs with descenders) and a narrow advance width for '1' are orthogonal, meaning each can be used without the other. Here are some fixed-width text figures that I designed for another project.
Attachment:
File comment: See descenders on '3', '4', '5', '7', and '9' and ascenders only on '6' and '8'
text_figures.png
text_figures.png [ 636 Bytes | Viewed 4487 times ]
Re: Help wanted with 8×8 VWF algorithm
by on (#149893)
That ascent/descent is very subtle, tepples.
Sik wrote:
It's more to do with the fact that if you have variable-width digits then use that font in a counter, the width of the number will go all over the place as the number changes - especially annoying when the value is changing constantly like with timers and such.

This is alleviated somewhat when the number is justified to the most-significant digit rather than the least...but still a problem. (And if you do that, then you get a confusing change when a digit is added, if you weren't using leading zeros.)
Re: Help wanted with 8×8 VWF algorithm
by on (#149914)
Sik wrote:
I'm getting the impression the problem is calculating which byte to write into (note how the right half of the digits is shifted down by 1 pixel as well).

Thanks. Indeed, I'm not quite sure if I'm getting the correct Y index value at all. And since I don't really know what to take into account for that, I can only hope someone will point me in the right direction. :)

Sik wrote:
Also consider testing with letters, numbers are probably the one thing you want to keep fixed width (yes, this means extra spacing around the 1).

The dialogue, where numbers barely ever appear anyway, will be an all-VWF. The menu, on the other hand, will employ fixed-width fonts for numbers etc., and possibly a VWF for descriptions and such.

tepples wrote:
What's the first thing that confuses you about the VWF engine in the Action 53 menu?

Nothing in particular, really. I've just been a bit frustrated about all that time spent on staring at other peoples' code examples without ever fully grasping the essence of how and why those work. :?
Re: Help wanted with 8×8 VWF algorithm
by on (#149915)
Ramsis wrote:
tepples wrote:
What's the first thing that confuses you about the VWF engine in the Action 53 menu?

Nothing in particular, really. I've just been a bit frustrated about all that time spent on staring at other peoples' code examples without ever fully grasping the essence of how and why those work. :?

Do you use IRC or AIM or Skype or Hangouts? I'm willing to explain how it works in real time text chat.
Re: Help wanted with 8×8 VWF algorithm
by on (#149932)
Today's progress:

Image

I rewrote/simplified the routine quite significantly, which now looks like this:

Code:
ProcessVWFTiles:
   A16

   lda DP_TextASCIIChar         ; ASCII char no. --> font tile no.
   asl a               ; value * 16 as 1 font tile = 16 bytes
   asl a
   asl a
   asl a
   tax

   A8

   ldy DP_VWFBufferIndex

   lda #16               ; loop through 16 bytes per tile
   sta DP_VWFLoop

-   lda.l GFX_FontMode5, x
   xba               ; move to high byte

   lda #$00

   jsr __VWFShiftBits         ; shift tile data if necessary

   A16

   xba

   ora ARRAY_VWFTileBuffer1, y
   sta ARRAY_VWFTileBuffer1, y

   A8

   iny
   inx

   dec DP_VWFLoop
   bne -

   ldx DP_TextASCIIChar         ; ASCII char no. --> font width table index

   lda.l SRC_FWTDialogue, x
   clc
   adc DP_VWFBitsUsed
   cmp #8
   bcs +
   sta DP_VWFBitsUsed

   A16

   tya
   sec
   sbc #16
   sta DP_VWFBufferIndex

   A8

   bra ++

+   sec
   sbc #8
   sta DP_VWFBitsUsed
   sty DP_VWFBufferIndex
++
rts



__VWFShiftBits:
   phx
   phy

   A16

   pha

   lda DP_VWFBitsUsed
   bne +
   
   pla

   bra __VWFShiftBitsDone

+   tay

   pla

-   lsr a
   dey
   bne -

__VWFShiftBitsDone:

   A8

   ply
   plx
rts


Still, when characters have a width of other than 8 or 4 pixels, it freaks out (this should read "bc", both of which are 7-pixel-wide characters):

Image

Anyone spot the error in my code? Please? :lol:

tepples wrote:
Do you use IRC or AIM or Skype or Hangouts? I'm willing to explain how it works in real time text chat.

Thanks, I might actually come back to you some time. :)
Re: Help wanted with 8×8 VWF algorithm
by on (#149950)
When you are building your proportional text string in RAM, you need to store the other half of the tiledata that shifts off of your original tile.

Let's say you are drawing 'bc', and each is six pixels long.

The first one is easy, it fits cleanly onto one tile. But the second one splits two pixels of 'c' onto the first tile, and four onto the next tile.

The way to do this is to use a 16-bit accumulator and xba.

Keep a bit-position for where you are at on the screen. This value lsr #3 (divided by 8) is the tile# you are on, and this value and #7 (low three bits) is the bit position on said tile.

In our case with 'bc', you've drawn 'b', so now you're on tile# 0, bit position #6.

Load up a horizontal line of 'c', and #$ff, and now use xba on it.

Thus we go from:
jjjjjjjj cccccc00 (j = junk, c = c, 0 = padding)
and #$ff
00000000 cccccc00
xba
cccccc00 00000000

Now remember our tile/bit position and #7 is 6. So we right shift A six times (lsr #6)

lsr #6
000000cc cccc0000

Or the way I like to do it:
pha; lda bitpos; and #7; tax; pla ;get the bitpos into X
-; beq +; lsr; dex; bra -; + ;shift right and decrement X until zero

(you can get this faster with a jmp (table,x) into a block of lsr's, but this is for demonstration.)

We first need to OR the upper 8-bits with the existing tile# 0 in RAM, and then store the remaining four bits of 'c' into the next tile. This usually goes something like this:

xba
sep #$20
ora tiledata,x
sta tiledata,x
xba
sta tiledata+16,x ;16 for 2bpp tiles
inx #2 ;one horizontal line
<repeat for all lines>

(the above can be optimized by doing it in the reverse order, this is for demonstration though.)

Now when you're done, add the length of 'c' (6) to your tile/bit-pos. It was 6 from 'b', now we add 6 from 'c' and it's 12. Or tile#1, bit-position #4. And repeat for the rest of the string.

When you're done building your string, the total # of tiles you need has to be incremented by one if bitpos&7 != 0. Say you only drew 'bc', since we're at 12, we have -two- tiles we need to transfer data for, and two tilemap entries need to be valid for that.

Simple method:
lda bitpos
clc; adc #7
lsr #3

Have fun ;)
Re: Help wanted with 8×8 VWF algorithm
by on (#149988)
1000 kudos to you, byuu. ^^ That 16 for 2bpp tiles clue of yours helped me make my algorithm work almost instantly. :D :D :D

Of course, it still took a lot more changes to my text engine, as well as an all-new buffer management/VRAM transfer routine, in order to get the desired result.

Which currently looks like this:

Image

To do:
  • move the buffer-building routine to the active display period (this should avoid gfx glitches)
  • rework carriage returns / maybe even implement automatic line-wrapping?!
  • track down and fix all buffer-related bugs (of which there are many :P )

Download:
http://manuloewe.de/snestuff/projects/furryrpg_build_00226.7z
(Please be warned -- this build is buggy!)
Re: Help wanted with 8×8 VWF algorithm
by on (#149995)
Now nitpicking on the font: how does it look on TV? (or at least with a NTSC filter) Because I have the feeling that font must be awful to read since it's so thin.
Re: Help wanted with 8×8 VWF algorithm
by on (#150001)
Sik wrote:
Now nitpicking on the font: how does it look on TV? (or at least with a NTSC filter) Because I have the feeling that font must be awful to read since it's so thin.

Rest assured that FURRY RPG will be designed with modern 40"+ TV sets in mind -- though not with all-anamorph tiles for 16:9, despite this actually being a short-listed (i.e., early on discarded) design question. :wink:
Re: Help wanted with 8×8 VWF algorithm
by on (#150006)
I was talking about the SDTV ones =S (i.e. the ones the SNES was originally intended for... maybe over composite instead of RF though)
Re: Help wanted with 8×8 VWF algorithm
by on (#150022)
Plenty of SDTVs take an S-Video signal. I may take a photo of S-Video displayed on an SDTV tonight.
Re: Help wanted with 8×8 VWF algorithm
by on (#150024)
Cool, happy to see you got it working :D

> I was talking about the SDTV ones

I was going to mention it, but I kind of assumed his target audience were people with PC monitors or HDTVs, given the character portrait is at the very bottom-left edge and would be heavily clipped by overscan if he were concerned with SDTV users.

I don't think it's objectionable to write an SNES game with modern displays in mind. The real SNES can display just fine on them, so you aren't even cheating the SNES itself. Might as well use a nice font. Just be sure to let people know not to run it on their classic CRT setups.
Re: Help wanted with 8×8 VWF algorithm
by on (#150025)
In 256x224 mode, there's not nearly as much clipping as there is on an NES.
Re: Help wanted with 8×8 VWF algorithm
by on (#150029)
tepples wrote:
Plenty of SDTVs take an S-Video signal. I may take a photo of S-Video displayed on an SDTV tonight.

Not everywhere. In Argentina we just jumped from composite straight to HDMI, for example. If somebody has a CRT you simply can't assume anything higher than composite (even if TVs that support better do exist).
Re: Help wanted with 8×8 VWF algorithm
by on (#150093)
As an SDTV user myself, I hope to combine the best of both worlds in the end. It should be obvious that important information will never appear in screen areas prone to being clipped. :wink:

As for the font itself, please keep in mind that there is still no graphics artist involved in the project. So basically, everything you see (yes, including the fonts) is placeholder artwork. If the dialog font appears too "thin" to you, you're out of luck though -- hi-res mode is a feature of my text engine, not a bug. :P

Concerning low-quality/obsolete SNES-TV hookups: There won't be any concessions made to the graphical design. Sorry, but c'est la vie. Buy yourself a newer TV set and an RGB-to-whatever converter, or use higan. :)

N.B. Any further project-related questions are best posted in this thread. Thanks!