<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#include "OgreMovableObject.h"
#include "OgreSceneNode.h"
#include "OgreTagPoint.h"
#include "OgreLight.h"
#include "OgreEntity.h"
#include "OgreRoot.h"
#include "OgreSceneManager.h"
#include "OgreCamera.h"
#include "OgreLodListener.h"

namespace Ogre {
	//-----------------------------------------------------------------------
	//-----------------------------------------------------------------------
	uint32 MovableObject::msDefaultQueryFlags = 0xFFFFFFFF;
	uint32 MovableObject::msDefaultVisibilityFlags = 0xFFFFFFFF;
    //-----------------------------------------------------------------------
    MovableObject::MovableObject()
        : mCreator(0)
        , mManager(0)
        , mParentNode(0)
        , mParentIsTagPoint(false)
        , mVisible(true)
		, mDebugDisplay(false)
        , mUpperDistance(0)
        , mSquaredUpperDistance(0)
        , mBeyondFarDistance(false)
        , mRenderQueueID(RENDER_QUEUE_MAIN)
        , mRenderQueueIDSet(false)
		, mRenderQueuePriority(100)
		, mRenderQueuePrioritySet(false)
		, mQueryFlags(msDefaultQueryFlags)
        , mVisibilityFlags(msDefaultVisibilityFlags)
        , mCastShadows(true)
        , mRenderingDisabled(false)
        , mListener(0)
        , mLightListUpdated(0)
		, mLightMask(0xFFFFFFFF)
    {
    }
    //-----------------------------------------------------------------------
    MovableObject::MovableObject(const String& name)
        : mName(name)
        , mCreator(0)
        , mManager(0)
        , mParentNode(0)
        , mParentIsTagPoint(false)
        , mVisible(true)
		, mDebugDisplay(false)
        , mUpperDistance(0)
        , mSquaredUpperDistance(0)
        , mBeyondFarDistance(false)
        , mRenderQueueID(RENDER_QUEUE_MAIN)
        , mRenderQueueIDSet(false)
		, mRenderQueuePriority(100)
		, mRenderQueuePrioritySet(false)
		, mQueryFlags(msDefaultQueryFlags)
        , mVisibilityFlags(msDefaultVisibilityFlags)
        , mCastShadows(true)
        , mRenderingDisabled(false)
        , mListener(0)
        , mLightListUpdated(0)
		, mLightMask(0xFFFFFFFF)
    {
    }
    //-----------------------------------------------------------------------
    MovableObject::~MovableObject()
    {
        // Call listener (note, only called if there's something to do)
        if (mListener)
        {
            mListener->objectDestroyed(this);
        }

        if (mParentNode)
        {
            // detach from parent
            if (mParentIsTagPoint)
            {
                // May be we are a lod entity which not in the parent entity child object list,
                // call this method could safely ignore this case.
                static_cast<TagPoint*>(mParentNode)->getParentEntity()->detachObjectFromBone(this);
            }
            else
            {
                // May be we are a lod entity which not in the parent node child object list,
                // call this method could safely ignore this case.
                static_cast<SceneNode*>(mParentNode)->detachObject(this);
            }
        }
    }
    //-----------------------------------------------------------------------
    void MovableObject::_notifyAttached(Node* parent, bool isTagPoint)
    {
        assert(!mParentNode || !parent);

        bool different = (parent != mParentNode);

        mParentNode = parent;
        mParentIsTagPoint = isTagPoint;

        // Mark light list being dirty, simply decrease
        // counter by one for minimise overhead
        --mLightListUpdated;

        // Call listener (note, only called if there's something to do)
        if (mListener && different)
        {
            if (mParentNode)
                mListener->objectAttached(this);
            else
                mListener->objectDetached(this);
        }
    }
    //-----------------------------------------------------------------------
    Node* MovableObject::getParentNode(void) const
    {
        return mParentNode;
    }
    //-----------------------------------------------------------------------
    SceneNode* MovableObject::getParentSceneNode(void) const
    {
        if (mParentIsTagPoint)
        {
            TagPoint* tp = static_cast<TagPoint*>(mParentNode);
            return tp->getParentEntity()->getParentSceneNode();
        }
        else
        {
            return static_cast<SceneNode*>(mParentNode);
        }
    }
    //-----------------------------------------------------------------------
    bool MovableObject::isAttached(void) const
    {
        return (mParentNode != 0);

    }
	//---------------------------------------------------------------------
	void MovableObject::detachFromParent(void)
	{
		if (isAttached())
		{
			if (mParentIsTagPoint)
			{
				TagPoint* tp = static_cast<TagPoint*>(mParentNode);
				tp->getParentEntity()->detachObjectFromBone(this);
			}
			else
			{
				SceneNode* sn = static_cast<SceneNode*>(mParentNode);
				sn->detachObject(this);
			}
		}
	}
    //-----------------------------------------------------------------------
	bool MovableObject::isInScene(void) const
	{
		if (mParentNode != 0)
		{
			if (mParentIsTagPoint)
			{
				TagPoint* tp = static_cast<TagPoint*>(mParentNode);
				return tp->getParentEntity()->isInScene();
			}
			else
			{
				SceneNode* sn = static_cast<SceneNode*>(mParentNode);
				return sn->isInSceneGraph();
			}
		}
		else
		{
			return false;
		}
	}
    //-----------------------------------------------------------------------
    void MovableObject::_notifyMoved(void)
    {
        // Mark light list being dirty, simply decrease
        // counter by one for minimise overhead
        --mLightListUpdated;

        // Notify listener if exists
        if (mListener)
        {
            mListener->objectMoved(this);
        }
    }
    //-----------------------------------------------------------------------
    void MovableObject::setVisible(bool visible)
    {
        mVisible = visible;
    }
    //-----------------------------------------------------------------------
    bool MovableObject::getVisible(void) const
    {
        return mVisible;
    }
    //-----------------------------------------------------------------------
    bool MovableObject::isVisible(void) const
    {
        if (!mVisible || mBeyondFarDistance || mRenderingDisabled)
            return false;

        SceneManager* sm = Root::getSingleton()._getCurrentSceneManager();
        if (sm && !(getVisibilityFlags() & sm->_getCombinedVisibilityMask()))
            return false;

        return true;
    }
	//-----------------------------------------------------------------------
	void MovableObject::_notifyCurrentCamera(Camera* cam)
	{
		if (mParentNode)
		{
			if (cam->getUseRenderingDistance() && mUpperDistance > 0)
			{
				Real rad = getBoundingRadius();
				Real squaredDepth = mParentNode->getSquaredViewDepth(cam->getLodCamera());

				const Vector3& scl = mParentNode->_getDerivedScale();
				Real factor = std::max(std::max(scl.x, scl.y), scl.z);

				// Max distance to still render
				Real maxDist = mUpperDistance + rad * factor;
				if (squaredDepth > Math::Sqr(maxDist))
				{
					mBeyondFarDistance = true;
				}
				else
				{
					mBeyondFarDistance = false;
				}
			}
			else
			{
				mBeyondFarDistance = false;
			}

            // Construct event object
            MovableObjectLodChangedEvent evt;
            evt.movableObject = this;
            evt.camera = cam;

            // Notify lod event listeners
            cam->getSceneManager()->_notifyMovableObjectLodChanged(evt);

		}

        mRenderingDisabled = mListener && !mListener->objectRendering(this, cam);
	}
    //-----------------------------------------------------------------------
    void MovableObject::setRenderQueueGroup(uint8 queueID)
    {
		assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!");
        mRenderQueueID = queueID;
        mRenderQueueIDSet = true;
    }

	//-----------------------------------------------------------------------
	void MovableObject::setRenderQueueGroupAndPriority(uint8 queueID, ushort priority)
	{
		setRenderQueueGroup(queueID);
		mRenderQueuePriority = queueID;
		mRenderQueuePrioritySet = true;

	}

    //-----------------------------------------------------------------------
    uint8 MovableObject::getRenderQueueGroup(void) const
    {
        return mRenderQueueID;
    }
    //-----------------------------------------------------------------------
	const Matrix4& MovableObject::_getParentNodeFullTransform(void) const
	{

		if(mParentNode)
		{
			// object attached to a sceneNode
			return mParentNode->_getFullTransform();
		}
        // fallback
        return Matrix4::IDENTITY;
	}
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getWorldBoundingBox(bool derive) const
    {
        if (derive)
        {
            mWorldAABB = this->getBoundingBox();
            mWorldAABB.transformAffine(_getParentNodeFullTransform());
        }

        return mWorldAABB;

    }
    //-----------------------------------------------------------------------
	const Sphere& MovableObject::getWorldBoundingSphere(bool derive) const
	{
		if (derive)
		{
			const Vector3& scl = mParentNode->_getDerivedScale();
			Real factor = std::max(std::max(scl.x, scl.y), scl.z);
			mWorldBoundingSphere.setRadius(getBoundingRadius() * factor);
			mWorldBoundingSphere.setCenter(mParentNode->_getDerivedPosition());
		}
		return mWorldBoundingSphere;
	}
    //-----------------------------------------------------------------------
    const LightList& MovableObject::queryLights(void) const
    {
        // Try listener first
        if (mListener)
        {
            const LightList* lightList =
                mListener->objectQueryLights(this);
            if (lightList)
            {
                return *lightList;
            }
        }

        // Query from parent entity if exists
        if (mParentIsTagPoint)
        {
            TagPoint* tp = static_cast<TagPoint*>(mParentNode);
            return tp->getParentEntity()->queryLights();
        }

        if (mParentNode)
        {
            SceneNode* sn = static_cast<SceneNode*>(mParentNode);

            // Make sure we only update this only if need.
            ulong frame = sn->getCreator()->_getLightsDirtyCounter();
            if (mLightListUpdated != frame)
            {
                mLightListUpdated = frame;

				const Vector3& scl = mParentNode->_getDerivedScale();
				Real factor = std::max(std::max(scl.x, scl.y), scl.z);

                sn->findLights(mLightList, this->getBoundingRadius() * factor, this->getLightMask());
            }
        }
        else
        {
            mLightList.clear();
        }

        return mLightList;
    }
    //-----------------------------------------------------------------------
    ShadowCaster::ShadowRenderableListIterator MovableObject::getShadowVolumeRenderableIterator(
        ShadowTechnique shadowTechnique, const Light* light,
        HardwareIndexBufferSharedPtr* indexBuffer,
        bool inExtrudeVertices, Real extrusionDist, unsigned long flags )
    {
        static ShadowRenderableList dummyList;
        return ShadowRenderableListIterator(dummyList.begin(), dummyList.end());
    }
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getLightCapBounds(void) const
    {
        // Same as original bounds
        return getWorldBoundingBox();
    }
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getDarkCapBounds(const Light& light, Real extrusionDist) const
    {
        // Extrude own light cap bounds
        mWorldDarkCapBounds = getLightCapBounds();
        this->extrudeBounds(mWorldDarkCapBounds, light.getAs4DVector(),
            extrusionDist);
        return mWorldDarkCapBounds;

    }
    //-----------------------------------------------------------------------
    Real MovableObject::getPointExtrusionDistance(const Light* l) const
    {
        if (mParentNode)
        {
            return getExtrusionDistance(mParentNode->_getDerivedPosition(), l);
        }
        else
        {
            return 0;
        }
    }
	//-----------------------------------------------------------------------
	uint32 MovableObject::getTypeFlags(void) const
	{
		if (mCreator)
		{
			return mCreator->getTypeFlags();
		}
		else
		{
			return 0xFFFFFFFF;
		}
	}
	//---------------------------------------------------------------------
	void MovableObject::setLightMask(uint32 lightMask)
	{
		this->mLightMask = lightMask;
		//make sure to request a new light list from the scene manager if mask changed
		mLightListUpdated = 0;
	}
	//---------------------------------------------------------------------
	class MORecvShadVisitor : public Renderable::Visitor
	{
	public:
		bool anyReceiveShadows;
		MORecvShadVisitor() : anyReceiveShadows(false)
		{

		}
		void visit(Renderable* rend, ushort lodIndex, bool isDebug,
			Any* pAny = 0)
		{
			Technique* tech = rend->getTechnique();
			bool techReceivesShadows = tech && tech->getParent()->getReceiveShadows();
			anyReceiveShadows = anyReceiveShadows ||
				techReceivesShadows || !tech;
		}
	};
	//---------------------------------------------------------------------
	bool MovableObject::getReceivesShadows()
	{
		MORecvShadVisitor visitor;
		visitRenderables(&visitor);
		return visitor.anyReceiveShadows;

	}
	//-----------------------------------------------------------------------
	//-----------------------------------------------------------------------
	MovableObject* MovableObjectFactory::createInstance(
		const String& name, SceneManager* manager,
		const NameValuePairList* params)
	{
		MovableObject* m = createInstanceImpl(name, params);
		m->_notifyCreator(this);
		m->_notifyManager(manager);
		return m;
	}

}

