summaryrefslogtreecommitdiff
path: root/packages/libgbafpc/examples/graphics/SimpleBGScroll/SimpleBGScroll.pp
blob: 205567eff37116c3b6dfde9928f7897ce1cc4ed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
program SimpleBGScroll;

uses
  ctypes, gba;

{$l build\r6502_portfont.bin.o}

{$include inc\r6502_portfont.bin.inc}

var
  MAPADDRESS: pcuint16;

const
  DELAY = 2;			                  // slow things down
  TILEWIDTH = 8;			              // how much to scroll
  ROW = 10;			                    // what row to place text at

// --------------------------------------------------------------------

var 
  palette: array [0..6] of cuint16;
  
// --------------------------------------------------------------------

const 
  message = '                                ' +
            'Hello, this is an example of an oldschool simple tile scroller ' +
            'not unlike how it was done in days of yore.  The ''@'' symbol ' +
            'at the top of your screen is intentional, to dispel the illusion ' +
            'of this scroller, to demonstrate the simple concept behind it. ' +
            'Check out the source to learn how it works.  It is very simple! ' +
            'This exercise brought to you by r6502...          ' +
            'Text is about to restart... ';



procedure updatescrolltext(idx: cuint32);
var
  i: integer;
  temppointer: pcuint16;
begin
  temppointer := pcuint16(MAPADDRESS + (ROW * 32));

  // write out a whole row of text to the map
  for i := 0 to 31 do
  begin
    // check for end of message so we can wrap around properly
    if (message[idx] = #0) then 
      idx := 0;

    // write a character - we subtract 32, because the font graphics
    // start at tile 0, but our text is in ascii (starting at 32 and up)
    // in other words, tile 0 is a space in our font, but in ascii a
    // space is 32 so we must account for that difference between the two.
    temppointer^ := Ord(message[idx]) - 32;
    inc(temppointer); 
    inc(idx);
  end;
end;


var
  i, scrollx, scrolldelay, textindex: integer;
  temppointer: pcuint16;

begin	
  MAPADDRESS := MAP_BASE_ADR(31);    // our base map address
  
  palette[0] := RGB8($40,$80,$c0);
  palette[1] := RGB8($FF,$FF,$FF);
  palette[2] := RGB8($F5,$FF,$FF);
  palette[3] := RGB8($DF,$FF,$F2);
  palette[4] := RGB8($CA,$FF,$E2);
  palette[5] := RGB8($B7,$FD,$D8);
  palette[6] := RGB8($2C,$4F,$8B);

  // Set up the interrupt handlers
  irqInit();
  // Enable Vblank Interrupt to allow VblankIntrWait
  irqEnable(IRQ_VBLANK);

  // Allow Interrupts
  REG_IME^ := 1;

  // load the palette for the background, 7 colors
  temppointer := BG_COLORS;
  
  for i := 0 to 6 do
  begin
    temppointer^ := cuint32(palette[i]); // u32 cast avoids u8 memory writing
    inc(temppointer);
  end;

  // load the font into gba video mem (48 characters, 4bit tiles)

  CpuFastSet(@r6502_portfont_bin, pcuint16(VRAM), (r6502_portfont_bin_size div 4) or COPY32);

  // clear screen map with tile 0 ('space' tile) (256x256 halfwords)

  //MAP_BASE_ADR(31) := nil;
  CpuFastSet( MAP_BASE_ADR(31), MAP_BASE_ADR(31), FILL or COPY32 or ($800 div 4));

  // set screen H and V scroll positions
  BG_OFFSET[0].x := 0; 
  BG_OFFSET[0].y := 0;

  // initialize our variables
  scrollx := 0;
  textindex := 0;
  scrolldelay := 0;

  // put the '@' symbol on the top of the screen to show how
  // the screen is only scrolling 7 pixels - to reveal the
  // illusion of how the scroller works
  pcuint16((MAPADDRESS + 1))^ := $20;	// 0x20 == '@'

  // draw a row of text from beginning of message
  updatescrolltext(0);

  // set the screen base to 31 (0x600F800) and char base to 0 (0x6000000)
  BGCTRL[0] := SCREEN_BASE(31);

  // screen mode & background to display
  SetMode( MODE_0 or BG0_ON );

  while true do 
  begin
    VBlankIntrWait();

    // check if we reached our delay
    if (scrolldelay = DELAY) then
    begin
      // yes, the delay is complete, so let's reset it
      scrolldelay := 0;

      // check if we reached our scrollcount
      if (scrollx = (TILEWIDTH-1)) then
      begin
        // yes, we've scrolled enough, so let's reset the count
        scrollx := 0;

        // check if we reached the end of our scrolltext
        // and if so we need to restart our index
        if (message[textindex] = #0) then 
          textindex := 0
        else 
          inc(textindex);

        // finally, let's update the scrolltext with the current text index
        updatescrolltext(textindex);
      end else 
        inc(scrollx);
    end else 
      inc(scrolldelay);

    // update the hardware horizontal scroll register
    BG_OFFSET[0].x := scrollx;
  end;
end.