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.