<commit_msg>Fixed setting render queue priority for movable object<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#include "OgreMovableObject.h"
#include "OgreSceneNode.h"
#include "OgreTagPoint.h"
#include "OgreLight.h"
#include "OgreEntity.h"
#include "OgreRoot.h"
#include "OgreSceneManager.h"
#include "OgreCamera.h"
#include "OgreLodListener.h"

namespace Ogre {
	//-----------------------------------------------------------------------
	//-----------------------------------------------------------------------
	uint32 MovableObject::msDefaultQueryFlags = 0xFFFFFFFF;
	uint32 MovableObject::msDefaultVisibilityFlags = 0xFFFFFFFF;
    //-----------------------------------------------------------------------
    MovableObject::MovableObject()
        : mCreator(0)
        , mManager(0)
        , mParentNode(0)
        , mParentIsTagPoint(false)
        , mVisible(true)
		, mDebugDisplay(false)
        , mUpperDistance(0)
        , mSquaredUpperDistance(0)
        , mBeyondFarDistance(false)
        , mRenderQueueID(RENDER_QUEUE_MAIN)
        , mRenderQueueIDSet(false)
		, mRenderQueuePriority(100)
		, mRenderQueuePrioritySet(false)
		, mQueryFlags(msDefaultQueryFlags)
        , mVisibilityFlags(msDefaultVisibilityFlags)
        , mCastShadows(true)
        , mRenderingDisabled(false)
        , mListener(0)
        , mLightListUpdated(0)
		, mLightMask(0xFFFFFFFF)
    {
    }
    //-----------------------------------------------------------------------
    MovableObject::MovableObject(const String& name)
        : mName(name)
        , mCreator(0)
        , mManager(0)
        , mParentNode(0)
        , mParentIsTagPoint(false)
        , mVisible(true)
		, mDebugDisplay(false)
        , mUpperDistance(0)
        , mSquaredUpperDistance(0)
        , mBeyondFarDistance(false)
        , mRenderQueueID(RENDER_QUEUE_MAIN)
        , mRenderQueueIDSet(false)
		, mRenderQueuePriority(100)
		, mRenderQueuePrioritySet(false)
		, mQueryFlags(msDefaultQueryFlags)
        , mVisibilityFlags(msDefaultVisibilityFlags)
        , mCastShadows(true)
        , mRenderingDisabled(false)
        , mListener(0)
        , mLightListUpdated(0)
		, mLightMask(0xFFFFFFFF)
    {
    }
    //-----------------------------------------------------------------------
    MovableObject::~MovableObject()
    {
        // Call listener (note, only called if there's something to do)
        if (mListener)
        {
            mListener->objectDestroyed(this);
        }

        if (mParentNode)
        {
            // detach from parent
            if (mParentIsTagPoint)
            {
                // May be we are a lod entity which not in the parent entity child object list,
                // call this method could safely ignore this case.
                static_cast<TagPoint*>(mParentNode)->getParentEntity()->detachObjectFromBone(this);
            }
            else
            {
                // May be we are a lod entity which not in the parent node child object list,
                // call this method could safely ignore this case.
                static_cast<SceneNode*>(mParentNode)->detachObject(this);
            }
        }
    }
    //-----------------------------------------------------------------------
    void MovableObject::_notifyAttached(Node* parent, bool isTagPoint)
    {
        assert(!mParentNode || !parent);

        bool different = (parent != mParentNode);

        mParentNode = parent;
        mParentIsTagPoint = isTagPoint;

        // Mark light list being dirty, simply decrease
        // counter by one for minimise overhead
        --mLightListUpdated;

        // Call listener (note, only called if there's something to do)
        if (mListener && different)
        {
            if (mParentNode)
                mListener->objectAttached(this);
            else
                mListener->objectDetached(this);
        }
    }
    //-----------------------------------------------------------------------
    Node* MovableObject::getParentNode(void) const
    {
        return mParentNode;
    }
    //-----------------------------------------------------------------------
    SceneNode* MovableObject::getParentSceneNode(void) const
    {
        if (mParentIsTagPoint)
        {
            TagPoint* tp = static_cast<TagPoint*>(mParentNode);
            return tp->getParentEntity()->getParentSceneNode();
        }
        else
        {
            return static_cast<SceneNode*>(mParentNode);
        }
    }
    //-----------------------------------------------------------------------
    bool MovableObject::isAttached(void) const
    {
        return (mParentNode != 0);

    }
	//---------------------------------------------------------------------
	void MovableObject::detachFromParent(void)
	{
		if (isAttached())
		{
			if (mParentIsTagPoint)
			{
				TagPoint* tp = static_cast<TagPoint*>(mParentNode);
				tp->getParentEntity()->detachObjectFromBone(this);
			}
			else
			{
				SceneNode* sn = static_cast<SceneNode*>(mParentNode);
				sn->detachObject(this);
			}
		}
	}
    //-----------------------------------------------------------------------
	bool MovableObject::isInScene(void) const
	{
		if (mParentNode != 0)
		{
			if (mParentIsTagPoint)
			{
				TagPoint* tp = static_cast<TagPoint*>(mParentNode);
				return tp->getParentEntity()->isInScene();
			}
			else
			{
				SceneNode* sn = static_cast<SceneNode*>(mParentNode);
				return sn->isInSceneGraph();
			}
		}
		else
		{
			return false;
		}
	}
    //-----------------------------------------------------------------------
    void MovableObject::_notifyMoved(void)
    {
        // Mark light list being dirty, simply decrease
        // counter by one for minimise overhead
        --mLightListUpdated;

        // Notify listener if exists
        if (mListener)
        {
            mListener->objectMoved(this);
        }
    }
    //-----------------------------------------------------------------------
    void MovableObject::setVisible(bool visible)
    {
        mVisible = visible;
    }
    //-----------------------------------------------------------------------
    bool MovableObject::getVisible(void) const
    {
        return mVisible;
    }
    //-----------------------------------------------------------------------
    bool MovableObject::isVisible(void) const
    {
        if (!mVisible || mBeyondFarDistance || mRenderingDisabled)
            return false;

        SceneManager* sm = Root::getSingleton()._getCurrentSceneManager();
        if (sm && !(getVisibilityFlags() & sm->_getCombinedVisibilityMask()))
            return false;

        return true;
    }
	//-----------------------------------------------------------------------
	void MovableObject::_notifyCurrentCamera(Camera* cam)
	{
		if (mParentNode)
		{
			if (cam->getUseRenderingDistance() && mUpperDistance > 0)
			{
				Real rad = getBoundingRadius();
				Real squaredDepth = mParentNode->getSquaredViewDepth(cam->getLodCamera());

				const Vector3& scl = mParentNode->_getDerivedScale();
				Real factor = std::max(std::max(scl.x, scl.y), scl.z);

				// Max distance to still render
				Real maxDist = mUpperDistance + rad * factor;
				if (squaredDepth > Math::Sqr(maxDist))
				{
					mBeyondFarDistance = true;
				}
				else
				{
					mBeyondFarDistance = false;
				}
			}
			else
			{
				mBeyondFarDistance = false;
			}

            // Construct event object
            MovableObjectLodChangedEvent evt;
            evt.movableObject = this;
            evt.camera = cam;

            // Notify lod event listeners
            cam->getSceneManager()->_notifyMovableObjectLodChanged(evt);

		}

        mRenderingDisabled = mListener && !mListener->objectRendering(this, cam);
	}
    //-----------------------------------------------------------------------
    void MovableObject::setRenderQueueGroup(uint8 queueID)
    {
		assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!");
        mRenderQueueID = queueID;
        mRenderQueueIDSet = true;
    }

	//-----------------------------------------------------------------------
	void MovableObject::setRenderQueueGroupAndPriority(uint8 queueID, ushort priority)
	{
		setRenderQueueGroup(queueID);
		mRenderQueuePriority = priority;
		mRenderQueuePrioritySet = true;

	}

