void MainMenu::updateConnecting() { /* * Cubes are in the 'connectingCubes' set between when they first connect * and when they become usable for the menu. They go through three states: * * 1. Displaying the Sifteo logo. This starts in cubeConnect(), and runs on a timer. * * 2. Loading assets. We start the load itself in cubeConnect(). After the logo * finishes, we switch to displaying a progress animation. * * 3. When loading finishes, we draw an idle screen on the cube and remove it * form connectingCubes. */ SystemTime now = SystemTime::now(); /* * Look for state transitions from (1) to (2) */ CubeSet beginLoadingAnim; beginLoadingAnim.clear(); for (CubeID cube : connectingCubes & ~loadingCubes) { if ((now - Shared::connectTime[cube]).milliseconds() >= kDisplayBlueLogoTimeMS) { loadingCubes.mark(cube); beginLoadingAnim.mark(cube); } } if (!beginLoadingAnim.empty()) { loadingAnimation.begin(beginLoadingAnim); } /* * Let cubes participate in the loading animation until the whole load is done */ if (loadingCubes.empty()) { // nothing to do return; } if (!loader.isComplete()) { // Still loading, update progress loadingAnimation.paint(loadingCubes, loader.averageProgress(100)); return; } // Loading is done! loadingAnimation.end(loadingCubes); // Draw an idle screen on each cube, and remove it from connectingCubes for (CubeID cube : loadingCubes) { auto& vid = Shared::video[cube]; vid.initMode(BG0); vid.bg0.erase(Menu_StripeTile); vid.bg0.image(vec(0,0), Menu_IdleCube); connectingCubes.clear(cube); // Dispatch connected event to current applet now that the cube is ready if (itemIndexCurrent >= 0) { ASSERT(itemIndexCurrent < items.count()); MainMenuItem *item = items[itemIndexCurrent]; item->onCubeConnect(cube); // If a game was waiting on a cube to launch, try again. if (cubeRangeSavedIcon && areEnoughCubesConnected(itemIndexCurrent)) { itemIndexChoice = itemIndexCurrent; toggleCubeRangeAlert(); // remove the warning asking for more cubes } } updateCubeRangeAlert(); } loadingCubes.clear(); }
void MainMenu::eventLoop() { while (1) { // Need to bind the menu to a new cube? if (!mainCube.isDefined()) { /* * Make sure we have at least one cube. Until we do, there's nothing * we can do, so just play our "cube missing" sound periodically. * * This exits as soon as at least one cube is in CubeSet::connected(), * but that cube may still be busy loading assets or showing the logo. */ waitForACube(); /* * Wait until we have a cube that's usable for our menu */ while (1) { CubeSet usable = CubeSet::connected() & ~connectingCubes; if (usable.empty()) { System::paint(); updateMusic(); updateConnecting(); System::yield(); continue; } else { mainCube = *usable.begin(); break; } } // try and avoid some of the garbage we often see :P System::finish(); if (itemIndexCurrent >= 0) { if (itemIndexCurrent > 0 && items[itemIndexCurrent]->isFirstRun()) { initMenu(itemIndexCurrent, true, 0); } else { initMenu(itemIndexCurrent, true); } } else { initMenu(0, false); } } MenuEvent e; itemIndexChoice = -1; // Keep running until a choice is made or the menu cube disconnects while (mainCube.isDefined() && menu.pollEvent(&e)) { updateConnecting(); updateSound(); updateMusic(); updateAlerts(); handleEvent(e); } if (itemIndexChoice >= 0) { ASSERT(itemIndexChoice < items.count()); return execItem(items[itemIndexChoice]); } } }