diff options
Diffstat (limited to 'arm9/source/main.c')
-rw-r--r-- | arm9/source/main.c | 168 |
1 files changed, 113 insertions, 55 deletions
diff --git a/arm9/source/main.c b/arm9/source/main.c index 56103da..9dc612c 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -1,122 +1,179 @@ -#include <stdio.h> -#include <time.h> -#include <nds.h> -#include "devices/clock.h" -#include "devices/math.h" -#include "devices/screen.h" -#include "bang.h" -#include "core.h" #include "main.h" +#include "config.h" -#define NUM_BR 5 -Bedrock br[NUM_BR] = {}; +char *system_name = "bedrock-nds/0.1.0"; +char *system_authors = "Ben Bridle"; + +// Reserve memory for all Bedrock instances up front. +Bedrock br[NUM_INSTANCES] = {}; +// The instance currently visible on the main screen. +u32 MAIN_INSTANCE = 0; + +// The NDS has two 2D engines, called the main engine and the sub engine. +// These can be freely allocated to either of the hardware screens, there +// is effectively no difference between the two engines for our purposes. +// The br_main pointer will point to the Bedrock instance currently using +// the main engine (which will always be the current user instance), and +// the br_sub pointer to the instance using the sub engine (which will +// always be the keyboard instance). Bedrock *br_main; Bedrock *br_sub; -bool main_on_bottom = TRUE; +// The main 2D engine always starts on the bottom hardware screen. +bool main_on_bottom = true; -char *system_name = "bedrock-nds/0.1.0-alpha"; -char *system_authors = "Ben Bridle"; +// Bake some Bedrock programs into the emulator. u8 main_program[] = { - #include "../include/cobalt.br.inc" + // #include "../include/alphabet-snake.br.inc" + // #include "../include/clock.br.inc" + #include "../include/cobalt-demo.br.inc" + // #include "../include/system-info.br.inc" }; u8 keyboard_program[] = { #include "../include/keyboard.br.inc" }; -// Change to the next screen layout. -void change_layout(void) { +// Swap the hardware screens. +void swap_screens(void) { lcdSwap(); main_on_bottom = !main_on_bottom; + // Hide the sub program if the main program is on the bottom screen. if (main_on_bottom) { - scr_unmake(&br_sub->scr); + screen_map_to_none(&br_sub->dev.screen); } else { - scr_make_sub(&br_sub->scr); + screen_map_to_sub(&br_sub->dev.screen); } } +// TODO void receive_keyboard_byte(u8 byte) { if (br_main) { - inp_receive_byte(&br_main->inp, byte); + input_receive_key(&br_main->dev.input, byte); } } -bool is_keyboard_open(void) { - return !main_on_bottom; -} - +// TODO void open_keyboard(void) { if (main_on_bottom) { - change_layout(); + swap_screens(); + // Deactivate the pointer on the main instance. + br_main->dev.input.pointer = false; + br_main->dev.input.wake = true; + // Connect the keyboard. + br_sub->dev.stream.local.output.connected = true; } } +// TODO void close_keyboard(void) { if (!main_on_bottom) { - change_layout(); + swap_screens(); + // Disconnect the keyboard. + br_sub->dev.stream.local.output.connected = false; } } +// Make a neighbouring user instance become the new active user instance. +void change_main_instance(int delta) { + screen_map_to_none(&br[MAIN_INSTANCE].dev.screen); + MAIN_INSTANCE = (MAIN_INSTANCE + delta) % USER_INSTANCES; + screen_map_to_main(&br[MAIN_INSTANCE].dev.screen); + br[MAIN_INSTANCE].dev.screen.wake = true; + br_main = &br[MAIN_INSTANCE]; +} + // Scan for input and handle emulator-specific keys. void receive_input(void) { + // This should be the only place in the entire codebase where the + // scanKeys function is called. scanKeys(); - if (keysDown() & KEY_SELECT) change_layout(); + // Swap screens when the select key is pressed. + if (keysDown() & KEY_SELECT) swap_screens(); + if (SWITCH_BETWEEN_INSTANCES) { + if (keysDown() & KEY_L) change_main_instance(-1); + if (keysDown() & KEY_R) change_main_instance(1); + } } +// ------ MAIN ----------------------------------------------------------------- + int main(void) { #define ALIVE(br) (br && br->alive) #define DEAD(br) (br && !br->alive) #define AWAKE(br) (br && br->alive && br->awake) #define ASLEEP(br) (br && br->alive && !br->awake) - // Set memory identifiers and system device strings. - for (int i=0; i<NUM_BR; i++) { - br[i].mem.id = i+1; - br[i].sys.name.mem = (u8*) &system_name[0]; - br[i].sys.authors.mem = (u8*) &system_authors[0]; + // Initialise all Bedrock instances. + for (int i=0; i<NUM_INSTANCES; i++) { + br_reset(&br[i]); + br[i].dev.memory.id = i+1; + readbuf_populate(&br[i].dev.system.name, (u8*) system_name); + readbuf_populate(&br[i].dev.system.authors, (u8*) system_authors); } - init_screens(); - init_clock(); - init_filesystem(); + // Initialise functions used by devices. + init_nds_clock(); + init_nds_screens(); + init_nds_filesystem(); + + // Start with the main screen on the bottom. lcdMainOnBottom(); - // Load program - start_br(&br[0], main_program, sizeof(main_program)); - start_br(&br[1], keyboard_program, sizeof(keyboard_program)); - br_main = &br[0]; - br_sub = &br[1]; - scr_make_main(&br_main->scr); + // Initialise the debug console. + // TODO: Remove. + // consoleDemoInit(); + + // Load program. + br_main = &br[MAIN_INSTANCE]; + br_sub = &br[KEY_INSTANCE]; + br_load(&br[MAIN_INSTANCE], main_program, sizeof(main_program)); + br_load(&br[KEY_INSTANCE], keyboard_program, sizeof(keyboard_program)); + + // We map the main instance to the main screen, but we don't map the + // sub instance because we don't want it to be visible just yet. + screen_map_to_main(&br_main->dev.screen); + + // ------ EVENT LOOP ------------------------------------------------------- while (1) { - if (AWAKE(br_main)) run_br(br_main); - if (AWAKE(br_sub)) run_br(br_sub); + if (AWAKE(br_main)) br_run(br_main); + if (AWAKE(br_sub)) br_run(br_sub); if (DEAD(br_main)) br_main = NULL; if (DEAD(br_sub)) br_sub = NULL; - bool main_flip = ASLEEP(br_main) && br_main->scr.dirty; - bool sub_flip = ASLEEP(br_sub) && br_sub->scr.dirty; - if (main_flip || sub_flip) swiWaitForVBlank(); - if (main_flip) { flip_buffer(br_main->scr.nds); br_main->scr.dirty = false; } - if (sub_flip) { flip_buffer(br_sub->scr.nds); br_sub->scr.dirty = false; } + // Check if screen buffers need to be flipped. + // Only flip buffers if the instance is asleep. + bool flip_main = ASLEEP(br_main) && br_main->dev.screen.dirty; + bool flip_sub = ASLEEP(br_sub) && br_sub->dev.screen.dirty; + // Wait for next frame to avoid running too fast. + if (flip_main || flip_sub) swiWaitForVBlank(); + if (flip_main) { + ndsscreen_flip_buffers(br_main->dev.screen.nds); + br_main->dev.screen.dirty = false; + } + if (flip_sub) { + ndsscreen_flip_buffers(br_sub->dev.screen.nds); + br_sub->dev.screen.dirty = false; + } rouse: receive_input(); + // Receive gamepad and touch input if main is on bottom screen. if (ALIVE(br_main) && main_on_bottom) { - inp_read_navigation(&br_main->inp); - inp_read_gamepad(&br_main->inp); - inp_read_touch(&br_main->inp); + input_update_gamepad(&br_main->dev.input); + input_update_touch(&br_main->dev.input); } + // Receive gamepad and touch input if sub is on bottom screen. if (ALIVE(br_sub) && !main_on_bottom) { - inp_read_navigation(&br_sub->inp); - inp_read_gamepad(&br_sub->inp); - inp_read_touch(&br_sub->inp); + input_update_gamepad(&br_sub->dev.input); + input_update_touch(&br_sub->dev.input); } - if (ASLEEP(br_main)) rouse_br(br_main); - if (ASLEEP(br_sub)) rouse_br(br_sub); + if (ASLEEP(br_main)) br_rouse(br_main); + if (ASLEEP(br_sub)) br_rouse(br_sub); + if (ASLEEP(br_main) && ASLEEP(br_sub)) { // Sleep until next keypad event or clock tick. swiIntrWait(1, IRQ_KEYS | IRQ_TIMER0); @@ -124,6 +181,7 @@ int main(void) { } if (!br_main) { + printf("SHUTTING DOWN\n"); systemShutDown(); return 0; } |