    //-----------------------------------------------------------------------
    uint8 MovableObject::getRenderQueueGroup(void) const
    {
        return mRenderQueueID;
    }
    //-----------------------------------------------------------------------
	const Matrix4& MovableObject::_getParentNodeFullTransform(void) const
	{

		if(mParentNode)
		{
			// object attached to a sceneNode
			return mParentNode->_getFullTransform();
		}
        // fallback
        return Matrix4::IDENTITY;
	}
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getWorldBoundingBox(bool derive) const
    {
        if (derive)
        {
            mWorldAABB = this->getBoundingBox();
            mWorldAABB.transformAffine(_getParentNodeFullTransform());
        }

        return mWorldAABB;

    }
    //-----------------------------------------------------------------------
	const Sphere& MovableObject::getWorldBoundingSphere(bool derive) const
	{
		if (derive)
		{
			const Vector3& scl = mParentNode->_getDerivedScale();
			Real factor = std::max(std::max(scl.x, scl.y), scl.z);
			mWorldBoundingSphere.setRadius(getBoundingRadius() * factor);
			mWorldBoundingSphere.setCenter(mParentNode->_getDerivedPosition());
		}
		return mWorldBoundingSphere;
	}
    //-----------------------------------------------------------------------
    const LightList& MovableObject::queryLights(void) const
    {
        // Try listener first
        if (mListener)
        {
            const LightList* lightList =
                mListener->objectQueryLights(this);
            if (lightList)
            {
                return *lightList;
            }
        }

        // Query from parent entity if exists
        if (mParentIsTagPoint)
        {
            TagPoint* tp = static_cast<TagPoint*>(mParentNode);
            return tp->getParentEntity()->queryLights();
        }

        if (mParentNode)
        {
            SceneNode* sn = static_cast<SceneNode*>(mParentNode);

            // Make sure we only update this only if need.
            ulong frame = sn->getCreator()->_getLightsDirtyCounter();
            if (mLightListUpdated != frame)
            {
                mLightListUpdated = frame;

				const Vector3& scl = mParentNode->_getDerivedScale();
				Real factor = std::max(std::max(scl.x, scl.y), scl.z);

                sn->findLights(mLightList, this->getBoundingRadius() * factor, this->getLightMask());
            }
        }
        else
        {
            mLightList.clear();
        }

        return mLightList;
    }
    //-----------------------------------------------------------------------
    ShadowCaster::ShadowRenderableListIterator MovableObject::getShadowVolumeRenderableIterator(
        ShadowTechnique shadowTechnique, const Light* light,
        HardwareIndexBufferSharedPtr* indexBuffer,
        bool inExtrudeVertices, Real extrusionDist, unsigned long flags )
    {
        static ShadowRenderableList dummyList;
        return ShadowRenderableListIterator(dummyList.begin(), dummyList.end());
    }
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getLightCapBounds(void) const
    {
        // Same as original bounds
        return getWorldBoundingBox();
    }
    //-----------------------------------------------------------------------
    const AxisAlignedBox& MovableObject::getDarkCapBounds(const Light& light, Real extrusionDist) const
    {
        // Extrude own light cap bounds
        mWorldDarkCapBounds = getLightCapBounds();
        this->extrudeBounds(mWorldDarkCapBounds, light.getAs4DVector(),
            extrusionDist);
        return mWorldDarkCapBounds;

    }
    //-----------------------------------------------------------------------
    Real MovableObject::getPointExtrusionDistance(const Light* l) const
    {
        if (mParentNode)
        {
            return getExtrusionDistance(mParentNode->_getDerivedPosition(), l);
        }
        else
        {
            return 0;
        }
    }
	//-----------------------------------------------------------------------
	uint32 MovableObject::getTypeFlags(void) const
	{
		if (mCreator)
		{
			return mCreator->getTypeFlags();
		}
		else
		{
			return 0xFFFFFFFF;
		}
	}
	//---------------------------------------------------------------------
	void MovableObject::setLightMask(uint32 lightMask)
	{
		this->mLightMask = lightMask;
		//make sure to request a new light list from the scene manager if mask changed
		mLightListUpdated = 0;
	}
	//---------------------------------------------------------------------
	class MORecvShadVisitor : public Renderable::Visitor
	{
	public:
		bool anyReceiveShadows;
		MORecvShadVisitor() : anyReceiveShadows(false)
		{

		}
		void visit(Renderable* rend, ushort lodIndex, bool isDebug,
			Any* pAny = 0)
		{
			Technique* tech = rend->getTechnique();
			bool techReceivesShadows = tech && tech->getParent()->getReceiveShadows();
			anyReceiveShadows = anyReceiveShadows ||
				techReceivesShadows || !tech;
		}
	};
	//---------------------------------------------------------------------
	bool MovableObject::getReceivesShadows()
	{
		MORecvShadVisitor visitor;
		visitRenderables(&visitor);
		return visitor.anyReceiveShadows;

	}
	//-----------------------------------------------------------------------
	//-----------------------------------------------------------------------
	MovableObject* MovableObjectFactory::createInstance(
		const String& name, SceneManager* manager,
		const NameValuePairList* params)
	{
		MovableObject* m = createInstanceImpl(name, params);
		m->_notifyCreator(this);
		m->_notifyManager(manager);
		return m;
	}

}

<|endoftext|>


<commit_before>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/shared_memory_handle.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/gpu_messages.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"

namespace content {

// Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO
// thread. This does very similar what MessageFilter usually does. It is not
// MessageFilter because GpuChannelHost doesn't support AddFilter.
class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener,
                                               public base::NonThreadSafe {
 public:
  Receiver(Client* client,
           const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
      : client_(client),
        io_task_runner_(io_task_runner),
        weak_factory_for_io_(this) {
    DCHECK(CalledOnValidThread());
  }

  ~Receiver() override { DCHECK(CalledOnValidThread()); }

  void InvalidateWeakPtr(base::WaitableEvent* event) {
    DCHECK(io_task_runner_->BelongsToCurrentThread());
    weak_factory_for_io_.InvalidateWeakPtrs();
    event->Signal();
  }

  // IPC::Listener implementation.
  void OnChannelError() override {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    OnDecodeAck(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
  }

  bool OnMessageReceived(const IPC::Message& msg) override {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(GpuJpegDecodeAcceleratorHost::Receiver, msg)
    IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderHostMsg_DecodeAck, OnDecodeAck)
    IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    DCHECK(handled);
    return handled;
  }

  base::WeakPtr<IPC::Listener> AsWeakPtrForIO() {
    return weak_factory_for_io_.GetWeakPtr();
  }

 private:
  void OnDecodeAck(int32_t bitstream_buffer_id, Error error) {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    if (!client_)
      return;

    if (error == media::JpegDecodeAccelerator::NO_ERRORS) {
      client_->VideoFrameReady(bitstream_buffer_id);
    } else {
      // Only NotifyError once.
      // Client::NotifyError() may trigger deletion of |this| (on another
      // thread), so calling it needs to be the last thing done on this stack!
      media::JpegDecodeAccelerator::Client* client = nullptr;
      std::swap(client, client_);
      client->NotifyError(bitstream_buffer_id, error);
    }
  }

  Client* client_;

  // GPU IO task runner.
  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;

  // Weak pointers will be invalidated on IO thread.
  base::WeakPtrFactory<Receiver> weak_factory_for_io_;

  DISALLOW_COPY_AND_ASSIGN(Receiver);
};

GpuJpegDecodeAcceleratorHost::GpuJpegDecodeAcceleratorHost(
    GpuChannelHost* channel,
    int32 route_id,
    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
    : channel_(channel),
      decoder_route_id_(route_id),
      io_task_runner_(io_task_runner) {
  DCHECK(channel_);
  DCHECK_NE(decoder_route_id_, MSG_ROUTING_NONE);
}

GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() {
  DCHECK(CalledOnValidThread());
  Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_));

  channel_->RemoveRoute(decoder_route_id_);

  // Invalidate weak ptr of |receiver_|. After that, no more messages will be
  // routed to |receiver_| on IO thread.
  base::WaitableEvent event(false, false);
  io_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(&Receiver::InvalidateWeakPtr,
                 base::Unretained(receiver_.get()), base::Unretained(&event)));
  event.Wait();
}

bool GpuJpegDecodeAcceleratorHost::Initialize(
    media::JpegDecodeAccelerator::Client* client) {
  DCHECK(CalledOnValidThread());

  bool succeeded = false;
  // This cannot be on IO thread because the msg is synchronous.
  Send(new GpuMsg_CreateJpegDecoder(decoder_route_id_, &succeeded));

  if (!succeeded) {
    DLOG(ERROR) << "Send(GpuMsg_CreateJpegDecoder()) failed";
    return false;
  }

  receiver_.reset(new Receiver(client, io_task_runner_));

  return true;
}

void GpuJpegDecodeAcceleratorHost::Decode(
    const media::BitstreamBuffer& bitstream_buffer,
    const scoped_refptr<media::VideoFrame>& video_frame) {
  DCHECK(CalledOnValidThread());

  DCHECK(
      base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle()));

  base::SharedMemoryHandle input_handle =
      channel_->ShareToGpuProcess(bitstream_buffer.handle());
  if (!base::SharedMemory::IsHandleValid(input_handle)) {
    DLOG(ERROR) << "Failed to duplicate handle of BitstreamBuffer";
    return;
  }
  base::SharedMemoryHandle output_handle =
      channel_->ShareToGpuProcess(video_frame->shared_memory_handle());
  if (!base::SharedMemory::IsHandleValid(output_handle)) {
    DLOG(ERROR) << "Failed to duplicate handle of VideoFrame";
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
    if (input_handle.auto_close) {
      // Defer closing task to the ScopedFD.
      base::ScopedFD(input_handle.fd);
    }
#else
    // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved.
#endif
    return;
  }

  size_t output_buffer_size = media::VideoFrame::AllocationSize(
      video_frame->format(), video_frame->coded_size());

  AcceleratedJpegDecoderMsg_Decode_Params decode_params;
  decode_params.coded_size = video_frame->coded_size();
  decode_params.input_buffer_id = bitstream_buffer.id();
  decode_params.input_buffer_handle = input_handle;
  decode_params.input_buffer_size = bitstream_buffer.size();
  decode_params.output_video_frame_handle = output_handle;
  decode_params.output_buffer_size = output_buffer_size;
  Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_, decode_params));
}

void GpuJpegDecodeAcceleratorHost::Send(IPC::Message* message) {
  DCHECK(CalledOnValidThread());

  if (!channel_->Send(message)) {
    DLOG(ERROR) << "Send(" << message->type() << ") failed";
  }
}

base::WeakPtr<IPC::Listener> GpuJpegDecodeAcceleratorHost::GetReceiver() {
  return receiver_->AsWeakPtrForIO();
}

}  // namespace content
<commit_msg>Fix crash if enable MJPEG acceleration on unsupported platform<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/shared_memory_handle.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/gpu_messages.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"

