#include "main.h" #include "config.h" char *system_name = "bedrock-nds/1.0.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; // The main 2D engine always starts on the bottom hardware screen. bool main_on_bottom = true; // Bake some Bedrock programs into the emulator. u8 main_program[] = { // #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" }; // 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) { screen_map_to_none(&br_sub->dev.screen); } else { screen_map_to_sub(&br_sub->dev.screen); } } // TODO void receive_keyboard_byte(u8 byte) { if (br_main) { input_receive_key(&br_main->dev.input, byte); } } // TODO void open_keyboard(void) { if (main_on_bottom) { 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) { 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(); // 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) // Initialise all Bedrock instances. for (int i=0; idev.screen); // ------ EVENT LOOP ------------------------------------------------------- while (1) { 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; // 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) { 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) { input_update_gamepad(&br_sub->dev.input); input_update_touch(&br_sub->dev.input); } 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); goto rouse; } if (!br_main) { printf("SHUTTING DOWN\n"); systemShutDown(); return 0; } } }