Home | History | Annotate | Download | only in raw
      1 #pragma version(1)
      2 #pragma stateVertex(PV)
      3 #pragma stateFragment(PFTexNearest)
      4 #pragma stateStore(PSIcons)
      5 
      6 #define PI 3.14159f
      7 
      8 int g_SpecialHWWar;
      9 
     10 // Attraction to center values from page edge to page center.
     11 float g_AttractionTable[9];
     12 float g_FrictionTable[9];
     13 float g_PhysicsTableSize;
     14 
     15 float g_PosPage;
     16 float g_PosVelocity;
     17 float g_LastPositionX;
     18 int g_LastTouchDown;
     19 float g_DT;
     20 int g_LastTime;
     21 int g_PosMax;
     22 float g_Zoom;
     23 float g_Animation;
     24 float g_OldPosPage;
     25 float g_OldPosVelocity;
     26 float g_OldZoom;
     27 float g_MoveToTotalTime;
     28 float g_MoveToTime;
     29 float g_MoveToOldPos;
     30 
     31 int g_Cols;
     32 int g_Rows;
     33 
     34 // Drawing constants, should be parameters ======
     35 #define VIEW_ANGLE 1.28700222f
     36 
     37 int g_DrawLastFrame;
     38 int lastFrame(int draw) {
     39     // We draw one extra frame to work around the last frame post bug.
     40     // We also need to track if we drew the last frame to deal with large DT
     41     // in the physics.
     42     int ret = g_DrawLastFrame | draw;
     43     g_DrawLastFrame = draw;
     44     return ret;  // should return draw instead.
     45 }
     46 
     47 void updateReadback() {
     48     if ((g_OldPosPage != g_PosPage) ||
     49         (g_OldPosVelocity != g_PosVelocity) ||
     50         (g_OldZoom != g_Zoom)) {
     51 
     52         g_OldPosPage = g_PosPage;
     53         g_OldPosVelocity = g_PosVelocity;
     54         g_OldZoom = g_Zoom;
     55 
     56         int i[3];
     57         i[0] = g_PosPage * (1 << 16);
     58         i[1] = g_PosVelocity * (1 << 16);
     59         i[2] = g_OldZoom * (1 << 16);
     60         sendToClient(&i[0], 1, 12, 1);
     61     }
     62 }
     63 
     64 void setColor(float r, float g, float b, float a) {
     65     if (g_SpecialHWWar) {
     66         color(0, 0, 0, 0.001f);
     67     } else {
     68         color(r, g, b, a);
     69     }
     70 }
     71 
     72 void init() {
     73     g_AttractionTable[0] = 20.0f;
     74     g_AttractionTable[1] = 20.0f;
     75     g_AttractionTable[2] = 20.0f;
     76     g_AttractionTable[3] = 10.0f;
     77     g_AttractionTable[4] = -10.0f;
     78     g_AttractionTable[5] = -20.0f;
     79     g_AttractionTable[6] = -20.0f;
     80     g_AttractionTable[7] = -20.0f;
     81     g_AttractionTable[8] = -20.0f;  // dup 7 to avoid a clamp later
     82     g_FrictionTable[0] = 10.0f;
     83     g_FrictionTable[1] = 10.0f;
     84     g_FrictionTable[2] = 11.0f;
     85     g_FrictionTable[3] = 15.0f;
     86     g_FrictionTable[4] = 15.0f;
     87     g_FrictionTable[5] = 11.0f;
     88     g_FrictionTable[6] = 10.0f;
     89     g_FrictionTable[7] = 10.0f;
     90     g_FrictionTable[8] = 10.0f;  // dup 7 to avoid a clamp later
     91     g_PhysicsTableSize = 7;
     92 
     93     g_PosVelocity = 0;
     94     g_PosPage = 0;
     95     g_LastTouchDown = 0;
     96     g_LastPositionX = 0;
     97     g_Zoom = 0;
     98     g_Animation = 1.f;
     99     g_SpecialHWWar = 1;
    100     g_MoveToTime = 0;
    101     g_MoveToOldPos = 0;
    102     g_MoveToTotalTime = 0.2f; // Duration of scrolling 1 line
    103 }
    104 
    105 void resetHWWar() {
    106     g_SpecialHWWar = 1;
    107 }
    108 
    109 void move() {
    110     if (g_LastTouchDown) {
    111         float dx = -(state->newPositionX - g_LastPositionX);
    112         g_PosVelocity = 0;
    113         g_PosPage += dx * 5.2f;
    114 
    115         float pmin = -0.49f;
    116         float pmax = g_PosMax + 0.49f;
    117         g_PosPage = clampf(g_PosPage, pmin, pmax);
    118     }
    119     g_LastTouchDown = state->newTouchDown;
    120     g_LastPositionX = state->newPositionX;
    121     g_MoveToTime = 0;
    122     //debugF("Move P", g_PosPage);
    123 }
    124 
    125 void moveTo() {
    126     g_MoveToTime = g_MoveToTotalTime;
    127     g_PosVelocity = 0;
    128     g_MoveToOldPos = g_PosPage;
    129 
    130 	// debugF("======= moveTo", state->targetPos);
    131 }
    132 
    133 void setZoom() {
    134     g_Zoom = state->zoomTarget;
    135     g_DrawLastFrame = 1;
    136     updateReadback();
    137 }
    138 
    139 void fling() {
    140     g_LastTouchDown = 0;
    141     g_PosVelocity = -state->flingVelocity * 4;
    142     float av = fabsf(g_PosVelocity);
    143     float minVel = 3.5f;
    144 
    145     minVel *= 1.f - (fabsf(fracf(g_PosPage + 0.5f) - 0.5f) * 0.45f);
    146 
    147     if (av < minVel && av > 0.2f) {
    148         if (g_PosVelocity > 0) {
    149             g_PosVelocity = minVel;
    150         } else {
    151             g_PosVelocity = -minVel;
    152         }
    153     }
    154 
    155     if (g_PosPage <= 0) {
    156         g_PosVelocity = maxf(0, g_PosVelocity);
    157     }
    158     if (g_PosPage > g_PosMax) {
    159         g_PosVelocity = minf(0, g_PosVelocity);
    160     }
    161 }
    162 
    163 float
    164 modf(float x, float y)
    165 {
    166     return x-(y*floorf(x/y));
    167 }
    168 
    169 
    170 /*
    171  * Interpolates values in the range 0..1 to a curve that eases in
    172  * and out.
    173  */
    174 float
    175 getInterpolation(float input) {
    176     return (cosf((input + 1) * PI) / 2.0f) + 0.5f;
    177 }
    178 
    179 
    180 void updatePos() {
    181     if (g_LastTouchDown) {
    182         return;
    183     }
    184 
    185     float tablePosNorm = fracf(g_PosPage + 0.5f);
    186     float tablePosF = tablePosNorm * g_PhysicsTableSize;
    187     int tablePosI = tablePosF;
    188     float tablePosFrac = tablePosF - tablePosI;
    189     float accel = lerpf(g_AttractionTable[tablePosI],
    190                         g_AttractionTable[tablePosI + 1],
    191                         tablePosFrac) * g_DT;
    192     float friction = lerpf(g_FrictionTable[tablePosI],
    193                         g_FrictionTable[tablePosI + 1],
    194                         tablePosFrac) * g_DT;
    195 
    196     if (g_MoveToTime) {
    197         // New position is old posiition + (total distance) * (interpolated time)
    198         g_PosPage = g_MoveToOldPos + (state->targetPos - g_MoveToOldPos) * getInterpolation((g_MoveToTotalTime - g_MoveToTime) / g_MoveToTotalTime);
    199         g_MoveToTime -= g_DT;
    200         if (g_MoveToTime <= 0) {
    201             g_MoveToTime = 0;
    202             g_PosPage = state->targetPos;
    203         }
    204         return;
    205     }
    206 
    207     // If our velocity is low OR acceleration is opposing it, apply it.
    208     if (fabsf(g_PosVelocity) < 4.0f || (g_PosVelocity * accel) < 0) {
    209         g_PosVelocity += accel;
    210     }
    211     //debugF("g_PosPage", g_PosPage);
    212     //debugF("  g_PosVelocity", g_PosVelocity);
    213     //debugF("  friction", friction);
    214     //debugF("  accel", accel);
    215 
    216     // Normal physics
    217     if (g_PosVelocity > 0) {
    218         g_PosVelocity -= friction;
    219         g_PosVelocity = maxf(g_PosVelocity, 0);
    220     } else {
    221         g_PosVelocity += friction;
    222         g_PosVelocity = minf(g_PosVelocity, 0);
    223     }
    224 
    225     if ((friction > fabsf(g_PosVelocity)) && (friction > fabsf(accel))) {
    226         // Special get back to center and overcome friction physics.
    227         float t = tablePosNorm - 0.5f;
    228         if (fabsf(t) < (friction * g_DT)) {
    229             // really close, just snap
    230             g_PosPage = roundf(g_PosPage);
    231             g_PosVelocity = 0;
    232         } else {
    233             if (t > 0) {
    234                 g_PosVelocity = -friction;
    235             } else {
    236                 g_PosVelocity = friction;
    237             }
    238         }
    239     }
    240 
    241     // Check for out of boundry conditions.
    242     if (g_PosPage < 0 && g_PosVelocity < 0) {
    243         float damp = 1.0 + (g_PosPage * 4);
    244         damp = clampf(damp, 0.f, 0.9f);
    245         g_PosVelocity *= damp;
    246     }
    247     if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
    248         float damp = 1.0 - ((g_PosPage - g_PosMax) * 4);
    249         damp = clampf(damp, 0.f, 0.9f);
    250         g_PosVelocity *= damp;
    251     }
    252 
    253     g_PosPage += g_PosVelocity * g_DT;
    254     g_PosPage = clampf(g_PosPage, -0.49, g_PosMax + 0.49);
    255 }
    256 
    257 
    258 void
    259 draw_home_button()
    260 {
    261     setColor(1.0f, 1.0f, 1.0f, 1.0f);
    262     bindTexture(NAMED_PFTexNearest, 0, state->homeButtonId);
    263 
    264     float w = getWidth();
    265     float h = getHeight();
    266 
    267     float x;
    268     float y;
    269     if (getWidth() > getHeight()) {
    270         x = w - (params->homeButtonTextureWidth * (1 - g_Animation)) + 20;
    271         y = (h - params->homeButtonTextureHeight) * 0.5f;
    272     } else {
    273         x = (w - params->homeButtonTextureWidth) / 2;
    274         y = -g_Animation * params->homeButtonTextureHeight;
    275         y -= 30; // move the house to the edge of the screen as it doesn't fill the texture.
    276     }
    277 
    278     drawSpriteScreenspace(x, y, 0, params->homeButtonTextureWidth, params->homeButtonTextureHeight);
    279 }
    280 
    281 void drawFrontGrid(float rowOffset, float p)
    282 {
    283     float h = getHeight();
    284     float w = getWidth();
    285 
    286     int intRowOffset = rowOffset;
    287     float rowFrac = rowOffset - intRowOffset;
    288     float colWidth = 120.f;//getWidth() / 4;
    289     float rowHeight = colWidth + 25.f;
    290     float yoff = 0.5f * h + 1.5f * rowHeight;
    291 
    292     int row, col;
    293     int colCount = 4;
    294     if (w > h) {
    295         colCount = 6;
    296         rowHeight -= 12.f;
    297         yoff = 0.47f * h + 1.0f * rowHeight;
    298     }
    299 
    300     int iconNum = (intRowOffset - 5) * colCount;
    301 
    302 
    303     bindProgramVertex(NAMED_PVCurve);
    304 
    305     vpConstants->Position.z = p;
    306 
    307     setColor(1.0f, 1.0f, 1.0f, 1.0f);
    308     for (row = -5; row < 15; row++) {
    309         float y = yoff - ((-rowFrac + row) * rowHeight);
    310 
    311         for (col=0; col < colCount; col++) {
    312             if (iconNum >= state->iconCount) {
    313                 return;
    314             }
    315 
    316             if (iconNum >= 0) {
    317                 float x = colWidth * col + (colWidth / 2);
    318                 vpConstants->Position.x = x + 0.2f;
    319 
    320                 if (state->selectedIconIndex == iconNum && !p) {
    321                     bindProgramFragment(NAMED_PFTexNearest);
    322                     bindTexture(NAMED_PFTexNearest, 0, state->selectedIconTexture);
    323                     vpConstants->ImgSize.x = SELECTION_TEXTURE_WIDTH_PX;
    324                     vpConstants->ImgSize.y = SELECTION_TEXTURE_HEIGHT_PX;
    325                     vpConstants->Position.y = y - (SELECTION_TEXTURE_HEIGHT_PX - ICON_TEXTURE_HEIGHT_PX) * 0.5f;
    326                     drawSimpleMesh(NAMED_SMCell);
    327                 }
    328 
    329                 bindProgramFragment(NAMED_PFTexMip);
    330                 vpConstants->ImgSize.x = ICON_TEXTURE_WIDTH_PX;
    331                 vpConstants->ImgSize.y = ICON_TEXTURE_HEIGHT_PX;
    332                 vpConstants->Position.y = y - 0.2f;
    333                 bindTexture(NAMED_PFTexMip, 0, loadI32(ALLOC_ICON_IDS, iconNum));
    334                 drawSimpleMesh(NAMED_SMCell);
    335 
    336                 bindProgramFragment(NAMED_PFTexMipAlpha);
    337                 vpConstants->ImgSize.x = 120.f;
    338                 vpConstants->ImgSize.y = 64.f;
    339                 vpConstants->Position.y = y - 64.f - 0.2f;
    340                 bindTexture(NAMED_PFTexMipAlpha, 0, loadI32(ALLOC_LABEL_IDS, iconNum));
    341                 drawSimpleMesh(NAMED_SMCell);
    342             }
    343             iconNum++;
    344         }
    345     }
    346 }
    347 
    348 
    349 int
    350 main(int launchID)
    351 {
    352     // Compute dt in seconds.
    353     int newTime = uptimeMillis();
    354     g_DT = (newTime - g_LastTime) / 1000.f;
    355     g_LastTime = newTime;
    356 
    357     if (!g_DrawLastFrame) {
    358         // If we stopped rendering we cannot use DT.
    359         // assume 30fps in this case.
    360         g_DT = 0.033f;
    361     }
    362     // physics may break if DT is large.
    363     g_DT = minf(g_DT, 0.2f);
    364 
    365     if (g_Zoom != state->zoomTarget) {
    366         float dz = g_DT * 1.7f;
    367         if (state->zoomTarget < 0.5f) {
    368             dz = -dz;
    369         }
    370         if (fabsf(g_Zoom - state->zoomTarget) < fabsf(dz)) {
    371             g_Zoom = state->zoomTarget;
    372         } else {
    373             g_Zoom += dz;
    374         }
    375         updateReadback();
    376     }
    377     g_Animation = powf(1-g_Zoom, 3);
    378 
    379     // Set clear value to dim the background based on the zoom position.
    380     if ((g_Zoom < 0.001f) && (state->zoomTarget < 0.001f) && !g_SpecialHWWar) {
    381         pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    382         // When we're zoomed out and not tracking motion events, reset the pos to 0.
    383         if (!g_LastTouchDown) {
    384             g_PosPage = 0;
    385         }
    386         return lastFrame(0);
    387     } else {
    388         pfClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
    389     }
    390 
    391     // icons & labels
    392     int iconCount = state->iconCount;
    393     if (getWidth() > getHeight()) {
    394         g_Cols = 6;
    395         g_Rows = 3;
    396     } else {
    397         g_Cols = 4;
    398         g_Rows = 4;
    399     }
    400     g_PosMax = ((iconCount + (g_Cols-1)) / g_Cols) - g_Rows;
    401     if (g_PosMax < 0) g_PosMax = 0;
    402 
    403     updatePos();
    404     updateReadback();
    405 
    406     //debugF("    draw g_PosPage", g_PosPage);
    407 
    408     // Draw the icons ========================================
    409     drawFrontGrid(g_PosPage, g_Animation);
    410 
    411     bindProgramFragment(NAMED_PFTexNearest);
    412     draw_home_button();
    413 
    414     // This is a WAR to do a rendering pass without drawing during init to
    415     // force the driver to preload and compile its shaders.
    416     // Without this the first animation does not appear due to the time it
    417     // takes to init the driver state.
    418     if (g_SpecialHWWar) {
    419         g_SpecialHWWar = 0;
    420         return 1;
    421     }
    422 
    423     // Bug workaround where the last frame is not always displayed
    424     // So we keep rendering until the bug is fixed.
    425     return lastFrame((g_PosVelocity != 0) || fracf(g_PosPage) || g_Zoom != state->zoomTarget || (g_MoveToTime != 0));
    426 }
    427 
    428