namespace content {

// Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO
// thread. This does very similar what MessageFilter usually does. It is not
// MessageFilter because GpuChannelHost doesn't support AddFilter.
class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener,
                                               public base::NonThreadSafe {
 public:
  Receiver(Client* client,
           const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
      : client_(client),
        io_task_runner_(io_task_runner),
        weak_factory_for_io_(this) {
    DCHECK(CalledOnValidThread());
  }

  ~Receiver() override { DCHECK(CalledOnValidThread()); }

  void InvalidateWeakPtr(base::WaitableEvent* event) {
    DCHECK(io_task_runner_->BelongsToCurrentThread());
    weak_factory_for_io_.InvalidateWeakPtrs();
    event->Signal();
  }

  // IPC::Listener implementation.
  void OnChannelError() override {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    OnDecodeAck(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
  }

  bool OnMessageReceived(const IPC::Message& msg) override {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(GpuJpegDecodeAcceleratorHost::Receiver, msg)
    IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderHostMsg_DecodeAck, OnDecodeAck)
    IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    DCHECK(handled);
    return handled;
  }

  base::WeakPtr<IPC::Listener> AsWeakPtrForIO() {
    return weak_factory_for_io_.GetWeakPtr();
  }

 private:
  void OnDecodeAck(int32_t bitstream_buffer_id, Error error) {
    DCHECK(io_task_runner_->BelongsToCurrentThread());

    if (!client_)
      return;

    if (error == media::JpegDecodeAccelerator::NO_ERRORS) {
      client_->VideoFrameReady(bitstream_buffer_id);
    } else {
      // Only NotifyError once.
      // Client::NotifyError() may trigger deletion of |this| (on another
      // thread), so calling it needs to be the last thing done on this stack!
      media::JpegDecodeAccelerator::Client* client = nullptr;
      std::swap(client, client_);
      client->NotifyError(bitstream_buffer_id, error);
    }
  }

  Client* client_;

  // GPU IO task runner.
  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;

  // Weak pointers will be invalidated on IO thread.
  base::WeakPtrFactory<Receiver> weak_factory_for_io_;

  DISALLOW_COPY_AND_ASSIGN(Receiver);
};

GpuJpegDecodeAcceleratorHost::GpuJpegDecodeAcceleratorHost(
    GpuChannelHost* channel,
    int32 route_id,
    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
    : channel_(channel),
      decoder_route_id_(route_id),
      io_task_runner_(io_task_runner) {
  DCHECK(channel_);
  DCHECK_NE(decoder_route_id_, MSG_ROUTING_NONE);
}

GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() {
  DCHECK(CalledOnValidThread());
  Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_));

  if (receiver_) {
    channel_->RemoveRoute(decoder_route_id_);

    // Invalidate weak ptr of |receiver_|. After that, no more messages will be
    // routed to |receiver_| on IO thread.
    base::WaitableEvent event(false, false);
    io_task_runner_->PostTask(FROM_HERE,
                              base::Bind(&Receiver::InvalidateWeakPtr,
                                         base::Unretained(receiver_.get()),
                                         base::Unretained(&event)));
    event.Wait();
  }
}

bool GpuJpegDecodeAcceleratorHost::Initialize(
    media::JpegDecodeAccelerator::Client* client) {
  DCHECK(CalledOnValidThread());

  bool succeeded = false;
  // This cannot be on IO thread because the msg is synchronous.
  Send(new GpuMsg_CreateJpegDecoder(decoder_route_id_, &succeeded));

  if (!succeeded) {
    DLOG(ERROR) << "Send(GpuMsg_CreateJpegDecoder()) failed";
    return false;
  }

  receiver_.reset(new Receiver(client, io_task_runner_));

  return true;
}

void GpuJpegDecodeAcceleratorHost::Decode(
    const media::BitstreamBuffer& bitstream_buffer,
    const scoped_refptr<media::VideoFrame>& video_frame) {
  DCHECK(CalledOnValidThread());

  DCHECK(
      base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle()));

  base::SharedMemoryHandle input_handle =
      channel_->ShareToGpuProcess(bitstream_buffer.handle());
  if (!base::SharedMemory::IsHandleValid(input_handle)) {
    DLOG(ERROR) << "Failed to duplicate handle of BitstreamBuffer";
    return;
  }
  base::SharedMemoryHandle output_handle =
      channel_->ShareToGpuProcess(video_frame->shared_memory_handle());
  if (!base::SharedMemory::IsHandleValid(output_handle)) {
    DLOG(ERROR) << "Failed to duplicate handle of VideoFrame";
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
    if (input_handle.auto_close) {
      // Defer closing task to the ScopedFD.
      base::ScopedFD(input_handle.fd);
    }
#else
    // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved.
#endif
    return;
  }

  size_t output_buffer_size = media::VideoFrame::AllocationSize(
      video_frame->format(), video_frame->coded_size());

  AcceleratedJpegDecoderMsg_Decode_Params decode_params;
  decode_params.coded_size = video_frame->coded_size();
  decode_params.input_buffer_id = bitstream_buffer.id();
  decode_params.input_buffer_handle = input_handle;
  decode_params.input_buffer_size = bitstream_buffer.size();
  decode_params.output_video_frame_handle = output_handle;
  decode_params.output_buffer_size = output_buffer_size;
  Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_, decode_params));
}

void GpuJpegDecodeAcceleratorHost::Send(IPC::Message* message) {
  DCHECK(CalledOnValidThread());

  if (!channel_->Send(message)) {
    DLOG(ERROR) << "Send(" << message->type() << ") failed";
  }
}

base::WeakPtr<IPC::Listener> GpuJpegDecodeAcceleratorHost::GetReceiver() {
  return receiver_->AsWeakPtrForIO();
}

}  // namespace content
<|endoftext|>


<commit_before>#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define MAX_BUF 1024

#include <sstream>
#include <iostream>
#include <string>
using namespace std;
#include <boost/property_tree/json_parser.hpp>

static int fd = -1;
#include <signal.h>
#include <stdio.h>
void sigcatch(int) {
	if(fd > 0) {
		close(fd);
	}
	exit(0);
}
int main(int ac,char*av[])
{
	if (SIG_ERR == signal(SIGINT, sigcatch)) {
		printf("failed to set signal handler.n");
		exit(1);
	}
     fd = socket( AF_LOCAL, SOCK_DGRAM, 0 );

	struct sockaddr_un addr;
	bzero( &addr, sizeof(addr) );
	addr.sun_family = AF_LOCAL;
	strcpy( addr.sun_path, "/tmp/mpu.6050.unix.domain" );

   int use = 1;
   if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &use, sizeof(int)) < 0) {
    perror("setsockopt(SO_REUSEADDR) failed");
   }
   if(::bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
   {

     printf(" cannot bind socket: %d. \n",errno);
     close(fd);

     return 0;

   }

    char buf[MAX_BUF];
    double degree = 20.0;
    double startDeg = 0.0;
    bool first = true;
    while(degree >0) {
    	socklen_t len = sizeof(addr);
        int ret = ::recvfrom(fd, buf, MAX_BUF, 0, (struct sockaddr *)&addr, &len);
        if(ret>0){
            //printf("Received: %s\n", buf);
            string recvStr(buf,ret);
            //std::cout << recvStr << std::endl;
            std::stringstream ss;
            ss << recvStr;
            try {
            	boost::property_tree::ptree pt;
            	boost::property_tree::read_json(ss, pt);
            	auto current = pt.get<double>("yaw");
            	//std::cout <<  current << std::endl;
            	if(first) {
            		startDeg = current;
            	}
            	auto diff = current - startDeg;
            	std::cout <<  "diff=<" << diff <<">"<< std::endl;
            	if( diff >= degree) {
            		break;
            	}
            } catch(std::exception e) {
            	std::cout << e.what() << std::endl;
            }
        } else if (ret==0){
        } else {
            printf("ret=<%d>\n",ret);
        }
    }
    close(fd);

    return 0;
}
<commit_msg>Update turn.cpp<commit_after>#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define MAX_BUF 1024

#include <sstream>
#include <iostream>
#include <string>
using namespace std;
#include <boost/property_tree/json_parser.hpp>

static int fd = -1;
#include <signal.h>
#include <stdio.h>
void sigcatch(int) {
	if(fd > 0) {
		close(fd);
	}
	exit(0);
}
int main(int ac,char*av[])
{
	if (SIG_ERR == signal(SIGINT, sigcatch)) {
		printf("failed to set signal handler.n");
		exit(1);
	}
     fd = socket( AF_LOCAL, SOCK_DGRAM, 0 );

	struct sockaddr_un addr;
	bzero( &addr, sizeof(addr) );
	addr.sun_family = AF_LOCAL;
	strcpy( addr.sun_path, "/tmp/mpu.6050.unix.domain" );

   int use = 1;
   if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &use, sizeof(int)) < 0) {
    perror("setsockopt(SO_REUSEADDR) failed");
   }
   if(::bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
   {

     printf(" cannot bind socket: %d. \n",errno);
     close(fd);

     return 0;

   }

    char buf[MAX_BUF];
    double degree = 20.0;
    double startDeg = 0.0;
    bool first = true;
    while(degree >0) {
    	socklen_t len = sizeof(addr);
        int ret = ::recvfrom(fd, buf, MAX_BUF, 0, (struct sockaddr *)&addr, &len);
        if(ret>0){
            //printf("Received: %s\n", buf);
            string recvStr(buf,ret);
            //std::cout << recvStr << std::endl;
            std::stringstream ss;
            ss << recvStr;
            try {
            	boost::property_tree::ptree pt;
            	boost::property_tree::read_json(ss, pt);
            	auto current = pt.get<double>("yaw");
            	//std::cout <<  current << std::endl;
            	if(first) {
            		startDeg = current;
            		first = false;
            	}
            	auto diff = current - startDeg;
            	std::cout <<  "diff=<" << diff <<">"<< std::endl;
            	if( diff >= degree) {
            		break;
            	}
            } catch(std::exception e) {
            	std::cout << e.what() << std::endl;
            }
        } else if (ret==0){
        } else {
            printf("ret=<%d>\n",ret);
        }
    }
    close(fd);

    return 0;
}
<|endoftext|>


<commit_before>#include "ComboBox.h"
#define _CRT_SECURE_NO_WARNINGS

int coloredLine;
int backgroundLine;
DWORD regularAttr;

ComboBox::ComboBox(int x, int y, char* options[], int size) {
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//defualt text width
	width = 15;
	coloredLine = -1;
	backgroundLine = -1;
	//set in the request position
	c = { (short)x, (short)y };

	//cursor size
	CONSOLE_CURSOR_INFO cci = { 100, FALSE };
	SetConsoleCursorInfo(handle, &cci);

	//dynamic allocations
	choosen = (char*)calloc(width, sizeof(char));
	listSize = size;
	list = (char**)calloc(size, sizeof(char*));
	int i;
	for (i = 0; i < size; i++) {
		list[i] = (char*)calloc(width, sizeof(char));
		strcpy_s(list[i], width, options[i]);
	}
	//init parameters
	isOpen = false;
	init();
}

ComboBox::~ComboBox() {
	//free allocation
	free(choosen);
	int i;
	for (i = 0; i < listSize; i++) {
		free(list[i]);
	}
}

void ComboBox::init() {

	int i, j;
	boolean endFlag;
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	DWORD wAttr2 = cbi.wAttributes | BACKGROUND_BLUE;
	//initialize the top box
	SetConsoleCursorPosition(handle, c);
	GetConsoleScreenBufferInfo(handle, &cbi);
	regularAttr = cbi.wAttributes;
	SetConsoleTextAttribute(handle, wAttr2);
	for (i = 0; i < width - 1; i++) {
		choosen[i] = ' ';
		printf("%c", choosen[i]);
	}
	wAttr2 = cbi.wAttributes | BACKGROUND_RED;
	SetConsoleTextAttribute(handle, wAttr2);
	choosen[width] = '>';
	printf("%c", choosen[width]);

	//set char ' ' for the printing(on the rest of the options)
	for (i = 0; i < listSize; i++) {
		endFlag = false;
		for (j = 0; j < width; j++) {
			if (list[i][j] == '\0' || endFlag == true) {
				list[i][j] = ' ';
				endFlag = true;
			}
		}
		endFlag = false;
	}
}

//show the options - printing them in the correct position
void ComboBox::showOptions() {
	int i;
	for (i = 0; i < listSize; i++) {
		printDelimiter(i * 2 + 1);
		printOption(i * 2 + 2, i);
	}
	printDelimiter(i * 2 + 1);
}

