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;