/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   This file is part of
 *       _______   ______________  ______     _____
 *      / ____/ | / /  _/ ____/  |/  /   |   |__  /
 *     / __/ /  |/ // // / __/ /|_/ / /| |    /_ <
 *    / /___/ /|  // // /_/ / /  / / ___ |  ___/ /
 *   /_____/_/ |_/___/\____/_/  /_/_/  |_| /____/.
 *
 *   Copyright © 2003-2010 Brain Control, all rights reserved.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef LSYS2_SYMBOLS_HPP
#define LSYS2_SYMBOLS_HPP

#include "../../eshared.hpp"

class eLsys2_Symbol_Cylinder : public eLsys2_Symbol {
public:
    eLsys2_Symbol_Cylinder() : m_model(eNULL) {
        m_numSegments = 3;
        m_localMass = 1.0f;
    }
    void setProperties(eSceneData* model, eF32 oscillation, const eVector3 &oscillationAxis, eF32 period, eBool hinge) {
        m_model = model;
        m_hinge = hinge;
        m_oscillation = oscillation;
        m_oscillationAxis = oscillationAxis;
        m_oscillationPeriod = period;
    }

    virtual eU32 init(void* state) const {
        if(this->m_hinge == eFALSE)
            return -1;

        Hinge o(this->m_oscillationAxis, this->m_oscillation, m_oscillationPeriod);
        return ((DrawState_X*)state)->newHinge(o);
    };

    virtual	void prepare(eU32 instanceHandle, void* state, eF32 blendWeight, eF32 energy) const {
        ((DrawState_X*)state)->accMass() += m_localMass * energy;
    };

	virtual void execute(eU32 instanceHandle, void* state, eF32 blendWeight, eF32 energy, const eF32* parameters, eLSys2_Context& context) const {

		eLsys2_Turtle& turtle = ((DrawState_X*)state)->getTurtle();

        {
            // calc mass rotation
            eF32 attractAmount = context.param(CTX_GRAVITY) * context.param(CTX_GRAVITY) * context.param(CTX_GRAVITY) * ((DrawState_X*)state)->accMass() * turtle.m_scale;
            eU32 axis = 2;
            eVector3 attractionVec = eVector3(0,-1,0);

            eVector3 look = turtle.m_rotation.getVector(axis);
		    eVector3 side = look^attractionVec;

		    eF32 cosAngleAttrLen = look * attractionVec;
		    eF32 cosAngleSqr = (cosAngleAttrLen * cosAngleAttrLen / attractionVec.sqrLength());
            eF32 sinAngleSqr = 1.0f - cosAngleSqr;
		    eF32 amount = (1.0f - (1.0f / (1.0f + attractAmount)));

		    // |side| = sin(alpha)
		    eF32 sideLen = side.length();
		    if(sideLen > eALMOST_ZERO) {
			    side /= sideLen;
			    eQuat rotation(side, ePI * 0.5f * sinAngleSqr * amount * energy);
                turtle.m_rotation = rotation * turtle.m_rotation;
		    }
        }

        turtle.move(energy);
		turtle.scale(ePow(context.param(CTX_DECAY), energy));

        ((DrawState_X*)state)->drawModel(instanceHandle, m_model, m_numSegments);
        ((DrawState_X*)state)->turtleUpdate();
	}

    eU32            m_numSegments;
    eSceneData*     m_model;
    eF32            m_localMass;
    eF32            m_oscillation;
    eVector3        m_oscillationAxis;
    eF32            m_oscillationPeriod;
    eBool           m_hinge;
};


#endif // LSYS2_SYMBOLS_HPP
