git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-lib/examples/cross-platform/scroller/src/text_scroller.c

      1 #include <gbdk/platform.h>
      2 #include <gbdk/font.h>
      3 #include <stdint.h>
      4 #include <stdio.h>
      5 
      6 // Positive 1 in valid y scroll coordinates
      7 #define P1 1
      8 // Negative 1 in valid y scroll coordinates
      9 #define N1 (uint8_t)(DEVICE_SCREEN_BUFFER_HEIGHT*8 - 1)
     10 
     11 const uint8_t shake_tbl[] = {0, P1, P1, P1, 0, N1, N1, N1};
     12 const uint8_t scanline_offsets_tbl[] = {0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0};
     13 const uint8_t * scanline_offsets = scanline_offsets_tbl;
     14 
     15 #define SCROLL_POS 15u
     16 #define SCROLL_HEIGHT 1u
     17 #define SCROLL_PIX_HEIGHT (SCROLL_HEIGHT * 8u)
     18 #define SCROLL_POS_PIX_START (((SCROLL_POS + DEVICE_SCREEN_Y_OFFSET) * 8u) - 2u)
     19 #define SCROLL_POS_PIX_END (((SCROLL_POS + DEVICE_SCREEN_Y_OFFSET) * 8u) + SCROLL_PIX_HEIGHT - 1u)
     20 
     21 inline void do_scroll(uint8_t x, uint8_t y) {
     22 #if defined(NINTENDO) || defined(NINTENDO_NES)
     23     move_bkg(x, y);
     24 #elif defined(SEGA)
     25     y;
     26     __WRITE_VDP_REG_UNSAFE(VDP_RSCX, -x);    
     27 #endif
     28 }
     29 
     30 #if defined(SEGA)
     31 uint8_t LYC_REG = 0;  // define the fake LYC_REG, we will use it as the interrupt routine state
     32 
     33 void vblank_isr(void) {
     34     __WRITE_VDP_REG_UNSAFE(VDP_R10, SCROLL_POS_PIX_START);
     35     do_scroll(0, 0);
     36     LYC_REG = SCROLL_POS_PIX_START;
     37 }
     38 #endif
     39 
     40 uint8_t scroller_x = 0;
     41 void scanline_isr(void) {
     42     switch (LYC_REG) {
     43 #if defined(NINTENDO) || defined(NINTENDO_NES)
     44         case 0: 
     45             do_scroll(0, 0);
     46             LYC_REG = SCROLL_POS_PIX_START;
     47             break;
     48 #endif
     49         case SCROLL_POS_PIX_START:
     50             do_scroll(scroller_x, shake_tbl[(scroller_x >> 1) & 7]);
     51 #if defined(SEGA)
     52             __WRITE_VDP_REG_UNSAFE(VDP_R10, R10_INT_OFF); // disable scanline interrupts after the next triggerimg
     53             while (VCOUNTER != SCROLL_POS_PIX_END);       // busywait for the end of the scanline effect
     54             do_scroll(0, 0);
     55 #endif
     56             LYC_REG = SCROLL_POS_PIX_END;
     57             break;
     58         case SCROLL_POS_PIX_END:
     59 #if defined(NINTENDO) || defined(NINTENDO_NES)
     60             do_scroll(0, 0);
     61             LYC_REG = 0;
     62 #endif
     63         default:
     64             break;
     65     }
     66 }
     67 
     68 const uint8_t scroller_text[] = "This is a text scroller demo for GBDK-2020. You can use ideas, that are "\
     69 "shown in this demo, to make different parallax effects, scrolling of tilemaps which are larger than 32x32 "\
     70 "tiles and TEXT SCROLLERS, of course! Need to write something else to make this text longer than 256 characters. "\
     71 "The quick red fox jumps over the lazy brown dog. 0123456789.          ";
     72 
     73 const uint8_t * scroller_next_char = scroller_text;
     74 uint8_t * scroller_vram_addr;
     75 uint8_t * base, * limit;
     76 
     77 void main(void) {
     78     DISPLAY_OFF;
     79     // Init font system / clear screen
     80     font_init();
     81     font_set(font_load(font_ibm));
     82     // Fill the screen background with '*'
     83     fill_bkg_rect(0, 0, DEVICE_SCREEN_WIDTH, DEVICE_SCREEN_HEIGHT, '*' - ' ');
     84     DISPLAY_ON;
     85 
     86     printf(" Scrolling %d chars", sizeof(scroller_text) - 1);
     87 
     88     CRITICAL {
     89         add_LCD(scanline_isr);
     90 #if defined(NINTENDO)
     91         STAT_REG |= STATF_LYC;
     92 #elif defined(SEGA)
     93         add_VBL(vblank_isr);
     94 #endif
     95         LYC_REG = 0;
     96     }
     97 #if defined(NINTENDO) || defined(NINTENDO_NES) || defined(SEGA)
     98     set_interrupts(VBL_IFLAG | LCD_IFLAG);
     99 #endif
    100     HIDE_LEFT_COLUMN;    
    101     base = (uint8_t *)((uint16_t)get_bkg_xy_addr(0, SCROLL_POS) & (DEVICE_SCREEN_MAP_ENTRY_SIZE==1?0xffe0:0xffc0));
    102     limit = base + (DEVICE_SCREEN_BUFFER_WIDTH * DEVICE_SCREEN_MAP_ENTRY_SIZE);
    103 
    104     scroller_vram_addr = base + ((DEVICE_SCREEN_X_OFFSET + DEVICE_SCREEN_WIDTH) * DEVICE_SCREEN_MAP_ENTRY_SIZE);
    105     if (scroller_vram_addr >= limit) scroller_vram_addr = base;
    106     
    107     set_vram_byte(scroller_vram_addr, *scroller_next_char - 0x20);
    108     
    109     while (TRUE) {
    110         scroller_x++;
    111         if ((scroller_x & 0x07) == 0) {
    112             // next letter
    113             scroller_next_char++;
    114             if (*scroller_next_char == 0) scroller_next_char = scroller_text;
    115             
    116             // next vram position
    117             scroller_vram_addr += DEVICE_SCREEN_MAP_ENTRY_SIZE;
    118             if (scroller_vram_addr >= limit) scroller_vram_addr = base;
    119             
    120             // put next char
    121             set_vram_byte(scroller_vram_addr, *scroller_next_char - 0x20);
    122         }
    123         vsync();        
    124     }
    125 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.