aboutsummaryrefslogtreecommitdiff
path: root/arm9/source/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm9/source/main.c')
-rw-r--r--arm9/source/main.c168
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;
}