Float2<T> Float2<T>::slerp(const Float2 &end, T percent) const { T theta = static_cast<T>(std::acos(this->dot(end) / (this->length() * end.length()))); T sinThetaRecip = static_cast<T>(1.0 / std::sin(theta)); T beginScale = static_cast<T>(std::sin((1.0 - percent) * theta) * sinThetaRecip); T endScale = std::sin(percent * theta) * sinThetaRecip; return this->scaledBy(beginScale) + end.scaledBy(endScale); }
void HotCubeCube::start() { BaseGameCube::start(); Float2 panning; panning.set(0, 0); buffer->bg1.setMask(BG1Mask::filled(vec(4,7), vec(8,2))); buffer->bg1.text(vec(4,7), BlackFont, " "); buffer->bg1.setPanning(panning); }
// compute velocity & position (cube included) and draw dot (exploded or not) void Cube::animate(Cube* cubes, const float dts) { static const float deadzone = 2.0f; static const float accelScale = 0.6f; static const float damping = 0.995f; if (lifeCounter <= 0) return; for (uint8_t d=0; d<dot_n; d++) { // if dot neither hidden nor exploded, animate it: if (not (vid.sprites[d].isHidden() || dots[d].exp)) { Float2 accel = id.accel().xy(); if (accel.len2() > deadzone * deadzone) dots[d].vel += accel * accelScale; dots[d].vel *= damping; Float2 step = dots[d].vel * dts; Float2 candidate = dots[d].pos + step; // Does this dot want to leave the cube ? Side mySide = (candidate.y < minPos.y) ? TOP : // 0 (candidate.x < minPos.x) ? LEFT : // 1 (candidate.y > maxPos.y) ? BOTTOM : // 2 (candidate.x > maxPos.x) ? RIGHT : // 3 NO_SIDE; // -1 bool stayHere = true; // default CubeID hisID; // neighbor CubeID Side hisSide = NO_SIDE; // his side number that touches mySide if (mySide != NO_SIDE) { // avoids cubeAt(NO_SIDE) error Neighborhood myNbh(id); hisID = myNbh.cubeAt(mySide); if (hisID.isDefined()) { // ...same with sideOf(NO_SIDE) Neighborhood hisNbh(hisID); hisSide = hisNbh.sideOf(id); stayHere = cubes[hisID].isFull(); } } if (stayHere) { // will this dot stay? if (mySide==TOP || mySide==BOTTOM) // bounce vertically? dots[d].vel.y = -dots[d].vel.y; if (mySide==LEFT || mySide==RIGHT) // ...horizontally? dots[d].vel.x = -dots[d].vel.x; dots[d].pos += dots[d].vel * dts; // finish calculation vid.sprites[d].setImage(DotIMG); // draw the dot vid.sprites[d].move(dots[d].pos); } else { // move to neighbor dots[d].pos += step; // finish calculation moveDot(d, cubes[hisID], mySide, hisSide); } } } collisionCheck(); displayDamages(); }
Int2 Questioner::doPanning(Int2 targetPan, int timetaken) { if(timetaken > TIME_TO_SCROLL) { myGameDrawer->doPanning(myCube, targetPan); return targetPan; } float panningPropTimeLeft = (TIME_TO_SCROLL - timetaken) / (float) TIME_TO_SCROLL; Float2 diffPan = vec((float) 0, panningPropTimeLeft * PIXEL_SCROLL); Float2 newPan = targetPan + diffPan; myGameDrawer->doPanning(myCube, newPan.round()); return newPan.round(); }
void AppSetup::onResizeWindow(const Int2& newSize) { m_inf.windowSize = newSize; Float2 newSizeF = Float2((float)newSize.width(), (float)newSize.height()); Float2 virtualSizeF = Float2((float)m_inf.virtualSize.width(), (float)m_inf.virtualSize.height()); if (m_inf.automaticFitToWindowSize && (newSize.width() != m_inf.virtualSize.width() || newSize.height() != m_inf.virtualSize.height())) { Float2 ppp(-1.f,-1.f); Int2 virtualPos(-1,-1); float ratioW = (float)newSize.width() / (float)m_inf.virtualSize.width(); float ratioH = (float)newSize.height() / (float)m_inf.virtualSize.height(); if (m_inf.virtualSizeAllowRatioDeformation) { ppp = Float2(ratioW,ratioH); virtualPos = Int2(0,0); } else if (newSizeF.width()/newSizeF.height() > virtualSizeF.width() / virtualSizeF.height()) { ppp = Float2(ratioH,ratioH); virtualPos = Int2((int)((newSizeF.width()-virtualSizeF.width()*ratioH)/2.f), 0); } else { ppp = Float2(ratioW,ratioW); virtualPos = Int2(0, (int)((newSizeF.height()-virtualSizeF.height()*ratioW)/2.f)); } this->setPixelPerPointLowLevel(ppp, virtualPos); } else { this->setPixelPerPointLowLevel(Float2(1.f,1.f), Int2(0,0)); #if defined(USES_WINDOWS_OPENGL) || defined(USES_LINUX) m_openGL->setRealWindowSize(newSize); m_openGL->set2DMode(); #else // do nothing here #endif } m_isUsingVirtualSize = (this->getPixelPerPoint() != Float2(1.f, 1.f) || this->getVirtualTopLeftCornerInWindow() != Int2(0, 0)); }
static void onTouch(void* ctxt, unsigned cube) { if(g_iCurMode & MODE_GAMEOVER && boards[cube].hasMarble()) //Tap on the "game over" cube to restart { //Play sound effect for clearing board (also board reset-- why not?) channels[BOARD_SFX_CHANNEL]->play(sBoardClear); for(int i = 0; i < NUM_CUBES; i++) { boards[i].getVid()->bg1.eraseMask(); //Wipe "game over" screen boards[i].initTilemap(); //Load a new tilemap into each boards[i].takeMarble(); } //Add marble to first cube Float2 fVel; fVel.set(0,0); Float2 fPos = LCD_center; fPos.x += TILE_WIDTH/2.0; fPos.y += TILE_HEIGHT/2.0; boards[0].addMarble(fPos, fVel); //Other starting tasks for(int i = 0; i < NUM_COLORS; i++) g_bColorsUsed[i] = false; g_iScore = -1; g_iCurMode = BOARD_NOTHING; for(int i = 0; i < NUM_CUBES; i++) g_starsCollected[i] = 0; g_iBoardReset = -1; } if(g_iCurMode & BOARD_WAITPORTAL && boards[cube].hasMarble()) //Tap on the flashy arrow cube to ignore portal { boards[cube].spitBack(); //Spit marble back out //Play sound effect for exiting a portal channels[PORTAL_CHANNEL]->play(sPortalExit); g_iCurMode = BOARD_NOTHING; for(int iCube = 0; iCube < NUM_CUBES; iCube++) { //Hide any flashy arrows boards[iCube].hideArrows(); boards[iCube].resetFlashTimer(); } } }
RGB565 calculateMandelbrot(UInt2 pixel) { /* * Calculate one pixel of a Mandelbrot fractal, * using continuous shading based on a renormalizing technique. * * Reference: http://linas.org/art-gallery/escape/escape.html */ const float radius2 = 400.f; const unsigned maxIters = 12; const float scale = 0.022f; const Int2 center = LCD_center + vec(25, 0); // We use Float2 vectors to store complex numbers Float2 z = vec(0, 0); Float2 c = (pixel - center) * scale; unsigned iters = 0; float modulus2; // Traditional Mandelbrot iteration do { z = z.cmul(z) + c; modulus2 = z.len2(); } while (++iters <= maxIters && modulus2 <= radius2); // A couple extra iterations z = z.cmul(z) + c; z = z.cmul(z) + c; iters += 2; // Continuous shading, taking into account the iteration number as well // as how far outside the escape radius we are. float mu = (iters - log(log(z.len())) / M_LN2) / maxIters; if (mu < 1.0f) { // Exterior of fractal return calculateColorPalette(mu); } else { // Interior (didn't escape within our limit, or NaN) return RGB565::fromRGB(0x000000); } }
void drawTextLayout(ID2D1DeviceContext* context, const Float2& zoomRatio, ID2D1SolidColorBrush* solidBrush, IDWriteTextLayout* textLayout, const Int2& position, const Float2& scale) { D2D1_MATRIX_3X2_F transformTmp; context->GetTransform(&transformTmp); context->SetTransform(D2D1::Matrix3x2F::Translation(zoomRatio.x() + (float)position.x() / scale.x(), zoomRatio.y() + (float)position.y() / scale.y()));// * s_ppp.x() * s_ppp.y( // TODO scale with s_ppp context->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), textLayout, solidBrush); context->SetTransform(transformTmp); }
// check distance between dots and mark them as exploded if too close void Cube::collisionCheck() { for (uint8_t i=0; i<dot_n; i++) if (not vid.sprites[i].isHidden() && !dots[i].exp) for (uint8_t j=i+1; j<dot_n; j++) if (not vid.sprites[j].isHidden() && !dots[i].exp) { Float2 dif = dots[i].pos - dots[j].pos; // are the dots too close ? if (dif.len2() < SPR_size.len2()/4) { dots[i].pos -= dif/2; // bring dots closer dots[j].pos += dif/2; // to each other dots[i].exp = exploDuration; dots[j].exp = exploDuration; #if ACCURATE == 1 // use a binary map to check if we hit or miss Conan: dots[i].bnd = isHit(dots[i].pos); dots[j].bnd = isHit(dots[j].pos); #else // ...or use a FlatAssetImage but it's less accurate: Float2 o = SPR_size/2; // offset to sprite center uint16_t linPosI = uint16_t( (dots[i].pos.x+o.x)/8 ) + uint16_t( (dots[i].pos.y+o.y)/8 ) * ConanIMG.tileWidth() ; uint16_t linPosJ = uint16_t( (dots[j].pos.x+o.x)/8 ) + uint16_t( (dots[j].pos.y+o.y)/8 ) * ConanIMG.tileWidth() ; // D'oh! need band aid ? dots[i].bnd = (ConanIMG.tile(linPosI) != whiteTile); dots[j].bnd = (ConanIMG.tile(linPosJ) != whiteTile && linPosJ != linPosI); #endif // D'oh! need band aid ? if (dots[i].bnd) lifeCounter -= 5; if (dots[j].bnd) lifeCounter -= 5; } } if (lifeCounter <= 0) win(); }
void drawLine(ID2D1DeviceContext* context, const Float2& zoomRatio, const Int2& pos1, const Int2& pos2, const Color& color, float thickness) { D2D1::ColorF colorDx(color.r() / 256.f, color.g() / 256.f, color.b() / 256.f, color.a() / 256.f); //D2D1::ColorF colorDx = D2D1::ColorF::MidnightBlue; ID2D1SolidColorBrush* solidBrush; DX::ThrowIfFailed(context->CreateSolidColorBrush(colorDx, &solidBrush)); D2D1_POINT_2F pt1; pt1.x = zoomRatio.x() + (float)pos1.x(); pt1.y = zoomRatio.y() + (float)pos1.y(); D2D1_POINT_2F pt2; pt2.x = zoomRatio.x() + (float)pos2.x(); pt2.y = zoomRatio.y() + (float)pos2.y(); context->SetTransform(D2D1::Matrix3x2F::Identity()); //s_context->SetDpi(DirectXDraw::getDefaultDpi().x(), DirectXDraw::getDefaultDpi().y()); context->DrawLine(pt1, pt2, solidBrush, thickness); solidBrush->Release(); //delete solidBrush; }
void writeScore(int i) { int maskWidth = 2; cubeVideo[cube].bg1.setMask(BG1Mask::filled(vec(0,12), vec(maskWidth * 2, 4))); text.set(-64 + maskWidth * 6, 52); String<3> bTest; bTest << Fixed(i, maskWidth, true); textTarget = text; writeText(bTest.c_str()); }
void drawRoundedRectangle(ID2D1DeviceContext* context, const Float2& zoomRatio, const Int2& posLeftTop, const Int2& posRightBottom, const Color& color, float round, float borderSize, bool fill) { D2D1::ColorF colorDx(color.r() / 256.f, color.g() / 256.f, color.b() / 256.f, color.a() / 256.f); ID2D1SolidColorBrush* solidBrush; DX::ThrowIfFailed(context->CreateSolidColorBrush(colorDx, &solidBrush)); D2D1_ROUNDED_RECT rrect; rrect.radiusX = round; rrect.radiusY = round; rrect.rect.left = zoomRatio.x() + (float)posLeftTop.x(); rrect.rect.top = zoomRatio.y() + (float)posLeftTop.y(); rrect.rect.right = zoomRatio.x() + (float)posRightBottom.x(); rrect.rect.bottom = zoomRatio.y() + (float)posRightBottom.y(); context->SetTransform(D2D1::Matrix3x2F::Identity()); if (fill) context->FillRoundedRectangle(rrect, solidBrush); //if (borderSize > 0.f) context->DrawRoundedRectangle(rrect, solidBrush, borderSize); solidBrush->Release(); //delete solidBrush; }
void update(TimeDelta timeStep) { //LOG("Update"); if (whichGame == 0) { cubeVideo[cube].bg0.image(vec(0,0), BackgroundXTwo); } else if (whichGame == 1) { cubeVideo[cube].bg0.image(vec(0,0), BackgroundYTwo); } writeScore(shakeScore); Int2 accel = cubeVideo[cube].physicalAccel().xy(); float delta; if (whichGame == 0) { delta = accel.x - lastAccel.x; } else if (whichGame == 1) { delta = accel.y - lastAccel.y; } delta = Sifteo::abs(delta); shakeCounter += delta; if (shakeCounter > 1000) { shakeCounter -= 1000; shakeScore++; } lastAccel = accel; cubeVideo[cube].bg1.setPanning(text.round()); }
void drawBitmap( ID2D1DeviceContext* context, const Float2& zoomRatio, const Float2& m_defaultDpi, ID2D1Bitmap* bitmap, const Float2& position, const Float2& scale, float opacity, D2D1_RECT_F* rectSource, D2D1_RECT_F* rectDest, float angleDegree, const Int2& rotationCenterPos, bool horizontalMirror, bool verticalMirror) { D2D1_MATRIX_3X2_F transformTmp; context->GetTransform(&transformTmp); D2D1::Matrix3x2F matTranslation = D2D1::Matrix3x2F::Translation(zoomRatio.x() + position.x(), zoomRatio.y() + position.y());// / scale.x() / scale.y() if (angleDegree != 0.f || horizontalMirror || verticalMirror) { D2D1::Matrix3x2F matMirroring = D2D1::Matrix3x2F::Scale(horizontalMirror ? -1.f : 1.f, verticalMirror ? -1.f : 1.f); D2D1_POINT_2F imageRotationCenterPos = D2D1::Point2F((float)rotationCenterPos.x(), (float)rotationCenterPos.y()); D2D1::Matrix3x2F matRotation = D2D1::Matrix3x2F::Rotation(angleDegree, imageRotationCenterPos); context->SetTransform(matMirroring * matRotation * matTranslation); } else { context->SetTransform(matTranslation);// * s_ppp.x() * s_ppp.y() } //Assert(scale.x() > 0.f && scale.y() > 0.f); // note about bitmaps: https://msdn.microsoft.com/en-us/library/windows/desktop/dd371150%28v=vs.85%29.aspx Float2 dpiBitmap; bitmap->GetDpi(&dpiBitmap.data[0], &dpiBitmap.data[1]); Float2 scaleToApply = dpiBitmap / m_defaultDpi * scale;//s_ppp * dpiBitmap / dpiContext * scale; D2D1_RECT_F rectDestFinal; if (rectDest == 0) { D2D1_SIZE_F sz = bitmap->GetSize(); rectDestFinal.left = 0.f; rectDestFinal.top = 0.f; rectDestFinal.right = sz.width * scaleToApply.x(); rectDestFinal.bottom = sz.height *scaleToApply.y(); context->DrawBitmap(bitmap, &rectDestFinal, opacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, rectSource); } else { rectDestFinal = *rectDest; rectDestFinal.left *= scaleToApply.x(); rectDestFinal.top *= scaleToApply.y(); rectDestFinal.right *= scaleToApply.x(); rectDestFinal.bottom *= scaleToApply.y(); Float2 srcScaleToApply = dpiBitmap / m_defaultDpi; D2D1_RECT_F rectSourceFinal; rectSourceFinal = *rectSource; rectSourceFinal.left /= srcScaleToApply.x(); rectSourceFinal.top /= srcScaleToApply.y(); rectSourceFinal.right /= srcScaleToApply.x(); rectSourceFinal.bottom /= srcScaleToApply.y(); context->DrawBitmap(bitmap, &rectDestFinal, opacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, &rectSourceFinal); } context->SetTransform(transformTmp);//D2D1::Matrix3x2F::Translation(0.f, 0.f)); //s_context->Flush(); }
Int2 AppSetup::getSizeOrtho2DWindow() const { Float2 ppp = this->getPixelPerPoint(); return Int2((int)((float)m_inf.windowSize.x() / ppp.x()), (int)((float)m_inf.windowSize.y() / ppp.y())); }
void main() { //Create our audio channels AudioChannel a1(0); AudioChannel a2(1); AudioChannel a3(2); AudioChannel a4(3); AudioChannel a5(4); AudioChannel a6(5); channels[0] = &a1; channels[1] = &a2; channels[2] = &a3; channels[3] = &a4; channels[4] = &a5; channels[5] = &a6; r.seed(); channels[BALL_ROLL_CHANNEL]->play(sRollLoop, REPEAT); //Start playing rolling marble noise channels[BALL_ROLL_CHANNEL]->setVolume(0); for(int i = 0; i < NUM_CUBES; i++) g_starsCollected[i] = 0; for(int i = 0; i < NUM_COLORS; i++) g_bColorsUsed[i] = false; g_iBoardReset = -1; g_iScore = -1; TimeStep ts; float fTapPromptDelay = 0.0; int iBoardDied; //Initialize our boards for(int i = 0; i < NUM_CUBES; i++) boards[i].init(i); Events::neighborAdd.set(onNeighborAdd); //Function for when two cubes touch each other Events::cubeTouch.set(onTouch); //Function for when a cube is tapped //Add the marble to one of them Float2 fVel; fVel.set(0,0); Float2 fPos = LCD_center; fPos.x += TILE_WIDTH/2.0; fPos.y += TILE_HEIGHT/2.0; boards[0].addMarble(fPos, fVel); TextDraw td; bool bFirstSound = true; //Main loop while (1) { ts.next(); for(int i = 0; i < NUM_CUBES; i++) { int iMode; switch(g_iCurMode) { case BOARD_NOTHING: iMode = boards[i].update(float(ts.delta())); //Update our rolling sound to the right volume if(boards[i].hasMarble()) { float fVol = boards[i].getMarbleVelocity() * 0.9; if(fVol > MAX_VOLUME) fVol = MAX_VOLUME; channels[BALL_ROLL_CHANNEL]->setVolume(fVol); } if(iMode & BOARD_GOTPOINT) { iMode ^= BOARD_GOTPOINT; g_iScore++; if(++g_starsCollected[i] == NUM_STARS_CUBE) g_iBoardReset = i; //Play sound for getting a star, but not right on reset if(bFirstSound) bFirstSound = false; else channels[BALL_SFX_CHANNEL]->play(sGetStar); } if(iMode & BOARD_DIED) { //Show game over screen iMode ^= BOARD_DIED; iMode |= MODE_GAMEOVER; td.draw(boards[i].getVid(), "Game over", 6); String<64> s; s << "Score: " << g_iScore; td.draw(boards[i].getVid(), s.c_str(), 8); fTapPromptDelay = 0.0; iBoardDied = i; bFirstSound = true; channels[BALL_ROLL_CHANNEL]->setVolume(0); channels[BALL_SFX_CHANNEL]->play(sDie); } if(iMode & BOARD_LEFT) { iMode ^= BOARD_LEFT; if(g_iBoardReset == i) { boards[i].reset(g_bColorsUsed); g_starsCollected[i] = 0; g_iBoardReset = -1; g_iScore += 3; //Three points for clearing board //Play sound effect for clearing board channels[BOARD_SFX_CHANNEL]->play(sBoardClear); } //Play pass-through-portal sound else if(!channels[PORTAL_CHANNEL]->isPlaying()) channels[PORTAL_CHANNEL]->play(sThroughPortal); } if(iMode & BOARD_WAITPORTAL) { //Play sound effect for entering a portal channels[PORTAL_CHANNEL]->play(sPortalEnter); channels[BALL_ROLL_CHANNEL]->setVolume(0); } g_iCurMode = iMode; break; case BOARD_WAITPORTAL: boards[i].waitPortal(float(ts.delta())); channels[BALL_ROLL_CHANNEL]->setVolume(0); break; case MODE_GAMEOVER: fTapPromptDelay += float(ts.delta()) / 3.0; if(fTapPromptDelay >= TAP_PROMPT_DELAY && fTapPromptDelay < 100.0) { fTapPromptDelay = 100; td.draw(boards[iBoardDied].getVid(), "Tap to restart", 14); } channels[BALL_ROLL_CHANNEL]->setVolume(0); } } System::paint(); } }
void Renderer::fitViewNearFarToObjects(Float2& near_far, const Float4x4& view, const float near_min, const float far_max, const bool inc_light_vols) const { near_far.set(near_min, far_max); return; // Note, the fitting is NOT tight. Firstly, we're using the geometry's // axis aligned bounding box, which is not tight (after the model // transform) then we're assuming the size of the box is maximum after // rotation into the camera space (which is also not tight). // Recall: OpenGL convention is to look down the negative Z axis, // therefore, more negative values are actually further away. near_far[0] = -std::numeric_limits<float>::infinity(); // znear near_far[1] = std::numeric_limits<float>::infinity(); // zfar float min_z, max_z; gm_->renderStackReset(); while (!gm_->renderStackEmpty()) { GeometryInstance* cur_geometry = gm_->renderStackPop(); AABBox* aabbox = cur_geometry->aabbox(); if (aabbox) { aabbox->calcMinMaxZBoundInViewSpace(min_z, max_z, view); if (max_z < near_far[1]) { near_far[1] = max_z; } if (min_z > near_far[0]) { near_far[0] = min_z; } } } // Also fit to light geometry: if (inc_light_vols) { Float3 pos_source; Float3 dir; float rad; Float3 center_view; LightPoint* light_point; LightSpot* light_spot; for (uint32_t i = 0; i < lighting_->lights().size(); i++) { switch (lighting_->lights()[i]->type()) { case LIGHT_POINT: light_point = (LightPoint*)(lighting_->lights()[i]); // Calculate model view projection matrix Float3::affineTransformPos(center_view, view, light_point->pos_world()); rad = light_point->outside_rad(); if ((center_view[2] - rad) < near_far[1]) { near_far[1] = center_view[2] - rad; } if ((center_view[2] + rad) > near_far[0]) { near_far[0] = center_view[2] + rad; } break; case LIGHT_SPOT_VSM: case LIGHT_SPOT: light_spot = (LightSpot*)(lighting_->lights()[i]); // Check the source point Float3::affineTransformPos(pos_source, view, light_spot->pos_world()); if (pos_source[2] < near_far[1]) { near_far[1] = pos_source[2]; } if (pos_source[2] > near_far[0]) { near_far[0] = pos_source[2]; } // Now check the cone end Float3::affineTransformPos(center_view, view, light_spot->cone_center_world()); rad = light_spot->cone_outside_radius(); if ((center_view[2] - rad) < near_far[1]) { near_far[1] = center_view[2] - rad; } if ((center_view[2] + rad) > near_far[0]) { near_far[0] = center_view[2] + rad; } break; default: break; } } } near_far[0] += LOOSE_EPSILON; near_far[1] -= LOOSE_EPSILON; // now clamp the near and far to the user defined values if (near_far[0] > near_min) { near_far[0] = near_min; } if (near_far[1] < far_max) { near_far[1] = far_max; } if (near_far[1] > near_far[0]) { near_far[1] = near_far[0] - 0.1f; } }