1 /***************************************************************************
2     Road Rendering & Control
3 
4     This is a complete port of the 68000 SUB CPU Program ROM.
5 
6     The original code consists of a shared Sega library and some routines
7     which are OutRun specific.
8 
9     Some of the original code is not used and is therefore not ported.
10 
11     This is the most complex area of the game code, and an area of the code
12     in need of refactoring.
13 
14     Useful background reading on road rendering:
15     http://www.extentofthejam.com/pseudo/
16 
17     Copyright Chris White.
18     See license.txt for more details.
19 ***************************************************************************/
20 
21 
22 #pragma once
23 
24 class ORoad
25 {
26 public:
27     uint32_t road_pos;        // 0x6: Current Road Position (addressed as long and word)
28     int16_t tilemap_h_target; // 0xA: Tilemap H target
29 
30 	// Stage Lookup Offset - Used to retrieve various data from in-game tables
31 	//
32 	// Stage Map:
33 	//
34 	// 24  23  22  21  20
35 	//   1B  1A  19  18
36 	//     12  11  10
37 	//       09  08
38 	//         00
39 	//
40 	// Increments by 8 each stage.
41 	// Also increments by +1 during the road split section from the values shown above.
42 	//
43 	// 0x38: Set to -8 during bonus mode section
44 	int16_t stage_lookup_off;
45 
46 	// These pointers rotate and select the current chunk of road data to blit
47 	uint16_t road_p0; // 0x3A: Road Pointer 0
48 	uint16_t road_p1; // 0x3C: Road Pointer 1 (Working road data)
49 	uint16_t road_p2; // 0x3E: Road Pointer 2 (Chunk of road to be blitted)
50 	uint16_t road_p3; // Ox40: Road Pointer 3 (Horizon Y Position)
51 
52     // 0x4C: Road Width Backup
53 	int16_t road_width_bak;
54 
55     // 0x4E: Car X Backup
56 	int16_t car_x_bak;
57 
58     // 0x66: Road Height Lookup
59 	uint16_t height_lookup;
60 
61     // 0x722 - [word] Road Height Index. Working copy of 60066.
62 	uint16_t height_lookup_wrk;
63 
64     // 0x6C: Change in road position
65     int32_t road_pos_change;
66 
67 	// 0x5E: Instruct CPU 1 to load end section road. Set Bit 1.
68 	uint8_t road_load_end;
69 
70 	// 0x306: Road Control
71 	uint8_t road_ctrl;
72 	enum
73 	{
74 		ROAD_OFF = 0,         // Both Roads Off
75 		ROAD_R0 = 1,          // Road 0
76 		ROAD_R1 = 2,          // Road 1
77 		ROAD_BOTH_P0 = 3,     // Both Roads (Road 0 Priority) [DEFAULT]
78 		ROAD_BOTH_P1 = 4,     // Both Roads (Road 1 Priority)
79 		ROAD_BOTH_P0_INV = 5, // Both Roads (Road 0 Priority) (Road Split. Invert Road 1)
80 		ROAD_BOTH_P1_INV = 6, // Both Roads (Road 1 Priority) (Road Split. Invert Road 1)
81 		ROAD_R0_SPLIT = 7,    // Road 0 (Road Split.)
82 		ROAD_R1_SPLIT = 8,    // Road 1 (Road Split. Invert Road 1)
83 	};
84 
85 	// 0x30B: Road Load Split.
86 	// This should be set to tell CPU 1 to init the road splitting code
87 	// 0    = Do Not Load
88 	// 0xFF = Load
89 	int8_t road_load_split;
90 
91 	// 0x314: Road Width
92 	// There are two road generators.
93 	//
94 	// The second road is drawn at an offset from the first, so that it either appears as one solid road, or as two separate roads.
95 	//
96 	// 00 = 3 lanes
97 	// D4 = 6 lanes
98 	//
99 	// Once the distance is greater than F0 or so, it's obvious there are two independent roads.
100 	int32_t road_width;// DANGER! USED AS LONG AND WORD
101 
102 	// 0x420: Offset Into Road Data [Current Road Position * 4]
103     // Moved from private for tracked
104 	uint16_t road_data_offset;
105 
106 	// 0x4F0: Start Address of Road Data For Current Stage In ROM
107     // TODO - move back to being private at some stage
108 	//uint32_t stage_addr;
109 
110     // 0x510: Horizon Y Position
111 	int16_t horizon_y2;
112     int16_t horizon_y_bak;
113 
114 	// 0x53C: Granular Position. More fine than other positioning info. Used to choose road background colour.
115 	uint16_t pos_fine;
116 
117     // 0x732 - [long] Base Horizon Y-Offset. Adjusting this almost has the effect of raising the camera.
118     // Stage 1 is 0x240
119     // Higher values = higher horizon.
120     // Note: This is adjusted mid-stage for Stage 2, but remains constant for Stage 1.
121 	const static int32_t HORIZON_OFF = -0x3FF;
122 	int32_t horizon_base;
123 
124 	// 0x736: 0 = Base Horizon Value Not Set. 1 = Value Set.
125 	uint8_t horizon_set;
126 
127     const static uint16_t ARRAY_LENGTH = 0x200;
128 
129 	// 60800 - 60BFF: Road X-Positions [Before H-Scroll Is Applied] - Same Data For Both Roads
130 	int16_t road_x[ARRAY_LENGTH];
131 
132 	// 60C00 - 60FFF: Road 0 H-Scroll Adjusted Positions
133 	int16_t road0_h[ARRAY_LENGTH];
134 
135 	// 61000 - 613FF: Road 1 H-Scroll Adjusted Positions
136 	int16_t road1_h[ARRAY_LENGTH];
137 
138 	// 61400 - 617FF: Not sure what this is yet
139 	int16_t road_unk[ARRAY_LENGTH];
140 
141 	// 61800 - 637FF: Road Y-Positions
142     //
143     // Consists of three separate blocks of data:
144     //
145     // Offset 0x000: Source Data. List of sequential numbers to indicate when to read next road value from source rom.
146     //               Numbers iterate down sequentially, until a hill, when they will rise again
147     // Offset 0x280: Priority information for road (during elevated sections). Used to hide sprites
148     // Offset 0x400: Destination Data. Final converted data to be output to road hardware
149     //
150     // This format is repeated four times, due to the way values rotate through road ram
151 	int16_t road_y[0x1000];
152 
153     const static uint8_t VIEW_ORIGINAL = 0;
154     const static uint8_t VIEW_ELEVATED = 1;
155     const static uint8_t VIEW_INCAR    = 2;
156 
157 	ORoad();
158 	~ORoad();
159 	void init();
160 	void tick();
161     uint8_t get_view_mode();
162     int16_t get_road_y(uint16_t);
163     void set_view_mode(uint8_t, bool snap = false);
164 
165 private:
166     // Enhancement: View Mode
167     uint8_t view_mode;
168 
169     // Enhancement: Target Horizon Adjust
170     int16_t horizon_target;
171 
172     // Enhancement: Horizon Offset, used for new view modes
173     int16_t horizon_offset;
174 
175 	uint16_t stage_loaded; // 0x4: Current Stage Backup (So we know when to load next stage road data)
176 
177 	uint32_t road_pos_old; // 0x410: Road Position Backup
178 
179 	// 60530 - [word] Distance into section of track, for height #1
180     // Ranges from 0x100 - 0x1FF
181 	uint16_t height_start;
182 
183 	// 0x536 - [word] Controls switch statement when processing road height
184     //                0 = Clear Road Height Segment
185     //                1 = Init Next Road Height Segment
186     //                2 = Use Elevation
187     //                3 =
188     //                4 =
189     //                5 = Set Base Horizon
190 	uint16_t height_ctrl;
191 
192 	// 0x542: Granular Position Backup.
193 	uint16_t pos_fine_old;
194 
195 	// 0x544 - [word] Difference between granular positions.
196 	int16_t pos_fine_diff;
197 
198 	// 0x70E - [word] Counter. Counts to 7. Denotes Interpolated track section currently being written.
199 	int8_t counter;
200 
201 	// 0x710 - Index Into Height Data (generally specifies hill type for specific section of road)
202     // The results of the value will differ depending on which road height section currently on.
203     // Not to be confused with 6072A, which is a much larger number.
204     // Hack to see different values: wpset 60710,2,r,1,{w@60710 = 5; g;}
205 	int16_t height_index;
206 
207 	// 0x712 - [long] Final Height Value. Takes Horizon and distance into screen into account.
208 	int32_t height_final;
209 
210 	// 0x716 - [word] Increment Value For 0x710 to adjust lookup from height data
211 	uint16_t height_inc;
212 
213 	// 0x718 - [word] This stores the position into the current road segment we're on.
214     // Derived from the granular position and used in conjunction with road height.
215     // As a hack try wpset 60718,2,r,1,{w@60718 = 0x6b5; g;}
216     // you'll stall at a position on the current road segment after value is set.
217 	uint16_t height_step;
218 
219 	// 0x71A - [word] Jump Table Control For Road Height (Read from Road Data).
220 	uint16_t height_ctrl2;
221 
222 	// 0x71C - [long] Stores current position into road height data. This is an actual address.
223 	uint32_t height_addr;
224 
225 	// 0x720 - [word] Elevation Flag
226 	int16_t elevation;
227 	enum {DOWN = -1, NO_CHANGE = 0, UP = 1};
228 
229 	// 0x724 - [word] Ascend/Descent Hold
230 	int16_t height_delay;
231 
232 	// 0x726 - [word] Speed at which to adjust height_step
233 	uint16_t step_adjust;
234 
235 	// 0x728
236 	uint16_t do_height_inc;
237 
238 	// 0x72A - [word] Distance into section of track, for height #2
239     //             Ranges from 0x100 - 0x1FF
240 	uint16_t height_end;
241 
242 	// 0x72C: Up Multiplier
243 	int8_t up_mult;
244 
245 	// 0x72E: Down Multiplier
246 	int8_t down_mult;
247 
248 	// 0x73A: 0 = Base Horizon Value Not Set. 1 = Value Set.
249 	uint32_t horizon_mod;
250 
251 	// 60700: Lengths of the 7 road segments 60700 - 6070D
252 	uint16_t section_lengths[7];
253 	int8_t length_offset;
254 	uint32_t a1_lookup;
255 
256     // Registers - todo: refactor these
257     int32_t change_per_entry; // [d2]
258     int32_t d5_o;
259     uint32_t a3_o;
260     uint32_t y_addr;
261     int16_t scanline;
262     int32_t total_height;
263 
264 	// -------------------------------------------------------------------------
265 	// Locations in Road RAM
266 	// -------------------------------------------------------------------------
267 	static const uint32_t HW_HSCROLL_TABLE0 = 0x80400;
268 	static const uint32_t HW_HSCROLL_TABLE1 = 0x80800;
269 	static const uint32_t HW_BGCOLOR = 0x80C00;
270 
271 	void set_default_hscroll();
272 	void clear_road_ram();
273 	void init_stage1();
274 	void do_road();
275 	void rotate_values();
276 	void check_load_road();
277 
278 	void setup_road_x();
279 	void setup_x_data(uint32_t);
280 	void set_tilemap_x(uint32_t);
281 	void create_curve(int16_t&, int16_t&,
282                       const int32_t, const int32_t, const int16_t, const int16_t);
283 
284 	void setup_hscroll();
285 	void do_road_offset(int16_t*, int16_t, bool);
286 
287 	void setup_road_y();
288 	void init_height_seg();
289 
290 	void init_elevation(uint32_t&);
291 	void do_elevation();
292 	void init_elevation_delay(uint32_t&);
293 	void do_elevation_delay();
294     void init_elevation_mixed(uint32_t&);
295     void do_elevation_mixed();
296 	void init_horizon_adjust(uint32_t&);
297 	void do_horizon_adjust();
298 
299 	void set_road_y();
300 	void set_y_interpolate();
301 	void set_y_horizon();
302 	void set_y_2044();
303 	void read_next_height();
304 	void set_elevation();
305 
306 	void set_horizon_y();
307 	void do_road_data();
308 
309 	void blit_roads();
310 	void blit_road(uint32_t);
311 
312 	void output_hscroll(int16_t*, uint32_t);
313 	void copy_bg_color();
314 };
315 
316 extern ORoad oroad;