static void inline
fxHorizontalFoldsModelStepObject(CompWindow * w,
				 Model * model,
				 Object * object,
				 float forwardProgress,
				 float sinForProg, float foldMaxAmp, int rowNo)
{
	ANIM_WINDOW(w);

	float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x -
				     w->output.left) * model->scale.x;
	float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y -
				     w->output.top) * model->scale.y;

	object->position.x = origx;

	if (aw->com.curWindowEvent == WindowEventShade ||
	    aw->com.curWindowEvent == WindowEventUnshade) {
		// Execute shade mode

		float relDistToFoldCenter = (rowNo % 2 == 1 ? 0.5 : 0);

		if (object->gridPosition.y == 0) {
			object->position.y = WIN_Y(w);
			object->position.z = 0;
		} else if (object->gridPosition.y == 1) {
			object->position.y =
			    (1 - forwardProgress) * origy +
			    forwardProgress *
			    (WIN_Y(w) + model->topHeight + model->bottomHeight);
			object->position.z = 0;
		} else {
			object->position.y =
			    (1 - forwardProgress) * origy +
			    forwardProgress * (WIN_Y(w) + model->topHeight);
			object->position.z =
			    getObjectZ(model, forwardProgress, sinForProg,
				       relDistToFoldCenter, foldMaxAmp);
		}
	} else {
		// Execute normal mode

		float relDistToFoldCenter;

		relDistToFoldCenter = (rowNo % 2 == 0 ? 0.5 : 0);

		object->position.y =
		    (1 - forwardProgress) * origy +
		    forwardProgress * (BORDER_Y(w) + BORDER_H(w) / 2.0);
		object->position.z =
		    getObjectZ(model, forwardProgress, sinForProg,
			       relDistToFoldCenter, foldMaxAmp);
	}
}
void fxHorizontalFoldsModelStep(CompWindow * w, float time)
{
	defaultAnimStep(w, time);

	ANIM_WINDOW(w);

	Model *model = aw->com.model;

	float winHeight = 0;
	if (aw->com.curWindowEvent == WindowEventShade ||
	    aw->com.curWindowEvent == WindowEventUnshade) {
		winHeight = (w)->height;
	} else {
		winHeight = BORDER_H(w);
	}
	int nHalfFolds =
	    2.0 * animGetI(w, ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS);
	float foldMaxAmp =
	    0.3 * pow((winHeight / nHalfFolds) / w->screen->height, 0.3) *
	    animGetF(w, ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_AMP_MULT);

	float forwardProgress = getProgressAndCenter(w, NULL);

	float sinForProg = sin(forwardProgress * M_PI / 2);

	Object *object = model->objects;
	int i;
	for (i = 0; i < model->numObjects; i++, object++)
		fxHorizontalFoldsModelStepObject(w,
						 model,
						 object,
						 forwardProgress,
						 sinForProg,
						 foldMaxAmp,
						 i / model->gridWidth);
}
Bool
fxDominoInit (CompWindow * w)
{
    if (!polygonsAnimInit (w))
	return FALSE;

    ANIMADDON_DISPLAY (w->screen->display);
    ANIMADDON_WINDOW (w);

    Bool isRazr = (aw->com->curAnimEffect == AnimEffectRazr);

    int fallDir;

    if (isRazr)
	fallDir = ad->animBaseFunctions->getActualAnimDirection
	    (w, animGetI (w, ANIMADDON_SCREEN_OPTION_RAZR_DIRECTION), TRUE);
    else
	fallDir = ad->animBaseFunctions->getActualAnimDirection
	    (w, animGetI (w, ANIMADDON_SCREEN_OPTION_DOMINO_DIRECTION), TRUE);

    int defaultGridSize = 20;
    float minCellSize = 30;
    int gridSizeX;
    int gridSizeY;
    int fallDirGridSize;
    float minDistStartEdge;		// half piece size in [0,1] range
    float gridCellW;
    float gridCellH;
    float cellAspectRatio = 1.25;

    if (isRazr)
	cellAspectRatio = 1;

    // Determine sensible domino piece sizes
    if (fallDir == AnimDirectionDown || fallDir == AnimDirectionUp)
    {
	if (minCellSize > BORDER_W(w))
	    minCellSize = BORDER_W(w);
	if (BORDER_W(w) / defaultGridSize < minCellSize)
	    gridSizeX = (int)(BORDER_W(w) / minCellSize);
	else
	    gridSizeX = defaultGridSize;
	gridCellW = BORDER_W(w) / gridSizeX;
	gridSizeY = (int)(BORDER_H(w) / (gridCellW * cellAspectRatio));
	if (gridSizeY == 0)
	    gridSizeY = 1;
	gridCellH = BORDER_H(w) / gridSizeY;
	fallDirGridSize = gridSizeY;
    }
    else
    {
	if (minCellSize > BORDER_H(w))
	    minCellSize = BORDER_H(w);
	if (BORDER_H(w) / defaultGridSize < minCellSize)
	    gridSizeY = (int)(BORDER_H(w) / minCellSize);
	else
	    gridSizeY = defaultGridSize;
	gridCellH = BORDER_H(w) / gridSizeY;
	gridSizeX = (int)(BORDER_W(w) / (gridCellH * cellAspectRatio));
	if (gridSizeX == 0)
	    gridSizeX = 1;
	gridCellW = BORDER_W(w) / gridSizeX;
	fallDirGridSize = gridSizeX;
    }
    minDistStartEdge = (1.0 / fallDirGridSize) / 2;

    float thickness = MIN(gridCellW, gridCellH) / 3.5;

    if (!tessellateIntoRectangles(w, gridSizeX, gridSizeY, thickness))
	return FALSE;

    float rotAxisX = 0;
    float rotAxisY = 0;
    Point3d rotAxisOff = { 0, 0, thickness / 2 };
    float posX = 0;				// position of standing piece
    float posY = 0;
    float posZ = 0;
    int nFallingColumns = gridSizeX;
    float gridCellHalfW = gridCellW / 2;
    float gridCellHalfH = gridCellH / 2;

    switch (fallDir)
    {
    case AnimDirectionDown:
	rotAxisX = -1;
	if (isRazr)
	    rotAxisOff.y = -gridCellHalfH;
	else
	{
	    posY = -(gridCellHalfH + thickness);
	    posZ = gridCellHalfH - thickness / 2;
	}
	break;
    case AnimDirectionLeft:
	rotAxisY = -1;
	if (isRazr)
	    rotAxisOff.x = gridCellHalfW;
	else
	{
	    posX = gridCellHalfW + thickness;
	    posZ = gridCellHalfW - thickness / 2;
	}
	nFallingColumns = gridSizeY;
	break;
    case AnimDirectionUp:
	rotAxisX = 1;
	if (isRazr)
	    rotAxisOff.y = gridCellHalfH;
	else
	{
	    posY = gridCellHalfH + thickness;
	    posZ = gridCellHalfH - thickness / 2;
	}
	break;
    case AnimDirectionRight:
	rotAxisY = 1;
	if (isRazr)
	    rotAxisOff.x = -gridCellHalfW;
	else
	{
	    posX = -(gridCellHalfW + thickness);
	    posZ = gridCellHalfW - thickness / 2;
	}
	nFallingColumns = gridSizeY;
	break;
    }

    float fadeDuration;
    float riseDuration;
    float riseTimeRandMax = 0.2;

    if (isRazr)
    {
	riseDuration = (1 - riseTimeRandMax) / fallDirGridSize;
	fadeDuration = riseDuration / 2;
    }
    else
    {
	fadeDuration = 0.18;
	riseDuration = 0.2;
    }
    float *riseTimeRandSeed = calloc(nFallingColumns, sizeof(float));

    if (!riseTimeRandSeed)
	// TODO: log error here
	return FALSE;
    int i;

    for (i = 0; i < nFallingColumns; i++)
	riseTimeRandSeed[i] = RAND_FLOAT();

    PolygonSet *pset = aw->eng.polygonSet;
    PolygonObject *p = pset->polygons;

    for (i = 0; i < pset->nPolygons; i++, p++)
    {
	p->rotAxis.x = rotAxisX;
	p->rotAxis.y = rotAxisY;
	p->rotAxis.z = 0;

	p->finalRelPos.x = posX;
	p->finalRelPos.y = posY;
	p->finalRelPos.z = posZ;

	// dist. from rise-start / fall-end edge in window ([0,1] range)
	float distStartEdge = 0;

	// dist. from edge perpendicular to movement (for move start time)
	// so that same the blocks in same row/col. appear to knock down
	// the next one
	float distPerpEdge = 0;

	switch (fallDir)
	{
	case AnimDirectionUp:
	    distStartEdge = p->centerRelPos.y;
	    distPerpEdge = p->centerRelPos.x;
	    break;
	case AnimDirectionRight:
	    distStartEdge = 1 - p->centerRelPos.x;
	    distPerpEdge = p->centerRelPos.y;
	    break;
	case AnimDirectionDown:
	    distStartEdge = 1 - p->centerRelPos.y;
	    distPerpEdge = p->centerRelPos.x;
	    break;
	case AnimDirectionLeft:
	    distStartEdge = p->centerRelPos.x;
	    distPerpEdge = p->centerRelPos.y;
	    break;
	}

	float riseTimeRand =
	    riseTimeRandSeed[(int)(distPerpEdge * nFallingColumns)] *
	    riseTimeRandMax;

	p->moveDuration = riseDuration;

	float mult = 1;
	if (fallDirGridSize > 1)
	    mult = ((distStartEdge - minDistStartEdge) /
		    (1 - 2 * minDistStartEdge));
	if (isRazr)
	{
	    p->moveStartTime =
		mult *
		(1 - riseDuration - riseTimeRandMax) + riseTimeRand;
	    p->fadeStartTime = p->moveStartTime + riseDuration / 2;
	    p->finalRotAng = -180;

	    p->rotAxisOffset.x = rotAxisOff.x;
	    p->rotAxisOffset.y = rotAxisOff.y;
	    p->rotAxisOffset.z = rotAxisOff.z;
	}
	else
	{
	    p->moveStartTime =
		mult *
		(1 - riseDuration - riseTimeRandMax) +
		riseTimeRand;
	    p->fadeStartTime =
		p->moveStartTime + riseDuration - riseTimeRand + 0.03;
	    p->finalRotAng = -90;
	}
	if (p->fadeStartTime > 1 - fadeDuration)
	    p->fadeStartTime = 1 - fadeDuration;
	p->fadeDuration = fadeDuration;
    }
    free(riseTimeRandSeed);
    pset->doDepthTest = TRUE;
    pset->doLighting = TRUE;
    pset->correctPerspective = CorrectPerspectivePolygon;

    aw->com->animTotalTime /= DOMINO_PERCEIVED_T;
    aw->com->animRemainingTime = aw->com->animTotalTime;

    return TRUE;
}
// Divide the window in 8 polygons (6 quadrilaters and 2 triangles (all of them draw as quadrilaters))
// Based on tessellateIntoRectangles and tessellateIntoHexagons. Improperly called tessellation.
static Bool
tessellateIntoAirplane (CompWindow * w)
{
    ANIMADDON_WINDOW (w);

    PolygonSet *pset = aw->eng.polygonSet;

    if (!pset)
	return FALSE;

    float winLimitsX;		// boundaries of polygon tessellation
    float winLimitsY;
    float winLimitsW;
    float winLimitsH;

    winLimitsX = BORDER_X (w);
    winLimitsY = BORDER_Y (w);
    winLimitsW = BORDER_W (w);
    winLimitsH = BORDER_H (w);

    int numpol = 8;
    if (pset->nPolygons != numpol)
    {
	if (pset->nPolygons > 0)
	    freePolygonObjects (pset);

	pset->nPolygons = numpol;

	pset->polygons = calloc (pset->nPolygons, sizeof (PolygonObject));
	if (!pset->polygons)
	{
	    compLogMessage ("animationaddon", CompLogLevelError,
			    "Not enough memory");
	    pset->nPolygons = 0;
	    return FALSE;
	}
    }

    float thickness = 0;
    thickness /= w->screen->width;
    pset->thickness = thickness;
    pset->nTotalFrontVertices = 0;

    float W = (float)winLimitsW;
    float H2 = (float)winLimitsH / 2;
    float H3 = (float)winLimitsH / 3;
    float H6 = (float)winLimitsH / 6;
    float halfThick = pset->thickness / 2;

    /**
     *
     * These correspond to the polygons:
     * based on GLUT sample origami.c code by Mark J. Kilgard
     *                  
     *       |-               W              -| 
     *       |-    H2     -|
     *
     * - --  +----+--------+------------------+
     * |     |    |       /                   |
     *       |    | 6   /                     | 
     *       | 7  |   /              5        |
     *   H2  |    | +                         |
     *       |    +--------+------------------+
     *       |  /                 4           |
     * H __  |/____________.__________________|
     *       |\          center               |
     *       |  \                 3           |
     *       |    +--------+------------------+
     *       |    | +                         |
     *       | 0  |   \                       |
     *       |    |  1  \            2        |  
     * |     |    |       \                   |
     * -     +----+--------+------------------+
     *
     *
     */

    PolygonObject *p = pset->polygons;
    int i;

    for (i = 0; i < 8; i++, p++)
    {
	float topRightY, topLeftY, bottomLeftY, bottomRightY;
	float topLeftX, topRightX, bottomLeftX, bottomRightX;

	p->centerPos.x = p->centerPosStart.x = winLimitsX + H2;
	p->centerPos.y = p->centerPosStart.y = winLimitsY + H2;
	p->centerPos.z = p->centerPosStart.z = -halfThick;
	p->rotAngle = p->rotAngleStart = 0;

	p->nSides = 4;
	p->nVertices = 2 * 4;
	pset->nTotalFrontVertices += 4;

	switch (i)
	{
	case 0:
	    topLeftX = -H2;
	    topLeftY = 0;
	    bottomLeftX = -H2;
	    bottomLeftY = H2;
	    bottomRightX = -H3;
	    bottomRightY = H2;
	    topRightX = -H3;
	    topRightY = H6;
	    break;
	case 1:
	    topLeftX = -H3;
	    topLeftY = H6;
	    bottomLeftX = -H3;
	    bottomLeftY = H2;
	    bottomRightX = 0;
	    bottomRightY = H2;
	    topRightX = 0;
	    topRightY = H2;
	    break;
	case 2:
	    topLeftX = -H3;
	    topLeftY = H6;
	    bottomLeftX = 0;
	    bottomLeftY = H2;
	    bottomRightX = W - H2;
	    bottomRightY = H2;
	    topRightX = W - H2;
	    topRightY = H6;
	    break;
	case 3:
	    topLeftX = -H2;
	    topLeftY = 0;
	    bottomLeftX = -H3;
	    bottomLeftY = H6;
	    bottomRightX = W - H2;
	    bottomRightY = H6;
	    topRightX = W - H2;
	    topRightY = 0;
	    break;
	case 4:
	    topLeftX = -H3;
	    topLeftY = -H6;
	    bottomLeftX = -H2;
	    bottomLeftY = 0;
	    bottomRightX = W - H2;
	    bottomRightY = 0;
	    topRightX = W - H2;
	    topRightY = -H6;
	    break;
	case 5:
	    topLeftX = 0;
	    topLeftY = -H2;
	    bottomLeftX = -H3;
	    bottomLeftY = -H6;
	    bottomRightX = W - H2;
	    bottomRightY = -H6;
	    topRightX = W - H2;
	    topRightY = -H2;
	    break;
	case 6:
	    topLeftX = -H3;
	    topLeftY = -H2;
	    bottomLeftX = -H3;
	    bottomLeftY = -H6;
	    bottomRightX = -H3;
	    bottomRightY = -H6;
	    topRightX = 0;
	    topRightY = -H2;
	    break;
	default:
	    topLeftX = -H2;
	    topLeftY = -H2;
	    bottomLeftX = -H2;
	    bottomLeftY = 0;
	    bottomRightX = -H3;
	    bottomRightY = -H6;
	    topRightX = -H3;
	    topRightY = -H2;
	    break;
	}

	// 4 front, 4 back vertices
	if (!p->vertices)
	{
	    p->vertices = calloc (8 * 3, sizeof (GLfloat));
	}
	if (!p->vertices)
	{
	    compLogMessage ("animation", CompLogLevelError,
			    "Not enough memory");
	    freePolygonObjects (pset);
	    return FALSE;
	}

	GLfloat *pv = p->vertices;

	// Determine 4 front vertices in ccw direction
	pv[0] = topLeftX;
	pv[1] = topLeftY;
	pv[2] = halfThick;

	pv[3] = bottomLeftX;
	pv[4] = bottomLeftY;
	pv[5] = halfThick;

	pv[6] = bottomRightX;
	pv[7] = bottomRightY;
	pv[8] = halfThick;

	pv[9] = topRightX;
	pv[10] = topRightY;
	pv[11] = halfThick;

	// Determine 4 back vertices in cw direction
	pv[12] = topRightX;
	pv[13] = topRightY;
	pv[14] = -halfThick;

	pv[15] = bottomRightX;
	pv[16] = bottomRightY;
	pv[17] = -halfThick;

	pv[18] = bottomLeftX;
	pv[19] = bottomLeftY;
	pv[20] = -halfThick;

	pv[21] = topLeftX;
	pv[22] = topLeftY;
	pv[23] = -halfThick;

	// 16 indices for 4 sides (for quad strip)
	if (!p->sideIndices)
	{
	    p->sideIndices = calloc (4 * 4, sizeof (GLushort));
	}
	if (!p->sideIndices)
	{
	    compLogMessage ("animation", CompLogLevelError,
			    "Not enough memory");
	    freePolygonObjects (pset);
	    return FALSE;
	}

	GLushort *ind = p->sideIndices;
	int id = 0;

	ind[id++] = 0;
	ind[id++] = 7;
	ind[id++] = 6;
	ind[id++] = 1;

	ind[id++] = 1;
	ind[id++] = 6;
	ind[id++] = 5;
	ind[id++] = 2;

	ind[id++] = 2;
	ind[id++] = 5;
	ind[id++] = 4;
	ind[id++] = 3;

	ind[id++] = 3;
	ind[id++] = 4;
	ind[id++] = 7;
	ind[id++] = 0;

	if (i < 4)
	{
	    p->boundingBox.x1 = p->centerPos.x + topLeftX;
	    p->boundingBox.y1 = p->centerPos.y + topLeftY;
	    p->boundingBox.x2 = ceil (p->centerPos.x + bottomRightX);
	    p->boundingBox.y2 = ceil (p->centerPos.y + bottomRightY);
	}
	else
	{
	    p->boundingBox.x1 = p->centerPos.x + bottomLeftX;
	    p->boundingBox.y1 = p->centerPos.y + topLeftY;
	    p->boundingBox.x2 = ceil (p->centerPos.x + bottomRightX);
	    p->boundingBox.y2 = ceil (p->centerPos.y + bottomLeftY);
	}
    }
    return TRUE;
}
Bool
fxAirplaneInit (CompWindow * w)
{
    if (!polygonsAnimInit (w))
	return FALSE;

    if (!tessellateIntoAirplane (w))
	return FALSE;

    ANIMADDON_WINDOW (w);

    float airplanePathLength =
	animGetF (w, ANIMADDON_SCREEN_OPTION_AIRPLANE_PATHLENGTH);

    PolygonSet *pset = aw->eng.polygonSet;
    PolygonObject *p = pset->polygons;

    float winLimitsW;		// boundaries of polygon tessellation
    float winLimitsH;

    winLimitsW = BORDER_W (w);
    winLimitsH = BORDER_H (w);

    float H4 = (float)winLimitsH / 4;
    float H6 = (float)winLimitsH / 6;

    int i;
    for (i = 0; i < pset->nPolygons; i++, p++)
    {
	if (!p->effectParameters)
	{
	    p->effectParameters = calloc (1, sizeof (AirplaneEffectParameters));
	}
	if (!p->effectParameters)
	{
	    compLogMessage ("animation", CompLogLevelError,
			    "Not enough memory");
	    return FALSE;
	}

	AirplaneEffectParameters *aep = p->effectParameters;

	p->moveStartTime = 0.00;
	p->moveDuration = 0.19;

	aep->moveStartTime2 = 0.19;
	aep->moveDuration2 = 0.19;

	aep->moveStartTime3 = 0.38;
	aep->moveDuration3 = 0.19;

	aep->moveStartTime4 = 0.58;
	aep->moveDuration4 = 0.09;

	aep->moveDuration5 = 0.41;

	aep->flyFinalRotation.x = 90;
	aep->flyFinalRotation.y = 10;

	aep->flyTheta = 0;

	aep->centerPosFly.x = 0;
	aep->centerPosFly.y = 0;
	aep->centerPosFly.z = 0;

	aep->flyScale = 0;
	aep->flyFinalScale = 6 * (winLimitsW / (w->screen->width / 2));

	switch (i)
	{
	case 0:
	    p->rotAxisOffset.x = -H4;
	    p->rotAxisOffset.y = H4;

	    p->rotAxis.x = 1.00;
	    p->rotAxis.y = 1.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 179.5;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = 84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = 0;

	    aep->rotAxisB.x = 0.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 0;
	    break;

	case 1:
	    p->rotAxisOffset.x = -H4;
	    p->rotAxisOffset.y = H4;

	    p->rotAxis.x = 1.00;
	    p->rotAxis.y = 1.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 179.5;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = 84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = H6;

	    aep->rotAxisB.x = 1.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = -84;
	    break;

	case 2:
	    p->moveDuration = 0.00;

	    p->rotAxisOffset.x = 0;
	    p->rotAxisOffset.y = 0;

	    p->rotAxis.x = 0.00;
	    p->rotAxis.y = 0.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 0;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = 84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = H6;

	    aep->rotAxisB.x = 1.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = -84;
	    break;

	case 3:
	    p->moveDuration = 0.00;

	    p->rotAxisOffset.x = 0;
	    p->rotAxisOffset.y = 0;

	    p->rotAxis.x = 0.00;
	    p->rotAxis.y = 0.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 0;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = 84;

	    aep->moveDuration3 = 0.00;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = 0;

	    aep->rotAxisB.x = 0.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 0;
	    break;

	case 4:
	    p->moveDuration = 0.00;

	    p->rotAxisOffset.x = 0;
	    p->rotAxisOffset.y = 0;

	    p->rotAxis.x = 0.00;
	    p->rotAxis.y = 0.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 0;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = -84;

	    aep->moveDuration3 = 0.00;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = 0;

	    aep->rotAxisB.x = 0.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 0;
	    break;

	case 5:
	    p->moveDuration = 0.00;

	    p->rotAxisOffset.x = 0;
	    p->rotAxisOffset.y = 0;

	    p->rotAxis.x = 0.00;
	    p->rotAxis.y = 0.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = 0;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = -84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = -H6;

	    aep->rotAxisB.x = 1.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 84;
	    break;

	case 6:
	    p->rotAxisOffset.x = -H4;
	    p->rotAxisOffset.y = -H4;

	    p->rotAxis.x = 1.00;
	    p->rotAxis.y = -1.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = -179.5;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = -84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = -H6;

	    aep->rotAxisB.x = 1.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 84;
	    break;

	case 7:
	    p->rotAxisOffset.x = -H4;
	    p->rotAxisOffset.y = -H4;

	    p->rotAxis.x = 1.00;
	    p->rotAxis.y = -1.00;
	    p->rotAxis.z = 0.00;

	    p->finalRotAng = -179.5;

	    aep->rotAxisOffsetA.x = 0;
	    aep->rotAxisOffsetA.y = 0;

	    aep->rotAxisA.x = 1.00;
	    aep->rotAxisA.y = 0.00;
	    aep->rotAxisA.z = 0.00;

	    aep->finalRotAngA = -84;

	    aep->rotAxisOffsetB.x = 0;
	    aep->rotAxisOffsetB.y = 0;

	    aep->rotAxisB.x = 0.00;
	    aep->rotAxisB.y = 0.00;
	    aep->rotAxisB.z = 0.00;

	    aep->finalRotAngB = 0;
	    break;
	}
    }

    if (airplanePathLength >= 1)
	pset->allFadeDuration = 0.30f / airplanePathLength;
    else
	pset->allFadeDuration = 0.30f;

    pset->doDepthTest = TRUE;
    pset->doLighting = TRUE;
    pset->correctPerspective = CorrectPerspectivePolygon;

    pset->extraPolygonTransformFunc =
	&AirplaneExtraPolygonTransformFunc;

    // Duration extension
    aw->com->animTotalTime *= 2 + airplanePathLength;
    aw->com->animRemainingTime = aw->com->animTotalTime;

    return TRUE;
}
Example #6
0
static void
fxCurvedFoldModelStepObject(CompWindow *w,
                            Model *model,
                            Object *object,
                            float forwardProgress, float curveMaxAmp)
{
    ANIM_WINDOW(w);

    float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x -
                                 w->output.left) * model->scale.x;
    float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y -
                                 w->output.top) * model->scale.y;

    if (aw->curWindowEvent == WindowEventShade ||
            aw->curWindowEvent == WindowEventUnshade)
    {
        // Execute shade mode

        // find position in window contents
        // (window contents correspond to 0.0-1.0 range)
        float relPosInWinContents =
            (object->gridPosition.y * WIN_H(w) -
             model->topHeight) / w->height;
        float relDistToCenter = fabs(relPosInWinContents - 0.5);

        if (object->gridPosition.y == 0)
        {
            object->position.x = origx;
            object->position.y = WIN_Y(w);
        }
        else if (object->gridPosition.y == 1)
        {
            object->position.x = origx;
            object->position.y =
                (1 - forwardProgress) * origy +
                forwardProgress *
                (WIN_Y(w) + model->topHeight + model->bottomHeight);
        }
        else
        {
            object->position.x =
                origx + sin(forwardProgress * M_PI / 2) *
                (0.5 - object->gridPosition.x) * 2 * model->scale.x *
                curveMaxAmp *
                (1 - pow (pow(2 * relDistToCenter, 1.3), 2));
            object->position.y =
                (1 - forwardProgress) * origy +
                forwardProgress * (WIN_Y(w) + model->topHeight);
        }
    }
    else
    {
        // Execute normal mode

        // find position within window borders
        // (border contents correspond to 0.0-1.0 range)
        float relPosInWinBorders =
            (object->gridPosition.y * WIN_H(w) -
             (w->output.top - w->input.top)) / BORDER_H(w);
        float relDistToCenter = fabs(relPosInWinBorders - 0.5);

        // prevent top & bottom shadows from extending too much
        if (relDistToCenter > 0.5)
            relDistToCenter = 0.5;

        object->position.x =
            origx + sin(forwardProgress * M_PI / 2) *
            (0.5 - object->gridPosition.x) * 2 * model->scale.x *
            curveMaxAmp *
            (1 - pow (pow(2 * relDistToCenter, 1.3), 2));
        object->position.y =
            (1 - forwardProgress) * origy +
            forwardProgress * (BORDER_Y(w) + BORDER_H(w) / 2.0);
    }
}
Example #7
0
void
fxFoldAnimStepPolygon (CompWindow    *w,
                       PolygonObject *p,
                       float         forwardProgress)
{
	const BananaValue *
	option_fold_gridx = bananaGetOption (bananaIndex,
	                                     "fold_gridx",
	                                     w->screen->screenNum);

	const BananaValue *
	option_fold_gridy = bananaGetOption (bananaIndex,
	                                     "fold_gridy",
	                                     w->screen->screenNum);

	const BananaValue *
	option_fold_dir = bananaGetOption (bananaIndex,
	                                   "fold_dir",
	                                   w->screen->screenNum);

	int dir = option_fold_dir->i == 0 ? 1 : -1;

	int gridSizeX = option_fold_gridx->i;
	int gridSizeY = option_fold_gridy->i;

	float moveProgress = forwardProgress - p->moveStartTime;

	if (p->moveDuration > 0)
		moveProgress /= p->moveDuration;
	if (moveProgress < 0)
		moveProgress = 0;
	else if (moveProgress > 1)
		moveProgress = 1;

	float const_x = BORDER_W (w) / (float)gridSizeX; //  width of single piece
	float const_y = BORDER_H (w) / (float)gridSizeY; // height of single piece

	p->rotAngle = dir * moveProgress * p->finalRotAng;

	if (p->rotAxis.x == 180)
	{
		if (p->finalRelPos.y == gridSizeY - 2)
		{
			// it means the last row
			p->centerPos.y =
			        p->centerPosStart.y + const_y / 2.0f -
			        cos (p->rotAngle * M_PI / 180.0f) * const_y / 2.0f;
			p->centerPos.z =
			        p->centerPosStart.z +
			        1.0f / w->screen->width * (sin (-p->rotAngle * M_PI / 180.0f) *
			                                   const_y / 2.0f);
		}
		else
		{
			// rows
			if (fabs (p->rotAngle) < 90)
			{
				// 1. rotate 90
				p->centerPos.y =
				        p->centerPosStart.y + const_y / 2.0f -
				        cos (p->rotAngle * M_PI / 180.0f) * const_y / 2.0f;
				p->centerPos.z =
				        p->centerPosStart.z +
				        1.0f / w->screen->width *
				        (sin (-p->rotAngle * M_PI / 180.0f) * const_y / 2.0f);
			}
			else
			{
				// 2. rotate faster 180
				float alpha = p->rotAngle - dir * 90; // [0 - 45]
				float alpha2 = 2 * alpha; // [0 - 90]

				p->rotAngle = (p->rotAngle - dir * 90) * 2 + dir * 90;

				p->centerPos.y =
				        p->centerPosStart.y + const_y / 2.0f + const_y -
				        cos (alpha * M_PI / 180.0f) * const_y + dir *
				        sin (alpha2 * M_PI / 180.0f) * const_y / 2.0f;

				p->centerPos.z =
				        p->centerPosStart.z +
				        1.0f / w->screen->width *
				        (-sin (alpha * M_PI / 180.0f) * const_y - dir *
				         cos (alpha2 * M_PI / 180.0f) * const_y / 2.0f);
			}
		}
	}
	else if (p->rotAxis.y == -180)
	{
		// simple blocks left
		p->centerPos.x =
		        p->centerPosStart.x + const_x / 2.0f -
		        cos (p->rotAngle * M_PI / 180.0f) * const_x / 2.0f;

		p->centerPos.z =
		        p->centerPosStart.z -
		        1.0f / w->screen->width * (sin (p->rotAngle * M_PI / 180.0f) *
		                                   const_x / 2.0f);
	}
	else if (p->rotAxis.y == 180)
	{
		// simple blocks right
		p->centerPos.x =
		        p->centerPosStart.x - const_x / 2.0f +
		        cos (-p->rotAngle * M_PI / 180.0f) * const_x / 2.0f;

		p->centerPos.z =
		        p->centerPosStart.z +
		        1.0f / w->screen->width * (sin (-p->rotAngle * M_PI / 180.0f) *
		                                   const_x / 2.0f);
	}
}