1 /***************************************************************************
2     Attract Mode: Animated OutRun Logo Graphic
3 
4     The logo is built from multiple sprite components.
5 
6     Copyright Chris White.
7     See license.txt for more details.
8 ***************************************************************************/
9 
10 #include "stdint.hpp"
11 #include "engine/osprites.hpp"
12 #include "engine/outils.hpp"
13 #include "engine/ologo.hpp"
14 
15 OLogo ologo;
16 
17 const uint8_t OLogo::bg_pal[] = { 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9A, 0x9B, 0x9C };
18 
OLogo()19 OLogo::OLogo()
20 {
21 }
22 
~OLogo()23 OLogo::~OLogo()
24 {
25 }
26 
enable(int16_t y)27 void OLogo::enable(int16_t y)
28 {
29     y_off = -y;
30 
31     entry_start = OSprites::SPRITE_ENTRIES - 0x10;
32 
33     // Enable block of sprites
34     for (int i = entry_start; i < entry_start + 7; i++)
35     {
36         osprites.jump_table[i].init(i);
37     }
38 
39     palm_frames[0] = outrun.adr.sprite_logo_palm1;
40     palm_frames[1] = outrun.adr.sprite_logo_palm2;
41     palm_frames[2] = outrun.adr.sprite_logo_palm3;
42     palm_frames[3] = outrun.adr.sprite_logo_palm2;
43     palm_frames[4] = outrun.adr.sprite_logo_palm1;
44     palm_frames[5] = outrun.adr.sprite_logo_palm2;
45     palm_frames[6] = outrun.adr.sprite_logo_palm3;
46     palm_frames[7] = outrun.adr.sprite_logo_palm2;
47 
48     setup_sprite1();
49     setup_sprite2();
50     setup_sprite3();
51     setup_sprite4();
52     setup_sprite5();
53     setup_sprite6();
54     setup_sprite7();
55 }
56 
disable()57 void OLogo::disable()
58 {
59     // Enable block of sprites
60     for (int i = entry_start; i < entry_start + 7; i++)
61     {
62         osprites.jump_table[i].control &= ~OSprites::ENABLE;
63     }
64 }
65 
tick()66 void OLogo::tick()
67 {
68     sprite_logo_bg();
69     sprite_logo_car();
70     sprite_logo_bird1();
71     sprite_logo_bird2();
72     sprite_logo_road();
73     sprite_logo_palm();
74     sprite_logo_text();
75 }
76 
77 // Animated Background Oval Sprite.
setup_sprite1()78 void OLogo::setup_sprite1()
79 {
80     oentry *e = &osprites.jump_table[entry_start + 0];
81     e->x = 0;
82     e->y = 0x70 - y_off;
83     e->road_priority = 0xFF;
84     e->priority = 0x1FA;
85     e->zoom = 0x7F;
86     e->pal_src = 0x99;
87     e->addr = outrun.adr.sprite_logo_bg;
88     osprites.map_palette(e);
89 }
90 
91 // Sprite Car Graphic
setup_sprite2()92 void OLogo::setup_sprite2()
93 {
94     oentry *e = &osprites.jump_table[entry_start + 1];
95     e->x = -3;
96     e->y = 0x88 - y_off;
97     e->road_priority = 0x100;
98     e->priority = 0x1FB;
99     e->zoom = 0x7F;
100     e->pal_src = 0x6E;
101     e->addr = outrun.adr.sprite_logo_car;
102     osprites.map_palette(e);
103 }
104 
105 // Sprite Flying Bird #1
setup_sprite3()106 void OLogo::setup_sprite3()
107 {
108     oentry *e = &osprites.jump_table[entry_start + 2];
109     e->x = 0x8;
110     e->y = 0x4E - y_off;
111     e->road_priority = 0x102;
112     e->priority = 0x1FD;
113     e->zoom = 0x7F;
114     e->counter = 0;
115     e->pal_src = 0x8B;
116     e->addr = outrun.adr.sprite_logo_bird1;
117     osprites.map_palette(e);
118 }
119 
120 // Sprite Flying Bird #2
setup_sprite4()121 void OLogo::setup_sprite4()
122 {
123     oentry *e = &osprites.jump_table[entry_start + 3];
124     e->x = 0x8;
125     e->y = 0x4E - y_off;
126     e->road_priority = 0x102;
127     e->priority = 0x1FD;
128     e->zoom = 0x7F;
129     e->counter = 0x20;
130     e->pal_src = 0x8C;
131     e->addr = outrun.adr.sprite_logo_bird2;
132     osprites.map_palette(e);
133 }
134 
135 // Sprite Road Base Section
setup_sprite5()136 void OLogo::setup_sprite5()
137 {
138     oentry *e = &osprites.jump_table[entry_start + 4];
139     e->x = -0x20;
140     e->y = 0x8F - y_off;
141     e->road_priority = 0x101;
142     e->priority = 0x1FC;
143     e->zoom = 0x7F;
144     e->pal_src = 0x6E;
145     e->addr = outrun.adr.sprite_logo_base;
146     osprites.map_palette(e);
147 }
148 
149 // Palm Tree
setup_sprite6()150 void OLogo::setup_sprite6()
151 {
152     oentry *e = &osprites.jump_table[entry_start + 5];
153     e->x = -0x40;
154     e->y = 0x6D - y_off;
155     e->road_priority = 0x102;
156     e->priority = 0x1FD;
157     e->zoom = 0x7F;
158     e->pal_src = 0x65;
159     e->addr = outrun.adr.sprite_logo_palm1;
160     osprites.map_palette(e);
161 }
162 
163 // OutRun logo text
setup_sprite7()164 void OLogo::setup_sprite7()
165 {
166     oentry *e = &osprites.jump_table[entry_start + 6];
167     e->x = 0x11;
168     e->y = 0x65 - y_off;
169     e->road_priority = 0x103;
170     e->priority = 0x1FE;
171     e->zoom = 0x7F;
172     e->counter = 0;
173     e->pal_src = 0x65;
174     e->addr = outrun.adr.sprite_logo_text;
175     osprites.map_palette(e);
176 }
177 
178 // Draw Background of OutRun logo in attract mode
sprite_logo_bg()179 void OLogo::sprite_logo_bg()
180 {
181     oentry *e = &osprites.jump_table[entry_start + 0];
182     e->reload++;
183     uint16_t d0 = e->reload;
184     uint16_t d1 = d0 - 1;
185     d1 ^= d0;
186 
187     // Map new palette
188     if (d1 & BIT_3)
189     {
190         e->pal_src = bg_pal[outils::random() & 7];
191         osprites.map_palette(e);
192     }
193 
194     osprites.do_spr_order_shadows(e);
195 }
196 
sprite_logo_car()197 void OLogo::sprite_logo_car()
198 {
199     oentry *e = &osprites.jump_table[entry_start + 1];
200     // Flicker background palette of car
201     e->reload++;
202     e->pal_src = ((e->reload & 2) >> 1) ? 0x8A : 0x6E;
203     osprites.map_palette(e);
204     osprites.do_spr_order_shadows(e);
205 }
206 
sprite_logo_bird1()207 void OLogo::sprite_logo_bird1()
208 {
209     oentry *e = &osprites.jump_table[entry_start + 2];
210     e->counter++;
211 
212     // Set Bird X Value
213     uint16_t index = (e->counter << 1) & 0xFF;
214     int8_t bird_x = roms.rom0.read8(DATA_MOVEMENT + index); // Note we sign the value here
215     int8_t zoom = bird_x >> 3;
216     e->x = (bird_x >> 3) + 8;
217 
218     // Set Zoom Lookup
219     e->zoom = zoom + 0x70;
220 
221     // Set Bird Y Value
222     index = (index << 1) & 0xFF;
223     int8_t bird_y = roms.rom0.read8(DATA_MOVEMENT + index); // Note we sign the value here
224     e->y = (bird_y >> 5) + 0x4E - y_off;
225 
226     // Set Frame
227     e->reload++;
228     uint16_t frame = (e->reload & 4) >> 2;
229     e->addr = frame ? outrun.adr.sprite_logo_bird2 : outrun.adr.sprite_logo_bird1;
230     osprites.do_spr_order_shadows(e);
231 }
232 
sprite_logo_bird2()233 void OLogo::sprite_logo_bird2()
234 {
235     oentry *e = &osprites.jump_table[entry_start + 3];
236     e->counter++;
237 
238     // Set Bird X Value
239     uint16_t index = (e->counter << 1) & 0xFF;
240     int8_t bird_x = roms.rom0.read8(DATA_MOVEMENT + index); // Note we sign the value here
241     int8_t zoom = bird_x >> 3;
242     e->x = (bird_x >> 3) - 2; // Different from sprite_logo_bird1
243 
244     // Set Zoom Lookup
245     e->zoom = zoom + 0x70;
246 
247     // Set Bird Y Value
248     index = (index << 1) & 0xFF;
249     int8_t bird_y = roms.rom0.read8(DATA_MOVEMENT + index); // Note we sign the value here
250     e->y = (bird_y >> 5) + 0x52 - y_off; // Different from sprite_logo_bird1
251 
252     // Set Frame
253     e->reload++;
254     uint16_t frame = (e->reload & 4) >> 2;
255     e->addr = frame ? outrun.adr.sprite_logo_bird2 : outrun.adr.sprite_logo_bird1;
256     osprites.do_spr_order_shadows(e);
257 }
258 
sprite_logo_road()259 void OLogo::sprite_logo_road()
260 {
261     osprites.do_spr_order_shadows(&osprites.jump_table[entry_start + 4]);
262 }
263 
sprite_logo_palm()264 void OLogo::sprite_logo_palm()
265 {
266     oentry *e = &osprites.jump_table[entry_start + 5];
267     e->reload++; // Increment frame number
268     e->addr = palm_frames[(e->reload & 0xE) >> 1];
269     osprites.do_spr_order_shadows(e);
270 }
271 
sprite_logo_text()272 void OLogo::sprite_logo_text()
273 {
274     osprites.do_spr_order_shadows(&osprites.jump_table[entry_start + 6]);
275 }
276 
277 // Blit Only: Used when frame skipping
blit()278 void OLogo::blit()
279 {
280     for (int i = 0; i < 7; i++)
281         osprites.do_spr_order_shadows(&osprites.jump_table[entry_start + i]);
282 }
283