void Tutorial::runLoop() { sf::Clock clock; float elapsedTime; float fpsElapsedTime = 0; switchClock.restart(); while (window->isOpen() && goToMenu == false){ elapsedTime = clock.getElapsedTime().asSeconds(); float fps = 1.f / elapsedTime; clock.restart(); pollEvents(); if (skipToMenuButton.getGlobalBounds().contains(mousePosition)) { //hovered skipToMenuButton.setFillColor(sf::Color(220,0,220,255)); //magenta if (leftMouseClicked) { leftMouseClicked = false; goToMenu = true; break; } } else { skipToMenuButton.setFillColor(sf::Color::Black); } switch (loopState) { case CROSSFADE: { leftMouseClicked = false; rightMouseClicked = false; // check if/why needed if (firstFadingFrame){ firstFadingFrame = false; alpha1 = 255; alpha2 = 0; } if (crossfade(elapsedTime, background[fadeIndexA], background[fadeIndexB])){ loopState = WAIT; bool goForward = fadeIndexB < fadeIndexA; if (goForward){ uint8_t temp = fadeIndexA; // swap indices fadeIndexA = fadeIndexB; fadeIndexB = temp; } else{ ++fadeIndexA; ++fadeIndexB; } } } break; case WAIT: { if (rightMouseClicked) { rightMouseClicked = false; // consume events leftMouseClicked = false; // just to be safe switchClock.restart(); if (fadeIndexB > 1){ // at second screen or higher firstFadingFrame = true; loopState = CROSSFADE; fadeIndexB -= 2; // jump to one before fadeIndexA } } else if (switchClock.getElapsedTime().asSeconds() > TIME_TO_WAIT_TILL_NEXT_SWITCH || leftMouseClicked) { if (fadeIndexB == 10) // 10 = backgroundarray size { goToMenu = true; break; } leftMouseClicked = false; // consume events //rightMouseClicked = false; // not needed because of the else if // just to be safe loopState = CROSSFADE; firstFadingFrame = true; switchClock.restart(); } } break; default: { assert(false); } break; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //draw /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// window->clear(sf::Color::White); window->draw(background[fadeIndexA]); window->draw(background[fadeIndexB]); if (fadeIndexA != 0 || loopState == CROSSFADE){ window->draw(skipToMenuButton); } window->display(); fpsElapsedTime += elapsedTime; if (fpsElapsedTime > 0.75) { std::ostringstream ss; ss.precision(4); ss << WINDOW_TITLE << fps << "fps"; window->setTitle(ss.str()); fpsElapsedTime = 0; } } }
int Narrator::script(int st, PRNG &prng) { static ChaosParticles chaosA(flow, runner.config["chaosParticles"]); static ChaosParticles chaosB(flow, runner.config["chaosParticles"]); static OrderParticles orderParticles(flow, runner.config["orderParticles"]); static Precursor precursor(flow, runner.config["precursor"]); static RingsEffect ringsA(flow, runner.config["ringsA"]); static RingsEffect ringsB(flow, runner.config["ringsB"]); static RingsEffect ringsC(flow, runner.config["ringsC"]); static PartnerDance partnerDance(flow, runner.config["partnerDance"]); static CameraFlowDebugEffect flowDebugEffect(flow, runner.config["flowDebugEffect"]); static Forest forest(flow, runner.config["forest"]); static DarknessEffect darkness; rapidjson::Value& config = runner.config["narrator"]; Sampler s(prng.uniform32()); switch (st) { ////////////////////////////////////////////////////////////////////////////////////////////// // Special states case 1: { // Darkness only ("off") crossfade(&darkness, 1); delayForever(); } case 2: { // Precursor only (sleep mode) precursor.reseed(prng.uniform32()); crossfade(&precursor, 1); delayForever(); } case 3: { // Debugging the computer vision system crossfade(&flowDebugEffect, 1); delayForever(); } ////////////////////////////////////////////////////////////////////////////////////////////// // Opening sequence case 0: { // Darkness until opening crossfade(&darkness, 1); delayUntilDate(config["opening"]["date"]); return config["opening"]["nextState"].GetInt(); } ////////////////////////////////////////////////////////////////////////////////////////////// // Cyclic states default: { endCycle(); return 10; } case 10: { // Order trying to form out of the tiniest sparks; runs for an unpredictable time, fails. precursor.reseed(prng.uniform32()); crossfade(&precursor, s.value(config["precursorCrossfade"])); // Bootstrap delay(s.value(config["precursorBootstrap"])); // Wait for darkness while (!precursor.isDone) { doFrame(); } return 20; } case 20: { // Bang. Explosive energy, hints of self-organization ChaosParticles *pChaosA = &chaosA; ChaosParticles *pChaosB = &chaosB; int bangCount = s.value(config["bangCount"]); for (int i = 0; i < bangCount; i++) { pChaosA->reseed(prng.circularVector() * s.value(config["bangSeedRadius"]), prng.uniform32()); crossfade(pChaosA, s.value(config["bangCrossfadeDuration"])); delay((1 << i) * s.value(config["bangDelayBasis"])); std::swap(pChaosA, pChaosB); } attention(s, config["bangAttention"]); return 30; } case 30: { // Textures of light, exploring something formless. Slow crossfade in ringsA.reseed(prng.uniform32()); crossfade(&ringsA, s.value(config["ringsA-Crossfade"])); attention(s, config["ringsA-Attention"]); return 40; } case 40: { // Add energy, explore another layer. ringsB.reseed(prng.uniform32()); crossfade(&ringsB, s.value(config["ringsB-Crossfade"])); attention(s, config["ringsB-Attention"]); return 50; } case 50: { // Biology happens, order emerges. Cellular look, emergent order. orderParticles.reseed(prng.uniform32()); orderParticles.symmetry = 10; crossfade(&orderParticles, s.value(config["orderCrossfade"])); while (orderParticles.symmetry > 4) { attention(s, config["orderStepAttention"]); orderParticles.symmetry--; } attention(s, config["orderStepAttention"]); return 60; } case 60: { // Two partners, populations of particles. // Spiralling inwards. Depression. Beauty on the edge of destruction, // pressing forward until nothing remains. partnerDance.reseed(prng.uniform32()); crossfade(&partnerDance, s.value(config["partnerCrossfade"])); attention(s, config["partnerAttention"]); return 70; } case 70: { // Sinking deeper. Interlude before a change. ringsC.reseed(prng.uniform32()); crossfade(&ringsC, s.value(config["ringsC-Crossfade"])); attention(s, config["ringsC-Attention"]); return 80; } case 80: { // Continuous renewal and regrowth. Destruction happens unintentionally, // regrowth is quick and generative. The only way to lose is to stagnate. forest.reseed(prng.uniform32()); crossfade(&forest, s.value(config["forestCrossfade"])); attention(s, config["forestAttention"]); return 90; } } }