//hide the options - printing ' ' in the correct position
void ComboBox::hideOptions() {
	int i;
	for (i = 1; i <= 2 * listSize + 1; i++) {
		printSpace(i);
	}
}

//printing the requested option to the top box
void ComboBox::chooseOption(int position, int lastColoredLine) {
	int listNum = position / 2 - 1 , i;
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	DWORD wAttr2 = cbi.wAttributes | BACKGROUND_BLUE;

	SetConsoleCursorPosition(handle, c);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, wAttr2);
	for (i = 0; i < width - 1; i++) {
		choosen[i] = list[listNum][i];
		printf("%c", choosen[i]);
	}
	setSelected(lastColoredLine);
}

void ComboBox::setSelected(int lastColoredLine) {
	printOption(lastColoredLine * 2 + 2, lastColoredLine);
	printOption(coloredLine * 2 + 2, coloredLine);
}

//print delimiter '-' all over the requested line (separate each option)
void ComboBox::printDelimiter(int position) {
	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf("-");
	}
}

//print the option
void ComboBox::printOption(int position, int itemNum) {
	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf("%c", list[itemNum][i]);
	}
}

void ComboBox::printOptionHoverd(int position, int lastBackgroundLine) {
	int lastPos = lastBackgroundLine * 2 + 2, i;
	COORD newCoord = { c.X, c.Y + (short)position };
	COORD lastCoord = { c.X, c.Y + (short)lastPos };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	DWORD wAttr = BACKGROUND_INTENSITY;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	if (backgroundLine == lastBackgroundLine) {
		return;
	}
	else {
		SetConsoleTextAttribute(handle, wAttr);
		//set hover on the new position
		for (i = 0; i < width; i++) {
			printf("%c", list[backgroundLine][i]);
		}
		//if (lastPos == 0) return;
		SetConsoleCursorPosition(handle, lastCoord);
		SetConsoleTextAttribute(handle, regularAttr);
		//set non hover on the last position
		for (i = 0; i < width; i++) {
			printf("%c", list[lastBackgroundLine][i]);
		}
	}
}

//print ' ' (space) for the hiding functioallity
void ComboBox::printSpace(int position) {

	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf(" ");
	}
}

//listening for any mouse click and handle if relevnt
void ComboBox::handleInput(INPUT_RECORD iRecord) {
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	switch (iRecord.EventType)
	{
	case MOUSE_EVENT: // mouse input
		MouseEventProc(iRecord.Event.MouseEvent);
		break;

	default:
		break;
	}
}

void ComboBox::MouseEventProc(MOUSE_EVENT_RECORD mer) {
#ifndef MOUSE_HWHEELED
#define MOUSE_HWHEELED 0x0008
#endif
	switch (mer.dwEventFlags) {

	case 0:
		//Right button press
		if (mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) {
			checkClickedPosition(mer.dwMousePosition);
		}
		break;
	case MOUSE_MOVED:
		//Right button press
		setHover(mer.dwMousePosition);
		break;
	}
}

void ComboBox::setHover(COORD dwMousePosition) {
	int x = dwMousePosition.X, y = dwMousePosition.Y,
			i, lastBackgroundLine;

	if (x >= c.X + 2 && x <= c.X + 15 && y >= c.Y && y <= c.Y + listSize * 2) {
		for (i = 2; i <= 2 * listSize; i += 2) {
			if (dwMousePosition.Y == c.Y + i) {
				lastBackgroundLine = backgroundLine;
				backgroundLine = i / 2 - 1;
				if (lastBackgroundLine == -1) lastBackgroundLine = 0;
				printOptionHoverd(i, lastBackgroundLine);
			}
		}
	}
}

//check if the clicked is relevant for this combo box.
//if yes - check the click position and choose the right operation
void ComboBox::checkClickedPosition(COORD dwMousePosition) {
	int lastColoredLine;

	if (dwMousePosition.X == c.X + width - 1 && dwMousePosition.Y == c.Y) {
		if (isOpen == true) {
			isOpen = false;
			hideOptions();
		}
		else {
			isOpen = true;
			showOptions();
		}
	}
	else if (dwMousePosition.X >= c.X && dwMousePosition.X < c.X + width) {
		for (int i = 2; i <= 2 * listSize; i += 2) {
			if (dwMousePosition.Y == c.Y + i) {
				lastColoredLine = coloredLine;
				coloredLine = i / 2 - 1;
				if (lastColoredLine == -1) lastColoredLine = 0;
				chooseOption(i, lastColoredLine);
			}
		}
	}
}<commit_msg>combo box - final<commit_after>#include "ComboBox.h"
#define _CRT_SECURE_NO_WARNINGS

int coloredLine;
int backgroundLine;
DWORD regularAttr;

ComboBox::ComboBox(int x, int y, char* options[], int size) {
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//defualt text width
	width = 15;
	coloredLine = -1;
	backgroundLine = -1;
	//set in the request position
	c = { (short)x, (short)y };

	//cursor size
	CONSOLE_CURSOR_INFO cci = { 100, FALSE };
	SetConsoleCursorInfo(handle, &cci);

	//dynamic allocations
	choosen = (char*)calloc(width, sizeof(char));
	listSize = size;
	list = (char**)calloc(size, sizeof(char*));
	int i;
	for (i = 0; i < size; i++) {
		list[i] = (char*)calloc(width, sizeof(char));
		strcpy_s(list[i], width, options[i]);
	}
	//init parameters
	isOpen = false;
	init();
}

ComboBox::~ComboBox() {
	//free allocation
	free(choosen);
	int i;
	for (i = 0; i < listSize; i++) {
		free(list[i]);
	}
}

void ComboBox::init() {

	int i, j;
	boolean endFlag;

	//initialize the top box
	SetConsoleCursorPosition(handle, c);

	CONSOLE_SCREEN_BUFFER_INFO cbi;
	GetConsoleScreenBufferInfo(handle, &cbi);
	regularAttr = cbi.wAttributes;
	DWORD wAttr2 = cbi.wAttributes | BACKGROUND_BLUE;
	SetConsoleTextAttribute(handle, wAttr2);
	for (i = 0; i < width - 1; i++) {
		choosen[i] = ' ';
		printf("%c", choosen[i]);
	}
	wAttr2 = cbi.wAttributes | BACKGROUND_RED;
	SetConsoleTextAttribute(handle, wAttr2);
	choosen[width] = '>';
	printf("%c", choosen[width]);

	//set char ' ' for the printing(on the rest of the options)
	for (i = 0; i < listSize; i++) {
		endFlag = false;
		for (j = 0; j < width; j++) {
			if (list[i][j] == '\0' || endFlag == true) {
				list[i][j] = ' ';
				endFlag = true;
			}
		}
		endFlag = false;
	}
}

//show the options - printing them in the correct position
void ComboBox::showOptions() {
	int i;
	for (i = 0; i < listSize; i++) {
		printDelimiter(i * 2 + 1);
		printOption(i * 2 + 2, i);
	}
	printDelimiter(i * 2 + 1);
}

//hide the options - printing ' ' in the correct position
void ComboBox::hideOptions() {
	int i;
	for (i = 1; i <= 2 * listSize + 1; i++) {
		printSpace(i);
	}
}

//printing the requested option to the top box
void ComboBox::chooseOption(int position, int lastColoredLine) {
	int listNum = position / 2 - 1 , i;
	SetConsoleCursorPosition(handle, c);
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	GetConsoleScreenBufferInfo(handle, &cbi);
	DWORD wAttr2 = cbi.wAttributes | BACKGROUND_BLUE;
	SetConsoleTextAttribute(handle, wAttr2);
	for (i = 0; i < width - 1; i++) {
		choosen[i] = list[listNum][i];
		printf("%c", choosen[i]);
	}
	setSelected(lastColoredLine);
}

void ComboBox::setSelected(int lastColoredLine) {
	printOption(lastColoredLine * 2 + 2, lastColoredLine);
	printOption(coloredLine * 2 + 2, coloredLine);
}

//print delimiter '-' all over the requested line (separate each option)
void ComboBox::printDelimiter(int position) {
	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf("-");
	}
}

//print the option
void ComboBox::printOption(int position, int itemNum) {
	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf("%c", list[itemNum][i]);
	}
}

void ComboBox::printOptionHoverd(int position, int lastBackgroundLine) {
	int lastPos = lastBackgroundLine * 2 + 2, i;
	COORD newCoord = { c.X, c.Y + (short)position };
	COORD lastCoord = { c.X, c.Y + (short)lastPos };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	DWORD wAttr = BACKGROUND_INTENSITY;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	if (backgroundLine == lastBackgroundLine) {
		return;
	}
	else {
		SetConsoleTextAttribute(handle, wAttr);
		//set hover on the new position
		for (i = 0; i < width; i++) {
			printf("%c", list[backgroundLine][i]);
		}
		//if (lastPos == 0) return;
		SetConsoleCursorPosition(handle, lastCoord);
		SetConsoleTextAttribute(handle, regularAttr);
		//set non hover on the last position
		for (i = 0; i < width; i++) {
			printf("%c", list[lastBackgroundLine][i]);
		}
	}
}

//print ' ' (space) for the hiding functioallity
void ComboBox::printSpace(int position) {

	COORD newCoord = { c.X, c.Y + (short)position };
	CONSOLE_SCREEN_BUFFER_INFO cbi;
	int i;

	SetConsoleCursorPosition(handle, newCoord);
	GetConsoleScreenBufferInfo(handle, &cbi);
	SetConsoleTextAttribute(handle, regularAttr);
	for (i = 0; i < width; i++) {
		printf(" ");
	}
}

//listening for any mouse click and handle if relevnt
void ComboBox::handleInput(INPUT_RECORD iRecord) {
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	switch (iRecord.EventType)
	{
	case MOUSE_EVENT: // mouse input
		MouseEventProc(iRecord.Event.MouseEvent);
		break;

	default:
		break;
	}
}

void ComboBox::MouseEventProc(MOUSE_EVENT_RECORD mer) {
#ifndef MOUSE_HWHEELED
#define MOUSE_HWHEELED 0x0008
#endif
	switch (mer.dwEventFlags) {

	case 0:
		//Right button press
		if (mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) {
			checkClickedPosition(mer.dwMousePosition);
		}
		break;
	case MOUSE_MOVED:
		//Right button press
		setHover(mer.dwMousePosition);
		break;
	}
}

void ComboBox::setHover(COORD dwMousePosition) {
	int x = dwMousePosition.X, y = dwMousePosition.Y,
			i, lastBackgroundLine;

	if (x >= c.X + 2 && x <= c.X + 15 && y >= c.Y && y <= c.Y + listSize * 2) {
		for (i = 2; i <= 2 * listSize; i += 2) {
			if (dwMousePosition.Y == c.Y + i) {
				lastBackgroundLine = backgroundLine;
				backgroundLine = i / 2 - 1;
				if (lastBackgroundLine == -1) lastBackgroundLine = 0;
				printOptionHoverd(i, lastBackgroundLine);
			}
		}
	}
}

