From d2d6d4460b3db9e3ce5b899fa6228cefa4050c06 Mon Sep 17 00:00:00 2001 From: RPG Hacker Date: Wed, 13 Dec 2023 09:57:04 +0100 Subject: [PATCH] Text box animation now only DMA's enough tiles to VRAM to cover the visible area of the text box (reducing V-Blank time) --- docs/vwf/manual/index.xhtml | 1 + .../vwf_dialogues/data/smw/data/vwfconfig.cfg | 4 +- .../data/testing/data/vwfmessages.asm | 248 ++++++++++++++++-- patches/vwf_dialogues/vwf_dialogues.asm | 160 ++++++++++- 4 files changed, 380 insertions(+), 33 deletions(-) diff --git a/docs/vwf/manual/index.xhtml b/docs/vwf/manual/index.xhtml index a0139e1..c393188 100644 --- a/docs/vwf/manual/index.xhtml +++ b/docs/vwf/manual/index.xhtml @@ -2451,6 +2451,7 @@ endif
  • Optimized performance of patch in V-Blank to reduce the chance of graphical bugs occurring from the interaction with other patches.
  • Optimized performance of some VWF core functionality, including text generation.
  • Added new !vwf_backup_duration_in_frames setting, which allows reducing the patch's V-Blank duration in the initialization step at the cost of longer start-up times for text boxes.
  • +
  • Reduced the amount of time the patch spends in V-Blank for smaller text boxes during the text box animation phase. This is achieved by only copying enough tiles to VRAM to cover the visible area of the text box (previous versions always copied an entire screen worth of tiles).
  • diff --git a/patches/vwf_dialogues/data/smw/data/vwfconfig.cfg b/patches/vwf_dialogues/data/smw/data/vwfconfig.cfg index c7d8bb6..9589045 100644 --- a/patches/vwf_dialogues/data/smw/data/vwfconfig.cfg +++ b/patches/vwf_dialogues/data/smw/data/vwfconfig.cfg @@ -4,11 +4,11 @@ ; These have to be long (24-Bit) addresses! -!vwf_var_ram ?= $702000 ; 947 bytes at default settings +!vwf_var_ram ?= $702000 ; 951 bytes at default settings !vwf_backup_ram ?= $730000 ; 16 KiB to backup L3 graphics and tilemap !vwf_gfx_ram ?= $734000 ; ~3 KB for VWF graphics and tilemap -!vwf_var_ram_sa1 ?= $40C000 ; 947 bytes at default settings +!vwf_var_ram_sa1 ?= $40C000 ; 951 bytes at default settings !vwf_backup_ram_sa1 ?= $410000 ; 16 KiB to backup L3 graphics and tilemap !vwf_gfx_ram_sa1 ?= $414000 ; ~3 KB for VWF graphics and tilemap !vwf_palette_backup_ram_sa1 ?= $400703 ; 64 bytes to back up parts of the palette that get overwritten diff --git a/patches/vwf_dialogues/data/testing/data/vwfmessages.asm b/patches/vwf_dialogues/data/testing/data/vwfmessages.asm index 6ed93fc..20b3367 100644 --- a/patches/vwf_dialogues/data/testing/data/vwfmessages.asm +++ b/patches/vwf_dialogues/data/testing/data/vwfmessages.asm @@ -39,6 +39,22 @@ %vwf_register_text_macro("CurrentPlayerWithPowerup", !macro_group("PlayerPowerup", remap_ram($7E0019)), !nbsp, !macro("CurrentPlayer")) +%vwf_register_text_macro("No", !str("NO") ) +%vwf_register_text_macro("Yes", !str("YES") ) + +%vwf_start_text_macro_group("NoYes") + %vwf_add_text_macro_to_group("No") + %vwf_add_text_macro_to_group("Yes") +%vwf_end_text_macro_group() + + +; RPG Hacker: This is just for testing purposes. Don't use %vwf_claim_varram() in your actual hacks. Use proper free RAM instead. +%vwf_claim_varram(box_anim_test_show_open_old, 1) +%vwf_claim_varram(box_anim_test_show_close_old, 1) +%vwf_claim_varram(box_anim_test_show_open, 1) +%vwf_claim_varram(box_anim_test_show_close, 1) + + ; Messages: ; RPG Hacker: Really, message $0050 (Yoshi's House) is the most important one for us, since it's the quickest one to get to. @@ -76,7 +92,7 @@ endif %vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Routines Test") ), %vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Error Handling Test") ), %vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Edge Cases") ), - !str("Reserved"), + %vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Message Box Anims") ), !str("Reserved"), !str("Reserved"), !str("Exit")) @@ -247,25 +263,28 @@ endif !open_message(0060) !opt_loc(TestSelection, 7) - !str("The following boxes of text should all stay the same color:") : !press_a : !clear - !set_color($06, rgb_15(31, 0, 0)) - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - !reset_color - !press_a : !clear - - !execute(.GiveReserveMushroom) - !str("I just put a mushroom into your reserve item box.") : !new_line : !new_line - !str("It should be hidden while this dialog box remains open.") - !press_a + !str("The following boxes of text should all stay the same color:") : !press_a : !clear + !set_color($06, rgb_15(31, 0, 0)) + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !str("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") + !reset_color + !press_a : !clear + + !execute(.GiveReserveMushroom) + !str("I just put a mushroom into your reserve item box.") : !new_line : !new_line + !str("It should be hidden while this dialog box remains open.") + !press_a + + !open_message(0045) - !open_message(0045) + !opt_loc(TestSelection, 8) + !execute(MessageBoxAnimTestInit) + !open_message(0080, false, false) - !opt_loc(TestSelection, 8) !opt_loc(TestSelection, 9) !opt_loc(TestSelection, 10) !opt_loc(TestSelection, 11) @@ -2212,15 +2231,184 @@ BufferOverflowTest: %vwf_message_start(0080) ; Message 11C-1 - ; Message header & text go here + %vwf_header(x_pos(0), y_pos(0), width(15), height(13), text_alignment(TextAlignment.Centered), box_animation(BoxAnimation.Instant)) + +.Start + !clear + + !options(MessageBoxAnimSelection, + %vwf_wrap( !str("Show Open (current): "), !macro_group("NoYes", !vwf_box_anim_test_show_open_old)), + %vwf_wrap( !str("Show Close (current): "), !macro_group("NoYes", !vwf_box_anim_test_show_close_old)), + %vwf_wrap( !str("Show Open (next): "), !macro_group("NoYes", !vwf_box_anim_test_show_open)), + %vwf_wrap( !str("Show Close (next): "), !macro_group("NoYes", !vwf_box_anim_test_show_close)), + !str(""), + !str("None"), + !str("SoE"), + !str("SoM"), + !str("MMZ"), + !str("Instant"), + !str(""), + !str("Exit")) + + !opt_loc(MessageBoxAnimSelection, 0) + !execute(.ToggleShowOpenOld) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 1) + !execute(.ToggleShowCloseOld) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 2) + !execute(.ToggleShowOpen) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 3) + !execute(.ToggleShowClose) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 4) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 5) + !execute(.SetupMessageBoxAnimTest_None) + !clear + !macro_buf(0) + !opt_loc(MessageBoxAnimSelection, 6) + !execute(.SetupMessageBoxAnimTest_SoE) + !clear + !macro_buf(0) + !opt_loc(MessageBoxAnimSelection, 7) + !execute(.SetupMessageBoxAnimTest_SoM) + !clear + !macro_buf(0) + !opt_loc(MessageBoxAnimSelection, 8) + !execute(.SetupMessageBoxAnimTest_MMZ) + !clear + !macro_buf(0) + !opt_loc(MessageBoxAnimSelection, 9) + !execute(.SetupMessageBoxAnimTest_Instant) + !clear + !macro_buf(0) + + !opt_loc(MessageBoxAnimSelection, 10) + !jump(.Start) + + !opt_loc(MessageBoxAnimSelection, 11) + !open_message(0050) %vwf_message_end() +.ToggleShowOpenOld: + lda !vwf_box_anim_test_show_open_old + eor.b #$01 + sta !vwf_box_anim_test_show_open_old + rtl + +.ToggleShowCloseOld: + lda !vwf_box_anim_test_show_close_old + eor.b #$01 + sta !vwf_box_anim_test_show_close_old + rtl + +.ToggleShowOpen: + lda !vwf_box_anim_test_show_open + eor.b #$01 + sta !vwf_box_anim_test_show_open + rtl + +.ToggleShowClose: + lda !vwf_box_anim_test_show_close + eor.b #$01 + sta !vwf_box_anim_test_show_close + rtl + +.SetupMessageBoxAnimTest + !vwf_test_message_id_base = $0081 + +..None + lda.b #!vwf_test_message_id_base+$00 + pha + bra ..CreateMacro + +..SoE + lda.b #!vwf_test_message_id_base+$01 + pha + bra ..CreateMacro + +..SoM + lda.b #!vwf_test_message_id_base+$02 + pha + bra ..CreateMacro + +..MMZ + lda.b #!vwf_test_message_id_base+$03 + pha + bra ..CreateMacro + +..Instant + lda.b #!vwf_test_message_id_base+$04 + pha + +..CreateMacro + jsl VWF_ResetBufferedTextMacros + + + jsl VWF_BeginBufferedTextMacro + %add_to_buffered_text_macro(..RawCommand1) + jsl VWF_EndBufferedTextMacro + + ; This modifies the arguments of the buffered !open_message() command. + lda !vwf_tm_buffers_text_index + dec #4 + tax + pla + sta !vwf_tm_buffers_text_buffer,x + inx #2 + + lda !vwf_box_anim_test_show_close_old + asl + ora !vwf_box_anim_test_show_open + sta !vwf_tm_buffers_text_buffer,x + + + jsl VWF_BeginBufferedTextMacro + %add_to_buffered_text_macro(..RawCommand2) + jsl VWF_EndBufferedTextMacro + + ; Same as above + lda !vwf_tm_buffers_text_index + dec #2 + tax + + lda !vwf_box_anim_test_show_close + asl + ora !vwf_box_anim_test_show_open_old + sta !vwf_tm_buffers_text_buffer,x + + rtl + +..RawCommand1: + %vwf_inline(!open_message(0000, true, true)) + +..RawCommand2: + %vwf_inline(!open_message(0080, true, true)) + +MessageBoxAnimTestInit: + lda.b #$00 + sta !vwf_box_anim_test_show_open_old + sta !vwf_box_anim_test_show_close_old + sta !vwf_box_anim_test_show_open + sta !vwf_box_anim_test_show_close + rtl + ;------------------------------------------------------- %vwf_message_start(0081) ; Message 11C-2 - ; Message header & text go here + %vwf_header(box_animation(BoxAnimation.None)) + + !str("Test") : !press_a + !macro_buf(1) %vwf_message_end() @@ -2228,7 +2416,10 @@ BufferOverflowTest: %vwf_message_start(0082) ; Message 11D-1 - ; Message header & text go here + %vwf_header(box_animation(BoxAnimation.SoE)) + + !str("Test") : !press_a + !macro_buf(1) %vwf_message_end() @@ -2236,7 +2427,10 @@ BufferOverflowTest: %vwf_message_start(0083) ; Message 11D-2 - ; Message header & text go here + %vwf_header(box_animation(BoxAnimation.SoM)) + + !str("Test") : !press_a + !macro_buf(1) %vwf_message_end() @@ -2244,7 +2438,10 @@ BufferOverflowTest: %vwf_message_start(0084) ; Message 11E-1 - ; Message header & text go here + %vwf_header(box_animation(BoxAnimation.MMZ)) + + !str("Test") : !press_a + !macro_buf(1) %vwf_message_end() @@ -2252,7 +2449,10 @@ BufferOverflowTest: %vwf_message_start(0085) ; Message 11E-2 - ; Message header & text go here + %vwf_header(box_animation(BoxAnimation.Instant)) + + !str("Test") : !press_a + !macro_buf(1) %vwf_message_end() diff --git a/patches/vwf_dialogues/vwf_dialogues.asm b/patches/vwf_dialogues/vwf_dialogues.asm index 61129b8..7fd501d 100644 --- a/patches/vwf_dialogues/vwf_dialogues.asm +++ b/patches/vwf_dialogues/vwf_dialogues.asm @@ -179,6 +179,9 @@ endmacro %vwf_claim_varram(tm_buffers_text_pointers, !vwf_num_reserved_text_macros*3) ; 24-bit pointer table for the buffered text macros. %vwf_claim_varram(tm_buffers_text_buffer, !vwf_buffered_text_macro_buffer_size) ; Buffer dedicated for uploading VWF text to in order to display variable text. +%vwf_claim_varram(create_window_start_pos, 2) ; Start position and length for CreateWindow DMA +%vwf_claim_varram(create_window_length, 2) + !vwf_buffer_empty_tile = !vwf_gfx_ram !vwf_buffer_bg_tile = !vwf_gfx_ram+$10 !vwf_buffer_frame = !vwf_gfx_ram+$20 @@ -1273,6 +1276,46 @@ ClearScreen: plb rts + + + + +; Calculates the start position and number of bytes to copy for the DMA in CreateWindow. +; This is mainly an optimization to use up less V-Blank time for smaller text boxes. +; Write the starting line number (Y position) to $7E0001 and the number of lines to draw +; to $7E0005. +SetWindowCopyArea: + ; First, we calculate the starting line. + stz $00 + lda.b #$01 + sta $02 + jsr GetTilemapPos + + lda $03 + sta !vwf_create_window_start_pos + lda $04 + sta !vwf_create_window_start_pos+1 + + ; Then we calculate the number of bytes we need to copy. + ; For this, we need to multiply the text box height with #$40 (64 in dec). + ; Since that's exactly 2^6, we can just ASL six times. + ; It's still quicker than an actual multiplication. + lda.b #$00 + xba + lda $05 + rep #$20 + + ; Sizes of 0 are bad, so make sure we calculate at last one line. + bne .NotZero + inc + +.NotZero + asl #6 + + sta !vwf_create_window_length + sep #$20 + + rts @@ -1304,6 +1347,30 @@ BufferWindow: dw .NoBox,.SoEBox,.SoMBox,.MMZBox,.InstBox .End + lda !vwf_current_y + bpl .NoUnderflow + lda.b #$00 + +.NoUnderflow + sta $01 + lda !vwf_current_height + inc #2 + sta $05 + + clc + adc $01 + + cmp.b #28+1 + bcc .NoOverflow + + lda.b #28 + sec + sbc $01 + sta $05 + +.NoOverflow + jsr SetWindowCopyArea + jmp Buffer_End @@ -1807,7 +1874,43 @@ CollapseWindow: .Routinetable dw .NoBox,.SoEBox,.SoMBox,.MMZBox,.InstBox -.End +.End + ; Since we're shrinking the text box, we might have to copy more tiles than the + ; actual text box size. That's what we use .AdditionalLineCopyTable for. + lda !vwf_box_create + asl + tax + + lda !vwf_current_y + sec + sbc .AdditionalLineCopyTable,x + ; inc + bpl .NoUnderflow + lda.b #$00 + +.NoUnderflow + sta $01 + + lda !vwf_current_height + clc + adc .AdditionalLineCopyTable+1,x + inc #2 + sta $05 + + clc + adc $01 + + cmp.b #28+1 + bcc .NoOverflow + + lda.b #28 + sec + sbc $01 + sta $05 + +.NoOverflow + jsr SetWindowCopyArea + lda !vwf_counter cmp #$02 bne .NotDone @@ -1823,6 +1926,18 @@ CollapseWindow: .NoNextMessage .NotDone jmp Buffer_End + +.AdditionalLineCopyTable + ; This table defines how many extra lines (in addition to the lines covering the text box) + ; need to be copied to the screen when collapsing a text box. The idea here is that shrinking + ; the text box should also erase tiles from the previous text box. + ; Each entry here is two bytes, the first one meaning "Y pos to subtract" and the second + ; "height to add". + db 0, 0; .NoBox + db 0, 2; .SoEBox + db 1, 2; .SoMBox + db 0, 0; .MMZBox + db 0, 0; .InstBox @@ -5199,6 +5314,23 @@ PrepareScreen: %dma_transfer(!vwf_dma_channel_nmi, DmaMode.WriteOnce, $2118, !vwf_buffer_text_box_tilemap, $0700) .End + lda !vwf_mode + cmp.b #$04 + bne .NoNextMessage + + ; Check if we're coming from a "display message" command. + ; If so, we need to skip parts of the initialization process. + lda !vwf_swap_message_settings + bit.b #%10000000 + beq .NoNextMessage + + lda #$00 + sta !vwf_swap_message_settings + lda.b #$06 + sta !vwf_mode + jmp VBlank_End + +.NoNextMessage lda !vwf_mode inc sta !vwf_mode @@ -5209,8 +5341,21 @@ PrepareScreen: CreateWindow: - %configure_vram_access(VRamAccessMode.Write, VRamIncrementMode.OnHighByte, VRamIncrementSize.1Byte, VRamAddressRemap.None, #$5C80) - %dma_transfer(!vwf_dma_channel_nmi, DmaMode.WriteOnce, $2118, !vwf_buffer_text_box_tilemap, $0700) + rep #$20 + lda !vwf_create_window_start_pos + lsr + clc + adc #$5C80 + sta $00 + + lda.w #!vwf_buffer_text_box_tilemap + clc + adc !vwf_create_window_start_pos + sta $02 + sep #$20 + + %configure_vram_access(VRamAccessMode.Write, VRamIncrementMode.OnHighByte, VRamIncrementSize.1Byte, VRamAddressRemap.None, $00) + %dma_transfer(!vwf_dma_channel_nmi, DmaMode.WriteOnce, $2118, dma_source_indirect_word($02, bank(!vwf_buffer_text_box_tilemap)), dma_size_indirect(!vwf_create_window_length)) lda !vwf_counter cmp #$02 @@ -5518,18 +5663,19 @@ StartNextMessage: bit.b #%00000001 beq .NoOpenAnim - lda #$06 + lda.b #$04 sta !vwf_mode + lda.b #$00 bra .Return .NoOpenAnim - lda #$08 + lda.b #$08 sta !vwf_mode + lda.b #$00 + sta !vwf_swap_message_settings .Return - lda #$00 - sta !vwf_swap_message_settings sta !vwf_swap_message_id sta !vwf_swap_message_id+1