YACE64 Logo

The Commodore 64 Emulator with the extra dimension

Home Introduction Features Screenshots Download Links Help About
Commodore 64
www.icons8.com

Tutorial 21

This script shows how to rotate a plane of character blocks. This a quit advanced topic, some knowledge about vector operation and an understanding how rotating coordinates in 3D space are needed.

This is the "Tutorial21" included in the Tutorial-Download..

Instructions

Main work is done in OnChar() - for other functions see other tutorials.

The script rotates three lines of the C64 screen around the Y and X axis. The rotation animation is done in the OnFrameEnd() function, where only the rotation angles are set.
The OnUser() function reacts to user input to one of the five script defined buttons. OnLoad() just setups our emulator and 3D scene as already seen in prior tutorials.

To understand how rotation works in context of YACE, you should know, that each character (and sprite) has ist own rotation coordinate, which is the left/bottom.
So setting one or more rotations to the character (or sprite) (see BlockManipulation) will only rotate it around its left/bottom coordinate. To set the position in 3D you need to set translation (xTranslation, yTranslation, zTranslation) values in BlockManipulation; if you want to rotate multiple character around an arbitrary point in 3D space you have first to set the position of all the characters (e.g. into a plane) around the rotation center (0.0, 0.0, 0.0) then rotate the coordinates and after that move everything to its desired position in 3D space.

See comments of the source code detailed informations.

const int MapEmptyId = 1;
grid<float> mapEmpty = { {0.0, 0.0},
{0.0, 0.0} }; // Depthmaps will be explained later

const int MapFlatId = 2;
grid<float> mapFlat = { {1.0, 1.0},
{1.0, 1.0} }; // Depthmaps will be explained later

float animatedRotationY = 0.0;
float animatedRotationX = 0.0;

const float pixelSize = 0.005f; // This is the default size of a 3D pixel

bool rotateX = false;
bool rotateY = false;

// Setup our scene
void OnLoad(bool reloaded)
{
    APP.ClearDepthMaps(); // Clear all loaded depth maps

    // Set the view mode to the new 3D
    APP.ViewMode = ViewMode::Ext3D;

    // Set the ambient light color and brigtness
    APP.SetAmbientLight(0.3, 0.3, 0.3);
    // Set the direction of the light (from the middle off the scene (x), from top to bottom (y) and back to forth (z))
    APP.SetLightDir(0.0, -1.0, +1.0);

    // Position the scene, so we have the top rows in the middle of the screen
    E3D.SetScenePosition(0.1, -0.35, +1.4);
    // Rotate the scene a little bit, so we can see the effect better
    E3D.SetSceneOrientation(-25.0, -15.0, 0.0, 0.0);

    // Name our script buttons
    GUI.SetButtonTitle(1, "Rotate X");
    GUI.SetButtonTitle(2, "Rotate Y");
    GUI.SetButtonTitle(3, "Rotate X and Y");
    GUI.SetButtonTitle(4, "Stop");
    GUI.SetButtonTitle(5, "-");
}

// This is called for every char on the screen (8x8 pixel block)
int OnChar(int mode, CharInfo& charInfo, BlockManipulation& charManipulationBack, BlockManipulation& charManipulationFore)
{
    // set some default transformations for all 40*25 chars of the C64 screen
    charManipulationFore.voxelMode = Voxel::HardEdge;
    charManipulationFore.depthMapIndex = MapFlatId;

    if (charInfo.row >= 1 && charInfo.row <= 3 && charInfo.col > 0 && charInfo.col < 39)
    {
        charManipulationFore.reflective = 1.0;
        charManipulationFore.zScale = 2.0;

        // rotate the char itself around his own axis (left/bottom is rotation center)
        if (rotateX)
        {
            charManipulationFore.rotationAxis1 = Rotation::X;
            charManipulationFore.rotation1 = animatedRotationX;
        }

        if (rotateY)
        {
            charManipulationFore.rotationAxis2 = Rotation::Y;
            charManipulationFore.rotation2 = animatedRotationY;
        }

        // Now rotate the char coordinate using a rotation Center...
        float rotationCenterY = pixelSize * 63.5;
        float rotationCenterX = -pixelSize * 285.0;

        // ...next create a vector with the position of each char in a x/y plane.
        // The rotationCenterX and rotationCenterY is the rotation center, in this case the middle of the three text rows.
        // Calculate the position of each char within the plane using the original x and y coordinate.
        Vector v = Vector(charInfo.x * pixelSize + rotationCenterX, -charInfo.y * pixelSize + rotationCenterY, 0.0);

        if (rotateX)
        {
            // rotate the position around the x axis
            v = v.RotateX(animatedRotationX);
        }

        if (rotateY)
        {
            // rotate the position around the y axis
            v = v.RotateY(animatedRotationY);
        }

        // move the rotated plane in place
        v += Vector(0.0, pixelSize * 71.5, -pixelSize * 2.0);

        charManipulationFore.xTranslation = v.x;
        charManipulationFore.yTranslation = v.y;
        charManipulationFore.zTranslation = v.z;
    }

    return Draw::DrawCombined;
}


void OnFrameEnd()
{
    // just some animation for the rotation angle (always in degree)
    animatedRotationY += 1.0;
    animatedRotationX += 0.5;
}

grid<float>& OnGetDepthMap(int mode, int index, bool front)
{
    switch (index)
    {
        case MapFlatId: return(mapFlat);
        default: break;
    }
    return(mapEmpty);
}

void OnUser(int buttonIndex)
{
    if (buttonIndex == 1)
    {
        rotateX = true;
        rotateY = false;
        animatedRotationX = 0.0;
        animatedRotationY = 0.0;
        GUI.ShowInfoMessage("Rotate around X axis");
    }
    else if (buttonIndex == 2)
    {
        rotateX = false;
        rotateY = true;
        animatedRotationX = 0.0;
        animatedRotationY = 0.0;
        GUI.ShowInfoMessage("Rotate around Y axis");
    }
    else if (buttonIndex == 3)
    {
        rotateX = true;
        rotateY = true;
        animatedRotationX = 0.0;
        animatedRotationY = 0.0;
        GUI.ShowInfoMessage("Rotate around X and Y axis");
    }
    else if (buttonIndex == 4)
    {
        rotateX = false;
        rotateY = false;
        animatedRotationX = 0.0;
        animatedRotationY = 0.0;
        GUI.ShowInfoMessage("Stop rotations");
    }
}