//check if the clicked is relevant for this combo box.
//if yes - check the click position and choose the right operation
void ComboBox::checkClickedPosition(COORD dwMousePosition) {
	int lastColoredLine;

	if (dwMousePosition.X == c.X + width - 1 && dwMousePosition.Y == c.Y) {
		if (isOpen == true) {
			isOpen = false;
			hideOptions();
		}
		else {
			isOpen = true;
			showOptions();
		}
	}
	else if (dwMousePosition.X >= c.X && dwMousePosition.X < c.X + width) {
		for (int i = 2; i <= 2 * listSize; i += 2) {
			if (dwMousePosition.Y == c.Y + i) {
				lastColoredLine = coloredLine;
				coloredLine = i / 2 - 1;
				if (lastColoredLine == -1) lastColoredLine = 0;
				chooseOption(i, lastColoredLine);
			}
		}
	}
}<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2017-2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CordioPalGap.h"
#include "hci_api.h"

namespace ble {
namespace pal {
namespace vendor {
namespace cordio {

bool Gap::is_feature_supported(
    Gap::ControllerSupportedFeatures_t feature
) {
    return (HciGetLeSupFeat() & (1 << feature.value()));
}

ble_error_t Gap::initialize() {
    return BLE_ERROR_NONE;
}

ble_error_t Gap::terminate() {
    return BLE_ERROR_NONE;
}

address_t Gap::get_device_address() {
    return address_t(HciGetBdAddr());
}

address_t Gap::get_random_address() {
    return device_random_address;
}

ble_error_t Gap::set_random_address(const address_t& address) {
    device_random_address = address;
    DmDevSetRandAddr(const_cast<uint8_t*>(address.data()));
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_advertising_parameters(
    uint16_t advertising_interval_min,
    uint16_t advertising_interval_max,
    advertising_type_t advertising_type,
    own_address_type_t own_address_type,
    advertising_peer_address_type_t peer_address_type,
    const address_t& peer_address,
    advertising_channel_map_t advertising_channel_map,
    advertising_filter_policy_t advertising_filter_policy
) {
    DmAdvSetInterval(
        DM_ADV_HANDLE_DEFAULT,
        advertising_interval_min,
        advertising_interval_max
    );

    DmAdvSetAddrType(own_address_type.value());

    DmAdvSetChannelMap(
        DM_ADV_HANDLE_DEFAULT,
        advertising_channel_map.value()
    );

    DmDevSetFilterPolicy(
        DM_FILT_POLICY_MODE_ADV,
        advertising_filter_policy.value()
    );

    DmAdvConfig(
        DM_ADV_HANDLE_DEFAULT,
        advertising_type.value(),
        peer_address_type.value(),
        const_cast<uint8_t*>(peer_address.data())
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_advertising_data(
    uint8_t advertising_data_length,
    const advertising_data_t& advertising_data
) {
    DmAdvSetData(
        DM_ADV_HANDLE_DEFAULT,
        HCI_ADV_DATA_OP_COMP_FRAG,
        DM_DATA_LOC_ADV,
        advertising_data_length,
        const_cast<uint8_t*>(advertising_data.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_scan_response_data(
    uint8_t scan_response_data_length,
    const advertising_data_t& scan_response_data
) {
    DmAdvSetData(
        DM_ADV_HANDLE_DEFAULT,
        HCI_ADV_DATA_OP_COMP_FRAG,
        DM_DATA_LOC_SCAN,
        scan_response_data_length,
        const_cast<uint8_t*>(scan_response_data.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::advertising_enable(bool enable) {
    if (enable) {
        uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
        uint16_t adv_durations[] = { /* infinite */ 0 };
        uint8_t max_ea_events[] = { 0 };
        DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
    } else {
        uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
        DmAdvStop(1, adv_handles);
    }
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_scan_parameters(
    bool active_scanning,
    uint16_t scan_interval,
    uint16_t scan_window,
    own_address_type_t own_address_type,
    scanning_filter_policy_t filter_policy
) {
    use_active_scanning = active_scanning;
    DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window);
    DmScanSetAddrType(own_address_type.value());
    DmDevSetFilterPolicy(
        DM_FILT_POLICY_MODE_SCAN,
        filter_policy.value()
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::scan_enable(
    bool enable,
    bool filter_duplicates
) {
    if (enable) {
        uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
        DmScanStart(
            HCI_SCAN_PHY_LE_1M_BIT,
            DM_DISC_MODE_NONE,
            &scanType,
            filter_duplicates,
            0,
            0
        );
    } else {
        DmScanStop();
    }
    return BLE_ERROR_NONE;
}

ble_error_t Gap::create_connection(
    uint16_t scan_interval,
    uint16_t scan_window,
    initiator_policy_t initiator_policy,
    connection_peer_address_type_t peer_address_type,
    const address_t& peer_address,
    own_address_type_t own_address_type,
    uint16_t connection_interval_min,
    uint16_t connection_interval_max,
    uint16_t connection_latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    DmConnSetScanInterval(scan_interval, scan_window);
    DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value());
    DmConnSetAddrType(own_address_type.value());

    hciConnSpec_t conn_spec = {
        connection_interval_min,
        connection_interval_max,
        connection_latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmConnSetConnSpec(&conn_spec);

    dmConnId_t connection_id = DmConnOpen(
        DM_CLIENT_ID_APP,
        HCI_INIT_PHY_LE_1M_BIT,
        peer_address_type.value(),
        const_cast<uint8_t*>(peer_address.data())
    );

    if (connection_id == DM_CONN_ID_NONE) {
        return BLE_ERROR_INTERNAL_STACK_FAILURE;
    }

    return BLE_ERROR_NONE;
}

ble_error_t Gap::cancel_connection_creation() {
    DmConnClose(
        DM_CLIENT_ID_APP,
        /* connection handle - invalid */ DM_CONN_ID_NONE,
        /* reason - invalid (use success) */ 0x00
    );
    return BLE_ERROR_NONE;
}

uint8_t Gap::read_white_list_capacity() {
    return HciGetWhiteListSize();
}

ble_error_t Gap::clear_whitelist() {
    DmDevWhiteListClear();
    return BLE_ERROR_NONE;
}

ble_error_t Gap::add_device_to_whitelist(
    whitelist_address_type_t address_type,
    address_t address
) {
    DmDevWhiteListAdd(
        address_type.value(),
        const_cast<uint8_t*>(address.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::remove_device_from_whitelist(
    whitelist_address_type_t address_type,
    address_t address
) {
    DmDevWhiteListRemove(
        address_type.value(),
        const_cast<uint8_t*>(address.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::connection_parameters_update(
    connection_handle_t connection,
    uint16_t connection_interval_min,
    uint16_t connection_interval_max,
    uint16_t connection_latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    if (DmConnCheckIdle(connection) != 0) {
        return BLE_ERROR_INVALID_STATE;
    }

    hciConnSpec_t connection_spec = {
        connection_interval_min,
        connection_interval_max,
        connection_latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmConnUpdate(
        connection,
        &connection_spec
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::accept_connection_parameter_request(
    connection_handle_t connection_handle,
    uint16_t interval_min,
    uint16_t interval_max,
    uint16_t latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    hciConnSpec_t connection_spec = {
        interval_min,
        interval_max,
        latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmRemoteConnParamReqReply(connection_handle, &connection_spec);
    return BLE_ERROR_NONE;
}

ble_error_t Gap::reject_connection_parameter_request(
    connection_handle_t connection_handle,
    hci_error_code_t rejection_reason
) {
    DmRemoteConnParamReqNegReply(
        connection_handle,
        rejection_reason.value()
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::disconnect(
    connection_handle_t connection,
    disconnection_reason_t disconnection_reason
) {
    DmConnClose(
        DM_CLIENT_ID_APP,
        connection,
        disconnection_reason.value()
    );
    return BLE_ERROR_NONE;
}

bool Gap::is_privacy_supported() {
    // We only support controller-based privacy, so return whether the controller supports it
    return HciLlPrivacySupported();
}

ble_error_t Gap::set_address_resolution(
    bool enable
) {
    DmPrivSetAddrResEnable(enable);
    return BLE_ERROR_NONE;
}

ble_error_t Gap::read_phy(connection_handle_t connection) {
    DmReadPhy(connection);
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_preferred_phys(
    const phy_set_t& tx_phys,
    const phy_set_t& rx_phys
) {
    DmSetDefaultPhy(
        create_all_phys_value(tx_phys, rx_phys),
        tx_phys.value(),
        rx_phys.value()
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_phy(
    connection_handle_t connection,
    const phy_set_t& tx_phys,
    const phy_set_t& rx_phys,
    coded_symbol_per_bit_t coded_symbol
) {
    /* if phy set is empty set corresponding all_phys bit to 1 */
    uint8_t all_phys = 0;
    if (tx_phys.value() == 0) {
        all_phys |= 0x01;
    }
    if (rx_phys.value() == 0) {
        all_phys |= 0x02;
    }

    DmSetPhy(
        connection,
        create_all_phys_value(tx_phys, rx_phys),
        tx_phys.value(),
        rx_phys.value(),
        coded_symbol.value()
    );

    return BLE_ERROR_NONE;
}

// singleton of the ARM Cordio client
Gap& Gap::get_gap() {
    static Gap _gap;
    return _gap;
}

/**
 * Callback which handle wsfMsgHdr_t and forward them to emit_gap_event.
 */
void Gap::gap_handler(const wsfMsgHdr_t* msg) {
    typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg);

    if (msg == NULL) {
        return;
    }

    connection_handle_t handle = (connection_handle_t)msg->param;

    switch(msg->event) {
        case DM_PHY_READ_IND:
            if (get_gap()._pal_event_handler) {
                const hciLeReadPhyCmdCmplEvt_t* evt = (const hciLeReadPhyCmdCmplEvt_t*)msg;

                get_gap()._pal_event_handler->on_read_phy(
                    (hci_error_code_t::type)msg->status,
                    handle,
                    (ble::phy_t::type)evt->txPhy,
                    (ble::phy_t::type)evt->rxPhy
                );
            }
            break;
        case DM_PHY_UPDATE_IND:
            if (get_gap()._pal_event_handler) {
                const hciLePhyUpdateEvt_t* evt = (const hciLePhyUpdateEvt_t*)msg;

                get_gap()._pal_event_handler->on_phy_update_complete(
                    (hci_error_code_t::type)msg->status,
                    handle,
                    (ble::phy_t::type)evt->txPhy,
                    (ble::phy_t::type)evt->rxPhy
                );
            }
            break;
    }

    // all handlers are stored in a static array
    static const event_handler_t handlers[] = {
        &event_handler<ConnectionCompleteMessageConverter>,
        &event_handler<GapAdvertisingReportMessageConverter>,
        &event_handler<DisconnectionMessageConverter>,
        &event_handler<ConnectionUpdateMessageConverter>,
        &event_handler<RemoteConnectionParameterRequestMessageConverter>
    };

    // event->hdr.param: connection handle

    // traverse all handlers and execute them with the event in input.
    // exit if an handler has handled the event.
    for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) {
        if (handlers[i](msg)) {
            return;
        }
    }
}

/**
 * T shall define a can_convert and convert function and a type
 */
template<typename T>
bool Gap::event_handler(const wsfMsgHdr_t* msg) {
    if (T::can_convert(msg)) {
        get_gap().emit_gap_event(T::convert((const typename T::type*)msg));
        return true;
    }
    return false;
}

} // cordio
} // vendor
} // pal
} // ble
<commit_msg>check for feature before using<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2017-2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CordioPalGap.h"
#include "hci_api.h"

namespace ble {
namespace pal {
namespace vendor {
namespace cordio {

bool Gap::is_feature_supported(
    Gap::ControllerSupportedFeatures_t feature
) {
    return (HciGetLeSupFeat() & (1 << feature.value()));
}

ble_error_t Gap::initialize() {
    return BLE_ERROR_NONE;
}

ble_error_t Gap::terminate() {
    return BLE_ERROR_NONE;
}

address_t Gap::get_device_address() {
    return address_t(HciGetBdAddr());
}

address_t Gap::get_random_address() {
    return device_random_address;
}

ble_error_t Gap::set_random_address(const address_t& address) {
    device_random_address = address;
    DmDevSetRandAddr(const_cast<uint8_t*>(address.data()));
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_advertising_parameters(
    uint16_t advertising_interval_min,
    uint16_t advertising_interval_max,
    advertising_type_t advertising_type,
    own_address_type_t own_address_type,
    advertising_peer_address_type_t peer_address_type,
    const address_t& peer_address,
    advertising_channel_map_t advertising_channel_map,
    advertising_filter_policy_t advertising_filter_policy
) {
    DmAdvSetInterval(
        DM_ADV_HANDLE_DEFAULT,
        advertising_interval_min,
        advertising_interval_max
    );

    DmAdvSetAddrType(own_address_type.value());

    DmAdvSetChannelMap(
        DM_ADV_HANDLE_DEFAULT,
        advertising_channel_map.value()
    );

    DmDevSetFilterPolicy(
        DM_FILT_POLICY_MODE_ADV,
        advertising_filter_policy.value()
    );

    DmAdvConfig(
        DM_ADV_HANDLE_DEFAULT,
        advertising_type.value(),
        peer_address_type.value(),
        const_cast<uint8_t*>(peer_address.data())
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_advertising_data(
    uint8_t advertising_data_length,
    const advertising_data_t& advertising_data
) {
    DmAdvSetData(
        DM_ADV_HANDLE_DEFAULT,
        HCI_ADV_DATA_OP_COMP_FRAG,
        DM_DATA_LOC_ADV,
        advertising_data_length,
        const_cast<uint8_t*>(advertising_data.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_scan_response_data(
    uint8_t scan_response_data_length,
    const advertising_data_t& scan_response_data
) {
    DmAdvSetData(
        DM_ADV_HANDLE_DEFAULT,
        HCI_ADV_DATA_OP_COMP_FRAG,
        DM_DATA_LOC_SCAN,
        scan_response_data_length,
        const_cast<uint8_t*>(scan_response_data.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::advertising_enable(bool enable) {
    if (enable) {
        uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
        uint16_t adv_durations[] = { /* infinite */ 0 };
        uint8_t max_ea_events[] = { 0 };
        DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
    } else {
        uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
        DmAdvStop(1, adv_handles);
    }
    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_scan_parameters(
    bool active_scanning,
    uint16_t scan_interval,
    uint16_t scan_window,
    own_address_type_t own_address_type,
    scanning_filter_policy_t filter_policy
) {
    use_active_scanning = active_scanning;
    DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window);
    DmScanSetAddrType(own_address_type.value());
    DmDevSetFilterPolicy(
        DM_FILT_POLICY_MODE_SCAN,
        filter_policy.value()
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::scan_enable(
    bool enable,
    bool filter_duplicates
) {
    if (enable) {
        uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
        DmScanStart(
            HCI_SCAN_PHY_LE_1M_BIT,
            DM_DISC_MODE_NONE,
            &scanType,
            filter_duplicates,
            0,
            0
        );
    } else {
        DmScanStop();
    }
    return BLE_ERROR_NONE;
}

ble_error_t Gap::create_connection(
    uint16_t scan_interval,
    uint16_t scan_window,
    initiator_policy_t initiator_policy,
    connection_peer_address_type_t peer_address_type,
    const address_t& peer_address,
    own_address_type_t own_address_type,
    uint16_t connection_interval_min,
    uint16_t connection_interval_max,
    uint16_t connection_latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    DmConnSetScanInterval(scan_interval, scan_window);
    DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value());
    DmConnSetAddrType(own_address_type.value());

    hciConnSpec_t conn_spec = {
        connection_interval_min,
        connection_interval_max,
        connection_latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmConnSetConnSpec(&conn_spec);

    dmConnId_t connection_id = DmConnOpen(
        DM_CLIENT_ID_APP,
        HCI_INIT_PHY_LE_1M_BIT,
        peer_address_type.value(),
        const_cast<uint8_t*>(peer_address.data())
    );

    if (connection_id == DM_CONN_ID_NONE) {
        return BLE_ERROR_INTERNAL_STACK_FAILURE;
    }

    return BLE_ERROR_NONE;
}

ble_error_t Gap::cancel_connection_creation() {
    DmConnClose(
        DM_CLIENT_ID_APP,
        /* connection handle - invalid */ DM_CONN_ID_NONE,
        /* reason - invalid (use success) */ 0x00
    );
    return BLE_ERROR_NONE;
}

uint8_t Gap::read_white_list_capacity() {
    return HciGetWhiteListSize();
}

ble_error_t Gap::clear_whitelist() {
    DmDevWhiteListClear();
    return BLE_ERROR_NONE;
}

ble_error_t Gap::add_device_to_whitelist(
    whitelist_address_type_t address_type,
    address_t address
) {
    DmDevWhiteListAdd(
        address_type.value(),
        const_cast<uint8_t*>(address.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::remove_device_from_whitelist(
    whitelist_address_type_t address_type,
    address_t address
) {
    DmDevWhiteListRemove(
        address_type.value(),
        const_cast<uint8_t*>(address.data())
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::connection_parameters_update(
    connection_handle_t connection,
    uint16_t connection_interval_min,
    uint16_t connection_interval_max,
    uint16_t connection_latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    if (DmConnCheckIdle(connection) != 0) {
        return BLE_ERROR_INVALID_STATE;
    }

    hciConnSpec_t connection_spec = {
        connection_interval_min,
        connection_interval_max,
        connection_latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmConnUpdate(
        connection,
        &connection_spec
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::accept_connection_parameter_request(
    connection_handle_t connection_handle,
    uint16_t interval_min,
    uint16_t interval_max,
    uint16_t latency,
    uint16_t supervision_timeout,
    uint16_t minimum_connection_event_length,
    uint16_t maximum_connection_event_length
) {
    hciConnSpec_t connection_spec = {
        interval_min,
        interval_max,
        latency,
        supervision_timeout,
        minimum_connection_event_length,
        maximum_connection_event_length
    };
    DmRemoteConnParamReqReply(connection_handle, &connection_spec);
    return BLE_ERROR_NONE;
}

ble_error_t Gap::reject_connection_parameter_request(
    connection_handle_t connection_handle,
    hci_error_code_t rejection_reason
) {
    DmRemoteConnParamReqNegReply(
        connection_handle,
        rejection_reason.value()
    );
    return BLE_ERROR_NONE;
}

ble_error_t Gap::disconnect(
    connection_handle_t connection,
    disconnection_reason_t disconnection_reason
) {
    DmConnClose(
        DM_CLIENT_ID_APP,
        connection,
        disconnection_reason.value()
    );
    return BLE_ERROR_NONE;
}

bool Gap::is_privacy_supported() {
    // We only support controller-based privacy, so return whether the controller supports it
    return HciLlPrivacySupported();
}

ble_error_t Gap::set_address_resolution(
    bool enable
) {
    DmPrivSetAddrResEnable(enable);
    return BLE_ERROR_NONE;
}

ble_error_t Gap::read_phy(connection_handle_t connection) {
    if (is_feature_supported(ControllerSupportedFeatures_t::LE_2M_PHY)
        || is_feature_supported(ControllerSupportedFeatures_t::LE_CODED_PHY)) {
        DmReadPhy(connection);
        return BLE_ERROR_NONE;
    }
    return BLE_ERROR_NOT_IMPLEMENTED;
}

ble_error_t Gap::set_preferred_phys(
    const phy_set_t& tx_phys,
    const phy_set_t& rx_phys
) {
    DmSetDefaultPhy(
        create_all_phys_value(tx_phys, rx_phys),
        tx_phys.value(),
        rx_phys.value()
    );

    return BLE_ERROR_NONE;
}

ble_error_t Gap::set_phy(
    connection_handle_t connection,
    const phy_set_t& tx_phys,
    const phy_set_t& rx_phys,
    coded_symbol_per_bit_t coded_symbol
) {
    /* if phy set is empty set corresponding all_phys bit to 1 */
    uint8_t all_phys = 0;
    if (tx_phys.value() == 0) {
        all_phys |= 0x01;
    }
    if (rx_phys.value() == 0) {
        all_phys |= 0x02;
    }

    DmSetPhy(
        connection,
        create_all_phys_value(tx_phys, rx_phys),
        tx_phys.value(),
        rx_phys.value(),
        coded_symbol.value()
    );

    return BLE_ERROR_NONE;
}

// singleton of the ARM Cordio client
Gap& Gap::get_gap() {
    static Gap _gap;
    return _gap;
}

/**
 * Callback which handle wsfMsgHdr_t and forward them to emit_gap_event.
 */
void Gap::gap_handler(const wsfMsgHdr_t* msg) {
    typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg);

    if (msg == NULL) {
        return;
    }

    connection_handle_t handle = (connection_handle_t)msg->param;

    switch(msg->event) {
        case DM_PHY_READ_IND:
            if (get_gap()._pal_event_handler) {
                const hciLeReadPhyCmdCmplEvt_t* evt = (const hciLeReadPhyCmdCmplEvt_t*)msg;

                get_gap()._pal_event_handler->on_read_phy(
                    (hci_error_code_t::type)msg->status,
                    handle,
                    (ble::phy_t::type)evt->txPhy,
                    (ble::phy_t::type)evt->rxPhy
                );
            }
            break;
        case DM_PHY_UPDATE_IND:
            if (get_gap()._pal_event_handler) {
                const hciLePhyUpdateEvt_t* evt = (const hciLePhyUpdateEvt_t*)msg;

                get_gap()._pal_event_handler->on_phy_update_complete(
                    (hci_error_code_t::type)msg->status,
                    handle,
                    (ble::phy_t::type)evt->txPhy,
                    (ble::phy_t::type)evt->rxPhy
                );
            }
            break;
    }

    // all handlers are stored in a static array
    static const event_handler_t handlers[] = {
        &event_handler<ConnectionCompleteMessageConverter>,
        &event_handler<GapAdvertisingReportMessageConverter>,
        &event_handler<DisconnectionMessageConverter>,
        &event_handler<ConnectionUpdateMessageConverter>,
        &event_handler<RemoteConnectionParameterRequestMessageConverter>
    };

    // event->hdr.param: connection handle

    // traverse all handlers and execute them with the event in input.
    // exit if an handler has handled the event.
    for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) {
        if (handlers[i](msg)) {
            return;
        }
    }
}

/**
 * T shall define a can_convert and convert function and a type
 */
template<typename T>
bool Gap::event_handler(const wsfMsgHdr_t* msg) {
    if (T::can_convert(msg)) {
        get_gap().emit_gap_event(T::convert((const typename T::type*)msg));
        return true;
    }
    return false;
}

} // cordio
} // vendor
} // pal
} // ble
<|endoftext|>


<commit_before>#include "semantic-analysis.h"
#include "deprecated-error.h"
#include "type-check.h"
#ifdef YUNI_OS_UNIX
#include <unistd.h>
#endif
#include "details/ir/emit.h"
#include "ref-unref.h"
#include <limits>

using namespace Yuni;

namespace ny::semantic::intrinsic {

namespace {

bool intrinsicReinterpret(Analyzer& seq, uint32_t lvid) {
	assert(seq.pushedparams.func.indexed.size() == 2);
	uint32_t lhs    = seq.pushedparams.func.indexed[0].lvid;
	uint32_t tolvid = seq.pushedparams.func.indexed[1].lvid;
	auto& cdef = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, tolvid});
	// copy the type, without any check
	auto& spare = seq.cdeftable.substitute(lvid);
	spare.import(cdef);
	spare.qualifiers = cdef.qualifiers;
	if (seq.canGenerateCode())
		ir::emit::copy(seq.out, lvid, lhs);
	auto& lvidinfo = seq.frame->lvids(lvid);
	lvidinfo.synthetic = false;
	if (canBeAcquired(seq, cdef) and seq.canGenerateCode()) { // re-acquire the object
		ir::emit::ref(seq.out, lvid);
		lvidinfo.autorelease = true;
		lvidinfo.scope = seq.frame->scope;
	}
	return true;
}

bool intrinsicMemcheckerHold(Analyzer& seq, uint32_t lvid) {
	seq.cdeftable.substitute(lvid).mutateToVoid();
	uint32_t ptrlvid = seq.pushedparams.func.indexed[0].lvid;
	auto& cdefptr = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, ptrlvid});
	if (not cdefptr.isRawPointer())
		return seq.complainIntrinsicParameter("__nanyc_memchecker_hold", 0, cdefptr, "'__pointer'");
	uint32_t sizelvid = seq.pushedparams.func.indexed[1].lvid;
	auto& cdefsize = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, sizelvid});
	if (not cdefsize.isBuiltinU64())
		return seq.complainIntrinsicParameter("__nanyc_memchecker_hold", 0, cdefsize, "'__u64'");
	if (seq.canGenerateCode())
		ir::emit::memory::hold(seq.out, ptrlvid, sizelvid);
	return true;
}

template<class T> bool intrinsicNanycTypeSizeT(Analyzer& seq, uint32_t lvid) {
	static_assert(sizeof(T) >= sizeof(uint16_t) and sizeof(T) <= sizeof(uint64_t), "size mistmatch");
	ny::CType ctype;
	if (std::numeric_limits<T>::is_signed) {
		switch (sizeof(T)) {
			case sizeof(uint64_t): ctype = ny::CType::t_i64; break;
			case sizeof(uint32_t): ctype = ny::CType::t_i32; break;
			case sizeof(uint16_t): ctype = ny::CType::t_i16; break;
		}
	}
	else {
		switch (sizeof(T)) {
			case sizeof(uint64_t): ctype = ny::CType::t_u64; break;
			case sizeof(uint32_t): ctype = ny::CType::t_u32; break;
			case sizeof(uint16_t): ctype = ny::CType::t_u16; break;
		}
	}
	auto& libtype = seq.cdeftable.atoms().core.object[(uint32_t) ctype];
	seq.cdeftable.substitute(lvid).mutateToAtom(libtype.pointer());
	if (seq.canGenerateCode())
		ir::emit::constantu64(seq.out, lvid, 0);
	return true;
}

using BuiltinIntrinsic = bool (*)(Analyzer&, uint32_t);

static const std::unordered_map<AnyString, std::pair<uint32_t, BuiltinIntrinsic>> builtinDispatch = {
	{"__reinterpret",            { 2, &intrinsicReinterpret }},
	{"__nanyc_memchecker_hold",  { 2, &intrinsicMemcheckerHold }},
	{"__nanyc_type_size_t",      { 0, &intrinsicNanycTypeSizeT<size_t> }},
	{"__nanyc_type_ssize_t",     { 0, &intrinsicNanycTypeSizeT<ssize_t> }},
	{"__nanyc_type_uintptr_t",   { 0, &intrinsicNanycTypeSizeT<uintptr_t> }},
	{"__nanyc_type_intptr_t",    { 0, &intrinsicNanycTypeSizeT<intptr_t> }},
};

} // namespace

Tribool::Value nanycSpecifics(Analyzer& analyzer, const AnyString& name, uint32_t lvid, bool produceError) {
	assert(not name.empty());
	assert(analyzer.frame != nullptr);
	auto it = builtinDispatch.find(name);
	if (unlikely(it == builtinDispatch.end())) {
		if (produceError)
			complain::unknownIntrinsic(name);
		return Tribool::Value::indeterminate;
	}
	// checking for parameters
	uint32_t count = it->second.first;
	if (unlikely(not analyzer.checkForIntrinsicParamCount(name, count)))
		return Tribool::Value::no;
	analyzer.frame->lvids(lvid).synthetic = false;
	// intrinsic builtin found !
	return ((it->second.second))(analyzer, lvid) ? Tribool::Value::yes : Tribool::Value::no;
}

} // ny::semantic::intrinsic
<commit_msg>semantic: add convenient function toTribool<commit_after>#include "semantic-analysis.h"
#include "deprecated-error.h"
#include "type-check.h"
#ifdef YUNI_OS_UNIX
#include <unistd.h>
#endif
#include "details/ir/emit.h"
#include "ref-unref.h"
#include <limits>

using namespace Yuni;

namespace ny::semantic::intrinsic {

namespace {

inline Tribool::Value toTribool(bool flag) {
	return flag ? Tribool::Value::yes : Tribool::Value::no;
}

bool intrinsicReinterpret(Analyzer& seq, uint32_t lvid) {
	assert(seq.pushedparams.func.indexed.size() == 2);
	uint32_t lhs    = seq.pushedparams.func.indexed[0].lvid;
	uint32_t tolvid = seq.pushedparams.func.indexed[1].lvid;
	auto& cdef = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, tolvid});
	// copy the type, without any check
	auto& spare = seq.cdeftable.substitute(lvid);
	spare.import(cdef);
	spare.qualifiers = cdef.qualifiers;
	if (seq.canGenerateCode())
		ir::emit::copy(seq.out, lvid, lhs);
	auto& lvidinfo = seq.frame->lvids(lvid);
	lvidinfo.synthetic = false;
	if (canBeAcquired(seq, cdef) and seq.canGenerateCode()) { // re-acquire the object
		ir::emit::ref(seq.out, lvid);
		lvidinfo.autorelease = true;
		lvidinfo.scope = seq.frame->scope;
	}
	return true;
}

bool intrinsicMemcheckerHold(Analyzer& seq, uint32_t lvid) {
	seq.cdeftable.substitute(lvid).mutateToVoid();
	uint32_t ptrlvid = seq.pushedparams.func.indexed[0].lvid;
	auto& cdefptr = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, ptrlvid});
	if (not cdefptr.isRawPointer())
		return seq.complainIntrinsicParameter("__nanyc_memchecker_hold", 0, cdefptr, "'__pointer'");
	uint32_t sizelvid = seq.pushedparams.func.indexed[1].lvid;
	auto& cdefsize = seq.cdeftable.classdefFollowClassMember(CLID{seq.frame->atomid, sizelvid});
	if (not cdefsize.isBuiltinU64())
		return seq.complainIntrinsicParameter("__nanyc_memchecker_hold", 0, cdefsize, "'__u64'");
	if (seq.canGenerateCode())
		ir::emit::memory::hold(seq.out, ptrlvid, sizelvid);
	return true;
}

template<class T> bool intrinsicNanycTypeSizeT(Analyzer& seq, uint32_t lvid) {
	static_assert(sizeof(T) >= sizeof(uint16_t) and sizeof(T) <= sizeof(uint64_t), "size mistmatch");
	ny::CType ctype;
	if (std::numeric_limits<T>::is_signed) {
		switch (sizeof(T)) {
			case sizeof(uint64_t): ctype = ny::CType::t_i64; break;
			case sizeof(uint32_t): ctype = ny::CType::t_i32; break;
			case sizeof(uint16_t): ctype = ny::CType::t_i16; break;
		}
	}
	else {
		switch (sizeof(T)) {
			case sizeof(uint64_t): ctype = ny::CType::t_u64; break;
			case sizeof(uint32_t): ctype = ny::CType::t_u32; break;
			case sizeof(uint16_t): ctype = ny::CType::t_u16; break;
		}
	}
	auto& libtype = seq.cdeftable.atoms().core.object[(uint32_t) ctype];
	seq.cdeftable.substitute(lvid).mutateToAtom(libtype.pointer());
	if (seq.canGenerateCode())
		ir::emit::constantu64(seq.out, lvid, 0);
	return true;
}

using BuiltinIntrinsic = bool (*)(Analyzer&, uint32_t);

static const std::unordered_map<AnyString, std::pair<uint32_t, BuiltinIntrinsic>> builtinDispatch = {
	{"__reinterpret",            { 2, &intrinsicReinterpret }},
	{"__nanyc_memchecker_hold",  { 2, &intrinsicMemcheckerHold }},
	{"__nanyc_type_size_t",      { 0, &intrinsicNanycTypeSizeT<size_t> }},
	{"__nanyc_type_ssize_t",     { 0, &intrinsicNanycTypeSizeT<ssize_t> }},
	{"__nanyc_type_uintptr_t",   { 0, &intrinsicNanycTypeSizeT<uintptr_t> }},
	{"__nanyc_type_intptr_t",    { 0, &intrinsicNanycTypeSizeT<intptr_t> }},
};

} // namespace

Tribool::Value nanycSpecifics(Analyzer& analyzer, const AnyString& name, uint32_t lvid, bool produceError) {
	assert(not name.empty());
	assert(analyzer.frame != nullptr);
	auto it = builtinDispatch.find(name);
	if (unlikely(it == builtinDispatch.end())) {
		if (produceError)
			complain::unknownIntrinsic(name);
		return Tribool::Value::indeterminate;
	}
	// checking for parameters
	uint32_t count = it->second.first;
	if (unlikely(not analyzer.checkForIntrinsicParamCount(name, count)))
		return Tribool::Value::no;
	analyzer.frame->lvids(lvid).synthetic = false;
	// intrinsic builtin found !
	return toTribool(((it->second.second))(analyzer, lvid));
}

} // ny::semantic::intrinsic
<|endoftext|>