<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fmundo.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 23:21:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SVX_FMUNDO_HXX
#define _SVX_FMUNDO_HXX

#ifndef _SVDUNDO_HXX
#include "svdundo.hxx"
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYCHANGELISTENER_HPP_
#include <com/sun/star/beans/XPropertyChangeListener.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYCHANGEEVENT_HPP_
#include <com/sun/star/beans/PropertyChangeEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_SCRIPTEVENT_HPP_
#include <com/sun/star/script/ScriptEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_XSCRIPTLISTENER_HPP_
#include <com/sun/star/script/XScriptListener.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_SCRIPTEVENTDESCRIPTOR_HPP_
#include <com/sun/star/script/ScriptEventDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XINDEXCONTAINER_HPP_
#include <com/sun/star/container/XIndexContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINERLISTENER_HPP_
#include <com/sun/star/container/XContainerListener.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_CONTAINEREVENT_HPP_
#include <com/sun/star/container/ContainerEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
/** === end UNO includes === **/

#ifndef _CPPUHELPER_IMPLBASE4_HXX_
#include <cppuhelper/implbase4.hxx>
#endif

#ifndef _SFXLSTNER_HXX //autogen
#include <svtools/lstner.hxx>
#endif

#ifndef _SVDOUNO_HXX //autogen wg. SdrUnoObj
#include "svdouno.hxx"
#endif

#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif

class FmFormModel;
class FmFormObj;
class SdrObject;
class FmXFormView;

FORWARD_DECLARE_INTERFACE(awt,XControl)
FORWARD_DECLARE_INTERFACE(awt,XControlContainer)
//FORWARD_DECLARE_INTERFACE(uno,Reference)

//==================================================================
// FmUndoPropertyAction
//==================================================================
class FmUndoPropertyAction: public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xObj;
    ::rtl::OUString         aPropertyName;
    ::com::sun::star::uno::Any          aNewValue;
    ::com::sun::star::uno::Any          aOldValue;

public:
    FmUndoPropertyAction(FmFormModel& rMod, const ::com::sun::star::beans::PropertyChangeEvent& evt);

    virtual void Undo();
    virtual void Redo();

    virtual String          GetComment() const;

};

//==================================================================
// FmUndoContainerAction
//==================================================================
class FmUndoContainerAction: public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >
                    m_xContainer;   // container which the action applies to
    ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                    m_xElement;     // object not owned by the action
    ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                    m_xOwnElement;  // object owned by the action
    sal_Int32       m_nIndex;       // index of the object within it's container
    ::com::sun::star::uno::Sequence< ::com::sun::star::script::ScriptEventDescriptor >
                    m_aEvents;      // events of the object

public:
    enum Action
    {
        Inserted = 1,
        Removed  = 2
    };

private:
    Action              m_eAction;

public:
    FmUndoContainerAction(FmFormModel& rMod,
                          Action _eAction,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >& xCont,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xElem,
                          sal_Int32 nIdx = -1);
    ~FmUndoContainerAction();

    virtual void Undo();
    virtual void Redo();

protected:
    void    implReInsert( ) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
    void    implReRemove( ) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
};

//==================================================================
// FmUndoModelReplaceAction
//==================================================================
class FmUndoModelReplaceAction : public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel> m_xReplaced;
    SdrUnoObj*          m_pObject;

public:
    FmUndoModelReplaceAction(FmFormModel& rMod, SdrUnoObj* pObject, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel>& xReplaced);
    ~FmUndoModelReplaceAction();

    virtual void Undo();
    virtual void Redo() { Undo(); }

    virtual String          GetComment() const;
};

//========================================================================
class SVX_DLLPRIVATE FmXUndoEnvironment
    : public ::cppu::WeakImplHelper4<   ::com::sun::star::beans::XPropertyChangeListener
                                    ,   ::com::sun::star::container::XContainerListener
                                    ,   ::com::sun::star::script::XScriptListener
                                    ,   ::com::sun::star::util::XModifyListener
                                    >
    , public SfxListener
                           //   public ::cppu::OWeakObject
{
    friend class FmXFormView;
    FmFormModel& rModel;

    void*               m_pPropertySetCache;
    oslInterlockedCount m_Locks;
    ::osl::Mutex        m_aMutex;
    sal_Bool            bReadOnly;

    void firing_Impl( const  ::com::sun::star::script::ScriptEvent& evt, ::com::sun::star::uno::Any *pSyncRet=0 );

public:
    FmXUndoEnvironment(FmFormModel& _rModel);
    ~FmXUndoEnvironment();

    // UNO Anbindung
    //  SMART_UNO_DECLARATION(FmXUndoEnvironment, ::cppu::OWeakObject);
    //  virtual sal_Bool queryInterface(UsrUik, ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>&);
    //  virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::reflection::XIdlClass>>    getIdlClasses(void);

    void Lock() { osl_incrementInterlockedCount( &m_Locks ); }
    void UnLock() { osl_decrementInterlockedCount( &m_Locks ); }
    sal_Bool IsLocked() const { return m_Locks != 0; }

    // access control
    struct Accessor { friend class FmFormModel; private: Accessor() { } };

    // addition and removal of form collections
    void AddForms( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer>& rForms );
    void RemoveForms( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer>& rForms );

    // readonly-ness
    void SetReadOnly( sal_Bool bRead, const Accessor& ) { bReadOnly = bRead; }
    sal_Bool IsReadOnly() const {return bReadOnly;}

protected:
    // XEventListener
    virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw( ::com::sun::star::uno::RuntimeException );

    // XPropertyChangeListener
    virtual void SAL_CALL propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException);

    // XContainerListener
    virtual void SAL_CALL elementInserted(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL elementReplaced(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL elementRemoved(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);

    // XScriptListener
    virtual void SAL_CALL firing(const  ::com::sun::star::script::ScriptEvent& evt) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL approveFiring(const  ::com::sun::star::script::ScriptEvent& evt) throw(::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException);

    // XModifyListener
    virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException);

    void ModeChanged();
    void Clear();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

private:
    void AddElement(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);
    void RemoveElement(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);
    void TogglePropertyListening(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);

    void    implSetModified();

    void    switchListening( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >& _rxContainer, bool _bStartListening ) SAL_THROW(());
    void    switchListening( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(());

public:
    // Methoden zur Zuordnung von Controls zu Forms,
    // werden von der Seite und der UndoUmgebung genutzt
    void Inserted(SdrObject* pObj);
    void Removed(SdrObject* pObj);

    void Inserted(FmFormObj* pObj);
    void Removed(FmFormObj* pObj);
};

#endif  //_SVX_FMUNDO_HXX

<commit_msg>INTEGRATION: CWS warnings01 (1.11.222); FILE MERGED 2006/02/15 13:27:37 fs 1.11.222.1: #i55991# warning-free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fmundo.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 16:07:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SVX_FMUNDO_HXX
#define _SVX_FMUNDO_HXX

#ifndef _SVDUNDO_HXX
#include "svdundo.hxx"
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYCHANGELISTENER_HPP_
#include <com/sun/star/beans/XPropertyChangeListener.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYCHANGEEVENT_HPP_
#include <com/sun/star/beans/PropertyChangeEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_SCRIPTEVENT_HPP_
#include <com/sun/star/script/ScriptEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_XSCRIPTLISTENER_HPP_
#include <com/sun/star/script/XScriptListener.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_SCRIPTEVENTDESCRIPTOR_HPP_
#include <com/sun/star/script/ScriptEventDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XINDEXCONTAINER_HPP_
#include <com/sun/star/container/XIndexContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINERLISTENER_HPP_
#include <com/sun/star/container/XContainerListener.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_CONTAINEREVENT_HPP_
#include <com/sun/star/container/ContainerEvent.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
/** === end UNO includes === **/

#ifndef _CPPUHELPER_IMPLBASE4_HXX_
#include <cppuhelper/implbase4.hxx>
#endif

#ifndef _SFXLSTNER_HXX //autogen
#include <svtools/lstner.hxx>
#endif

#ifndef _SVDOUNO_HXX //autogen wg. SdrUnoObj
#include "svdouno.hxx"
#endif

#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif

class FmFormModel;
class FmFormObj;
class SdrObject;
class FmXFormView;

FORWARD_DECLARE_INTERFACE(awt,XControl)
FORWARD_DECLARE_INTERFACE(awt,XControlContainer)
//FORWARD_DECLARE_INTERFACE(uno,Reference)

//==================================================================
// FmUndoPropertyAction
//==================================================================
class FmUndoPropertyAction: public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xObj;
    ::rtl::OUString         aPropertyName;
    ::com::sun::star::uno::Any          aNewValue;
    ::com::sun::star::uno::Any          aOldValue;

public:
    FmUndoPropertyAction(FmFormModel& rMod, const ::com::sun::star::beans::PropertyChangeEvent& evt);

    virtual void Undo();
    virtual void Redo();

    virtual String          GetComment() const;

};

//==================================================================
// FmUndoContainerAction
//==================================================================
class FmUndoContainerAction: public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >
                    m_xContainer;   // container which the action applies to
    ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                    m_xElement;     // object not owned by the action
    ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                    m_xOwnElement;  // object owned by the action
    sal_Int32       m_nIndex;       // index of the object within it's container
    ::com::sun::star::uno::Sequence< ::com::sun::star::script::ScriptEventDescriptor >
                    m_aEvents;      // events of the object

public:
    enum Action
    {
        Inserted = 1,
        Removed  = 2
    };

private:
    Action              m_eAction;

public:
    FmUndoContainerAction(FmFormModel& rMod,
                          Action _eAction,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >& xCont,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xElem,
                          sal_Int32 nIdx = -1);
    ~FmUndoContainerAction();

    virtual void Undo();
    virtual void Redo();

protected:
    void    implReInsert( ) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
    void    implReRemove( ) SAL_THROW( ( ::com::sun::star::uno::Exception ) );
};

//==================================================================
// FmUndoModelReplaceAction
//==================================================================
class FmUndoModelReplaceAction : public SdrUndoAction
{
    ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel> m_xReplaced;
    SdrUnoObj*          m_pObject;

public:
    FmUndoModelReplaceAction(FmFormModel& rMod, SdrUnoObj* pObject, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel>& xReplaced);
    ~FmUndoModelReplaceAction();

    virtual void Undo();
    virtual void Redo() { Undo(); }

    virtual String          GetComment() const;
};

//========================================================================
class SVX_DLLPRIVATE FmXUndoEnvironment
    : public ::cppu::WeakImplHelper4<   ::com::sun::star::beans::XPropertyChangeListener
                                    ,   ::com::sun::star::container::XContainerListener
                                    ,   ::com::sun::star::script::XScriptListener
                                    ,   ::com::sun::star::util::XModifyListener
                                    >
    , public SfxListener
                           //   public ::cppu::OWeakObject
{
    friend class FmXFormView;
    FmFormModel& rModel;

    void*               m_pPropertySetCache;
    oslInterlockedCount m_Locks;
    ::osl::Mutex        m_aMutex;
    sal_Bool            bReadOnly;

    void firing_Impl( const  ::com::sun::star::script::ScriptEvent& evt, ::com::sun::star::uno::Any *pSyncRet=0 );

public:
    FmXUndoEnvironment(FmFormModel& _rModel);
    ~FmXUndoEnvironment();

    // UNO Anbindung
    //  SMART_UNO_DECLARATION(FmXUndoEnvironment, ::cppu::OWeakObject);
    //  virtual sal_Bool queryInterface(UsrUik, ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>&);
    //  virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::reflection::XIdlClass>>    getIdlClasses(void);

    void Lock() { osl_incrementInterlockedCount( &m_Locks ); }
    void UnLock() { osl_decrementInterlockedCount( &m_Locks ); }
    sal_Bool IsLocked() const { return m_Locks != 0; }

    // access control
    struct Accessor { friend class FmFormModel; private: Accessor() { } };

    // addition and removal of form collections
    void AddForms( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer>& rForms );
    void RemoveForms( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer>& rForms );

    // readonly-ness
    void SetReadOnly( sal_Bool bRead, const Accessor& ) { bReadOnly = bRead; }
    sal_Bool IsReadOnly() const {return bReadOnly;}

protected:
    // XEventListener
    virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw( ::com::sun::star::uno::RuntimeException );

    // XPropertyChangeListener
    virtual void SAL_CALL propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException);

    // XContainerListener
    virtual void SAL_CALL elementInserted(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL elementReplaced(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL elementRemoved(const ::com::sun::star::container::ContainerEvent& rEvent) throw(::com::sun::star::uno::RuntimeException);

    // XScriptListener
    virtual void SAL_CALL firing(const  ::com::sun::star::script::ScriptEvent& evt) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL approveFiring(const  ::com::sun::star::script::ScriptEvent& evt) throw(::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException);

    // XModifyListener
    virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException);

    void ModeChanged();
    void Clear();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

private:
    void AddElement(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);
    void RemoveElement(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);
    void TogglePropertyListening(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& Element);

    void    implSetModified();

    void    switchListening( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer >& _rxContainer, bool _bStartListening ) SAL_THROW(());
    void    switchListening( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(());

public:
    // Methoden zur Zuordnung von Controls zu Forms,
    // werden von der Seite und der UndoUmgebung genutzt
    void Inserted(SdrObject* pObj);
    void Removed(SdrObject* pObj);

    void Inserted(FmFormObj* pObj);
    void Removed(FmFormObj* pObj);
};

#endif  //_SVX_FMUNDO_HXX

<|endoftext|>


<commit_before>#ifndef CACHEDICT_H
#define CACHEDICT_H

template <typename K, typename V>
class CacheDict {
    K keys[2];
    V vals[2];
    unsigned size = 0;
    bool flip = true;

public:
    CacheDict() {}

    V* get(const K& key)
    {
        if (size >= 1 && key == keys[0]) {
            return &vals[0];
        } else if (size == 2 && key == keys[1]) {
            return &vals[1];
        }

        return nullptr;
    }

    void save(K key, V val)
    {
        std::size_t index = 0;
        if (flip) {
            index = 1;
        }

        keys[index] = key;
        vals[index] = val;

        size = size < 2 ? ++size : size;
        flip = !flip;
    }
};

#endif<commit_msg>fix flip bit<commit_after>#ifndef CACHEDICT_H
#define CACHEDICT_H

template <typename K, typename V>
class CacheDict {
    K keys[2];
    V vals[2];
    unsigned size = 0;
    bool flip = true;

public:
    CacheDict() {}

    V* get(const K& key)
    {
        if (size >= 1 && key == keys[0]) {
            return &vals[0];
        } else if (size == 2 && key == keys[1]) {
            return &vals[1];
        }

        return nullptr;
    }

    void save(K key, V val)
    {
        std::size_t index = 0;
        if (flip && size >= 2) {
            index = 1;
        }

        keys[index] = key;
        vals[index] = val;

        size = size < 2 ? ++size : size;
        flip = !flip;
    }
};

#endif<|endoftext|>


<commit_before>#include "transaction_type.hpp"
#include "account.hpp"
#include "account_type.hpp"
#include "b_string.hpp"
#include <cassert>
#include <vector>

namespace phatbooks
{

using transaction_type::TransactionType;
using transaction_type::expenditure_transaction;
using transaction_type::revenue_transaction;
using transaction_type::balance_sheet_transaction;
using transaction_type::envelope_transaction;
using transaction_type::generic_transaction;
using transaction_type::num_transaction_types;
using std::vector;

vector<TransactionType> const&
transaction_types()
{
	static vector<TransactionType> ret;
	static bool initialized = false;
	if (!initialized)
	{
		size_t const sz = static_cast<size_t>(num_transaction_types);
		ret.reserve(sz);
		for (size_t i = 0; i != sz; ++i)
		{
			ret.push_back(static_cast<TransactionType>(i));
		}
		initialized = true;
	}
	assert (ret.size() == static_cast<size_t>(num_transaction_types));
	return ret;
}

BString
transaction_type_to_verb(TransactionType p_transaction_type)
{
	switch (p_transaction_type)
	{
	case expenditure_transaction:
		return "Spend";
	case revenue_transaction:
		return "Earn";
	case balance_sheet_transaction:
		return "Transfer between accounts";
	case envelope_transaction:
		return "Transfer between budget envelopes";
	case generic_transaction:
		return "Generic transaction";
	default:
		assert (false);
	}
}

bool
transaction_type_is_actual(TransactionType p_transaction_type)
{
	return p_transaction_type != envelope_transaction;
}

vector<account_type::AccountType> const&
source_account_types
(	transaction_type::TransactionType p_transaction_type
)
{
	static vector<account_type::AccountType>
		ret_array[static_cast<size_t>(num_transaction_types)];
	static bool initialized = false;

	if (!initialized)
	{
#		ifndef NDEBUG
			for
			(	size_t i = 0;
				i != static_cast<size_t>(num_transaction_types);
				++i
			)
			{
				assert (ret_array[i].empty());
			}
#		endif

		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::revenue);

		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::revenue);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::expense);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::pure_envelope);

		// Generic transaction - can handle all AccountTypes;
		ret_array[static_cast<size_t>(generic_transaction)] = account_types();

		// Now we're initialized.
		initialized = true;
	}

#	ifndef NDEBUG
		vector<account_type::AccountType> const& debug_ret =
			ret_array[static_cast<size_t>(p_transaction_type)];
		assert (!debug_ret.empty());
		assert (initialized);
#	endif

	return ret_array[static_cast<size_t>(p_transaction_type)];
}

vector<account_type::AccountType> const&
destination_account_types
(	transaction_type::TransactionType p_transaction_type
)
{
	static vector<account_type::AccountType>
		ret_array[static_cast<size_t>(num_transaction_types)];
	static bool initialized = false;

	if (!initialized)
	{
#		ifndef NDEBUG
			for
			(	size_t i = 0;
				i != static_cast<size_t>(num_transaction_types);
				++i
			)
			{
				assert (ret_array[i].empty());
			}
#		endif

		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::expense);

		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::revenue);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::expense);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::pure_envelope);

		// Generic transaction - can handle all AccountTypes;
		ret_array[static_cast<size_t>(generic_transaction)] = account_types();

		// Now we're initialized.
		initialized = true;
	}

#	ifndef NDEBUG
		vector<account_type::AccountType> const& debug_ret =
			ret_array[static_cast<size_t>(p_transaction_type)];
		assert (!debug_ret.empty());
		assert (initialized);
#	endif

	return ret_array[static_cast<size_t>(p_transaction_type)];
}

TransactionType
natural_transaction_type(Account const& account_x, Account const& account_y)
{
	account_type::AccountType const account_type_x = account_x.account_type();
	account_type::AccountType const account_type_y = account_y.account_type();

	switch (account_type_x)
	{
	case account_type::asset:  // fallthrough
	case account_type::liability:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return balance_sheet_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:
			return revenue_transaction;
		case account_type::expense:
			return expenditure_transaction;
		case account_type::pure_envelope:
			return generic_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::equity:
		return generic_transaction;
	case account_type::revenue:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return revenue_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:  // fallthrough
		case account_type::expense:  // fallthrough
		case account_type::pure_envelope:
			return envelope_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::expense:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return expenditure_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:  // fallthrough
		case account_type::expense:  // fallthrough
		case account_type::pure_envelope:
			return envelope_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::pure_envelope:
		return envelope_transaction;
	default:
		assert (false);
	}

	assert (false);
}

}  // namespace phatbooks
<commit_msg>Made two of the TransactionType "verbs" briefer, so they will fit in the TransactionTypeCtrl as currently sized.<commit_after>#include "transaction_type.hpp"
#include "account.hpp"
#include "account_type.hpp"
#include "b_string.hpp"
#include <cassert>
#include <vector>

namespace phatbooks
{

using transaction_type::TransactionType;
using transaction_type::expenditure_transaction;
using transaction_type::revenue_transaction;
using transaction_type::balance_sheet_transaction;
using transaction_type::envelope_transaction;
using transaction_type::generic_transaction;
using transaction_type::num_transaction_types;
using std::vector;

vector<TransactionType> const&
transaction_types()
{
	static vector<TransactionType> ret;
	static bool initialized = false;
	if (!initialized)
	{
		size_t const sz = static_cast<size_t>(num_transaction_types);
		ret.reserve(sz);
		for (size_t i = 0; i != sz; ++i)
		{
			ret.push_back(static_cast<TransactionType>(i));
		}
		initialized = true;
	}
	assert (ret.size() == static_cast<size_t>(num_transaction_types));
	return ret;
}

BString
transaction_type_to_verb(TransactionType p_transaction_type)
{
	switch (p_transaction_type)
	{
	case expenditure_transaction:
		return "Spend";
	case revenue_transaction:
		return "Earn";
	case balance_sheet_transaction:
		return "Account transfer";
	case envelope_transaction:
		return "Budget transfer";
	case generic_transaction:
		return "Generic";
	default:
		assert (false);
	}
}

bool
transaction_type_is_actual(TransactionType p_transaction_type)
{
	return p_transaction_type != envelope_transaction;
}

vector<account_type::AccountType> const&
source_account_types
(	transaction_type::TransactionType p_transaction_type
)
{
	static vector<account_type::AccountType>
		ret_array[static_cast<size_t>(num_transaction_types)];
	static bool initialized = false;

	if (!initialized)
	{
#		ifndef NDEBUG
			for
			(	size_t i = 0;
				i != static_cast<size_t>(num_transaction_types);
				++i
			)
			{
				assert (ret_array[i].empty());
			}
#		endif

		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::revenue);

		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::revenue);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::expense);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::pure_envelope);

		// Generic transaction - can handle all AccountTypes;
		ret_array[static_cast<size_t>(generic_transaction)] = account_types();

		// Now we're initialized.
		initialized = true;
	}

#	ifndef NDEBUG
		vector<account_type::AccountType> const& debug_ret =
			ret_array[static_cast<size_t>(p_transaction_type)];
		assert (!debug_ret.empty());
		assert (initialized);
#	endif

	return ret_array[static_cast<size_t>(p_transaction_type)];
}

vector<account_type::AccountType> const&
destination_account_types
(	transaction_type::TransactionType p_transaction_type
)
{
	static vector<account_type::AccountType>
		ret_array[static_cast<size_t>(num_transaction_types)];
	static bool initialized = false;

	if (!initialized)
	{
#		ifndef NDEBUG
			for
			(	size_t i = 0;
				i != static_cast<size_t>(num_transaction_types);
				++i
			)
			{
				assert (ret_array[i].empty());
			}
#		endif

		ret_array[static_cast<size_t>(expenditure_transaction)].
			push_back(account_type::expense);

		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(revenue_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::asset);
		ret_array[static_cast<size_t>(balance_sheet_transaction)].
			push_back(account_type::liability);

		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::revenue);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::expense);
		ret_array[static_cast<size_t>(envelope_transaction)].
			push_back(account_type::pure_envelope);

		// Generic transaction - can handle all AccountTypes;
		ret_array[static_cast<size_t>(generic_transaction)] = account_types();

		// Now we're initialized.
		initialized = true;
	}

#	ifndef NDEBUG
		vector<account_type::AccountType> const& debug_ret =
			ret_array[static_cast<size_t>(p_transaction_type)];
		assert (!debug_ret.empty());
		assert (initialized);
#	endif

	return ret_array[static_cast<size_t>(p_transaction_type)];
}

TransactionType
natural_transaction_type(Account const& account_x, Account const& account_y)
{
	account_type::AccountType const account_type_x = account_x.account_type();
	account_type::AccountType const account_type_y = account_y.account_type();

	switch (account_type_x)
	{
	case account_type::asset:  // fallthrough
	case account_type::liability:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return balance_sheet_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:
			return revenue_transaction;
		case account_type::expense:
			return expenditure_transaction;
		case account_type::pure_envelope:
			return generic_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::equity:
		return generic_transaction;
	case account_type::revenue:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return revenue_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:  // fallthrough
		case account_type::expense:  // fallthrough
		case account_type::pure_envelope:
			return envelope_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::expense:
		switch (account_type_y)
		{
		case account_type::asset:  // fallthrough
		case account_type::liability:
			return expenditure_transaction;
		case account_type::equity:
			return generic_transaction;
		case account_type::revenue:  // fallthrough
		case account_type::expense:  // fallthrough
		case account_type::pure_envelope:
			return envelope_transaction;
		default:
			assert (false);
		}
		assert (false);
	case account_type::pure_envelope:
		return envelope_transaction;
	default:
		assert (false);
	}

	assert (false);
}

}  // namespace phatbooks
<|endoftext|>


<commit_before>
#include "common/common.h"
#include "glslpp/preproc.h"

#include "fileutils.h"
#include "stringutils.h"

#include <assert.h>
#include <stdio.h>
#include <stdarg.h>

GLCCint _preprocess(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseTwo(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseThree(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseFour(GLCCPreprocessor* _preproc);

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// TODO: Relocate this into a common header. This will work for any stateful object that has an
// char* mErrorString.
template<typename T>
GLCCint ReportError(GLCCint _errCode, T *_where, const char* _fmt, ...)
{
    // Cleanup if anythign is there already.
    if (_where->mErrorString) {
        delete [] _where->mErrorString;
        _where->mErrorString = NULL;
    }

    // determine required size.
    va_list args;
    va_start( args, _fmt);
    int reqSize = vsnprintf(NULL, 0, _fmt, args);
    assert(reqSize >= 0);
    va_end(args);

    // Create new place.
    va_start( args, _fmt);
    _where->mErrorString = new char[reqSize + 1];
    vsnprintf(_where->mErrorString, reqSize + 1, _fmt, args);
    va_end(args);

    return _errCode;
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
struct GLCCPreprocessor
{
    const GLPPOptions mOptions;

    char* mFilename;
    char* mInputBuffer;
    char* mOutputBuffer;
    char* mErrorString;

    GLCCint mVersionGLSL;
    bool mUsedLineContinuations;

    // --------------------------------------------------------------------------------------------
    GLCCPreprocessor(const GLPPOptions& _options)
    : mOptions(_options)
    , mFilename(NULL)
    , mInputBuffer(NULL)
    , mOutputBuffer(NULL)
    , mErrorString(NULL)
    , mVersionGLSL(110) // Per the spec, this is the default.
    , mUsedLineContinuations(false)
    { }

    // --------------------------------------------------------------------------------------------
    ~GLCCPreprocessor()
    {
        delete [] mFilename;
        delete [] mInputBuffer;
        delete [] mOutputBuffer;
        delete [] mErrorString;
    }
};

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
GLCCint genPreprocessor(GLCCPreprocessor** _newPreproc, const GLPPOptions* _optOptions)
{
    if (!_newPreproc) {
        return GLCCError_MissingRequiredParameter;
    }

    // Options are optional. If unspecified, the defaults (per the constructor) will be used.
    GLPPOptions myOpts;
    if (_optOptions) {
        myOpts = (*_optOptions);
    }

    (*_newPreproc) = new GLCCPreprocessor(myOpts);
    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint deletePreprocessor(GLCCPreprocessor** _preproc)
{
    if (!_preproc) {
        return GLCCError_MissingRequiredParameter;
    }

    if (*_preproc) {
        delete (*_preproc);
        (*_preproc) = NULL;
    }

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint preprocessFromFile(GLCCPreprocessor* _preproc, const char* _filename)
{
    if (!_preproc) {
        return GLCCError_MissingRequiredParameter;
    }

    _preproc->mFilename = stringDuplicate(_filename);
    _preproc->mInputBuffer = fileContentsToString(_filename);
    if (_preproc->mInputBuffer == NULL) {
        return GLCCError_FileNotFound;
    }

    return _preprocess(_preproc);
}

// ------------------------------------------------------------------------------------------------
GLCCint preprocessFromMemory(GLCCPreprocessor* _preproc, const char* _memBuffer, const char* _optFilename)
{
    if (!_preproc || !_memBuffer) {
        return GLCCError_MissingRequiredParameter;
    }

    _preproc->mFilename = stringDuplicate((_optFilename != NULL) ? _optFilename : "MemoryBuffer");
    _preproc->mInputBuffer = stringDuplicate(_memBuffer);

    return _preprocess(_preproc);
}

// ------------------------------------------------------------------------------------------------
const char* getLastError(GLCCPreprocessor* _preproc)
{
    if (!_preproc) {
        return NULL;
    }

    return _preproc->mErrorString;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocess(GLCCPreprocessor* _preproc)
{
    GLCCint errCode = GLCCError_Ok;
    // In the C preprocessor, phase 1 is reading into memory. If we're here, we've already
    // done that.

    if ((errCode = _preprocessPhaseTwo(_preproc)) != GLCCError_Ok)
        return errCode;

    if ((errCode = _preprocessPhaseThree(_preproc)) != GLCCError_Ok)
        return errCode;

    return _preprocessPhaseFour(_preproc);
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseTwo(GLCCPreprocessor* _preproc)
{
    // Phase Two is line continuation. We do this in-place in _preproc->mInputBuffer.

    // ANNOY: Line continuation isn't supported in all versions of GLSL--added in GLSL420.
    //     We could detect the #version here and error out if line continuations are used and
    //     the version is less than 420. Instead, we just record whether line continuation
    //     occurred and a later phase will croak. That simplifies the processing here.
    //
    // TODO: We should support a non-conformant behavior (which should probably be the default)
    //     that if you use line continuation, we insert an equivalent number of \ns after the next
    //     non-escaped EOL character. This would keep line numbers in sync for error purposes.

    size_t srcFp = 0;
    size_t dstFp = 0;
    size_t lineNum = 1;
    size_t charNum = 1;
    int contiguousLinesContinued = 0;
    bool anyContinuations = false;

    bool advanceDst = false;
    for (srcFp = 0; _preproc->mInputBuffer[srcFp]; ++srcFp) {
        char thisChar = _preproc->mInputBuffer[srcFp + 0];
        char nextChar = _preproc->mInputBuffer[srcFp + 1];
        int advanceSrc = 0;

        if (thisChar == '\\' && nextChar == '\n') {
            ++contiguousLinesContinued;
            anyContinuations = true;
            advanceDst = false;
            advanceSrc = 1;
        } else {
            if (_preproc->mOptions.mMaintainLineCount && thisChar == '\n') {
                while (contiguousLinesContinued-- > 0) {
                    _preproc->mInputBuffer[dstFp++] = '\n';
                }
            }
            advanceDst = true;
        }

        // PERFORMANCE: Profile whether an extra branch here matters. We do this a lot. It could
        // be that the branch here costs more than it saves and it could be factored out.
        if (dstFp != srcFp && advanceDst) {
            _preproc->mInputBuffer[dstFp] = thisChar;
        }

        if (thisChar == '\n') {
            ++lineNum;
            charNum = 1;
        }

        // Move the srcFp forward (skipping characters) as necessary.
        srcFp += advanceSrc;

        if (advanceDst) {
            ++dstFp;
        }
    }

    // Write out the new '\0', then record whether we did any line continuations.
    _preproc->mInputBuffer[dstFp] = '\0';
    _preproc->mUsedLineContinuations = anyContinuations;

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseThree(GLCCPreprocessor* _preproc)
{
    // Phase three is comment processing. At this point, line continuations are gone, so any EOLs
    // that remain are "real", and will have effects on non-comment characters.
    // According to the C Preprocessor documentation:
    //     - Comments are replaced by one space
    //     - EOLs are preserved in both single and multi-line comments.
    // As with line continuations, we do this in-place in _preproc->mInputBuffer.

    enum ECommentMode {
        ECM_NoComment = 0,
        ECM_SingleLine,
        ECM_MultiLine
    };

    ECommentMode commentMode = ECM_NoComment;
    size_t srcFp = 0;
    size_t dstFp = 0;
    size_t lineNum = 1;
    size_t charNum = 1;

    bool advanceDst = false;
    for (srcFp = 0; _preproc->mInputBuffer[srcFp]; ++srcFp) {
        char thisChar = _preproc->mInputBuffer[srcFp + 0];
        char nextChar = _preproc->mInputBuffer[srcFp + 1];

        switch(commentMode) {
            case ECM_NoComment:
            {
                if (thisChar == '/') {
                    if (nextChar == '/') {
                        // Entering a single line comment. Write a space.
                        _preproc->mInputBuffer[dstFp++] = ' ';
                        commentMode = ECM_SingleLine;
                        // Move the source location. This is for consistency--but not needed for single line
                        // comments. It *is* required for multi-line comments.
                        ++srcFp;
                        break;
                    } else if (nextChar == '*') {
                        // Entering multi-line comment. Write a space.
                        _preproc->mInputBuffer[dstFp++] = ' ';
                        commentMode = ECM_MultiLine;
                        // We must move the src pointer here--otherwise we would recognize /*/
                        // as a begin and end of a comment string.
                        ++srcFp;
                        break;
                    }
                }

                _preproc->mInputBuffer[dstFp++] = thisChar;
                break;
            }

            case ECM_SingleLine:
            {
                if (thisChar == '\n') {
                    commentMode = ECM_NoComment;
                    _preproc->mInputBuffer[dstFp++] = thisChar;
                }
                break;
            }

            case ECM_MultiLine:
            {
                if (thisChar == '\n') {
                    // Write out the newline, they are preserved.
                    _preproc->mInputBuffer[dstFp++] = thisChar;
                }

                if (thisChar == '*' && nextChar == '/') {
                    commentMode = ECM_NoComment;
                    // Advance the src pointer, otherwise we'd recognize */* as a finish->start comment.
                    ++srcFp;
                }

                break;
            }

            default:
                assert(!"Error in parser.");
                break;
        };
    }

    _preproc->mInputBuffer[dstFp] = '\0';

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseFour(GLCCPreprocessor* _preproc)
{
    // Phase four is what people think of when they think of the preprocessor. This does
    // processing on preprocessor directives, macro substitution, etc.
    // Because of the complexity of this phase, we use a real parser here rather than a hand-
    // rolled parser like the ones used for phase two and phase three.

    // I deferred complaining about the #version directive--in case the author used line
    // coninuations here, too.

    // ANNOY: The preprocessor has to be both a line parser and a line-independent parser. This
    //     is the result of a particular intersection of rules. Preprocessor directives that
    //     begin with # are processed in a line manner--they take over the complete line they
    //     appear on. However, macro substitution has a particular corner case that's a bit
    //     dumb. If you have a function-like macro, it doesn't perform macro substitution unless
    //     the call-site looks like a function call. But that site could be split over multiple
    //     lines, meaning that we have to actually do light parsing on that portion of the file.
    //     For this reason, you'll find that the lexxer/parser for this have rules to basically
    //     determine when they do and do not care about EOLs.

    printf("%s", _preproc->mInputBuffer);

    return ReportError(GLCCError_NotImplemented, _preproc, "Phase %d has not yet been implemented. %s", 4, "food");
}
<commit_msg>+ glslpp - Actually add spaces to line output<commit_after>
#include "common/common.h"
#include "glslpp/preproc.h"

#include "fileutils.h"
#include "stringutils.h"

#include <assert.h>
#include <stdio.h>
#include <stdarg.h>

GLCCint _preprocess(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseTwo(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseThree(GLCCPreprocessor* _preproc);
GLCCint _preprocessPhaseFour(GLCCPreprocessor* _preproc);

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// TODO: Relocate this into a common header. This will work for any stateful object that has an
// char* mErrorString.
template<typename T>
GLCCint ReportError(GLCCint _errCode, T *_where, const char* _fmt, ...)
{
    // Cleanup if anythign is there already.
    if (_where->mErrorString) {
        delete [] _where->mErrorString;
        _where->mErrorString = NULL;
    }

    // determine required size.
    va_list args;
    va_start( args, _fmt);
    int reqSize = vsnprintf(NULL, 0, _fmt, args);
    assert(reqSize >= 0);
    va_end(args);

    // Create new place.
    va_start( args, _fmt);
    _where->mErrorString = new char[reqSize + 1];
    vsnprintf(_where->mErrorString, reqSize + 1, _fmt, args);
    va_end(args);

    return _errCode;
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
struct GLCCPreprocessor
{
    const GLPPOptions mOptions;

    char* mFilename;
    char* mInputBuffer;
    char* mOutputBuffer;
    char* mErrorString;

    GLCCint mVersionGLSL;
    bool mUsedLineContinuations;

    // --------------------------------------------------------------------------------------------
    GLCCPreprocessor(const GLPPOptions& _options)
    : mOptions(_options)
    , mFilename(NULL)
    , mInputBuffer(NULL)
    , mOutputBuffer(NULL)
    , mErrorString(NULL)
    , mVersionGLSL(110) // Per the spec, this is the default.
    , mUsedLineContinuations(false)
    { }

    // --------------------------------------------------------------------------------------------
    ~GLCCPreprocessor()
    {
        delete [] mFilename;
        delete [] mInputBuffer;
        delete [] mOutputBuffer;
        delete [] mErrorString;
    }
};

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
GLCCint genPreprocessor(GLCCPreprocessor** _newPreproc, const GLPPOptions* _optOptions)
{
    if (!_newPreproc) {
        return GLCCError_MissingRequiredParameter;
    }

    // Options are optional. If unspecified, the defaults (per the constructor) will be used.
    GLPPOptions myOpts;
    if (_optOptions) {
        myOpts = (*_optOptions);
    }

    (*_newPreproc) = new GLCCPreprocessor(myOpts);
    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint deletePreprocessor(GLCCPreprocessor** _preproc)
{
    if (!_preproc) {
        return GLCCError_MissingRequiredParameter;
    }

    if (*_preproc) {
        delete (*_preproc);
        (*_preproc) = NULL;
    }

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint preprocessFromFile(GLCCPreprocessor* _preproc, const char* _filename)
{
    if (!_preproc) {
        return GLCCError_MissingRequiredParameter;
    }

    _preproc->mFilename = stringDuplicate(_filename);
    _preproc->mInputBuffer = fileContentsToString(_filename);
    if (_preproc->mInputBuffer == NULL) {
        return GLCCError_FileNotFound;
    }

    return _preprocess(_preproc);
}

// ------------------------------------------------------------------------------------------------
GLCCint preprocessFromMemory(GLCCPreprocessor* _preproc, const char* _memBuffer, const char* _optFilename)
{
    if (!_preproc || !_memBuffer) {
        return GLCCError_MissingRequiredParameter;
    }

    _preproc->mFilename = stringDuplicate((_optFilename != NULL) ? _optFilename : "MemoryBuffer");
    _preproc->mInputBuffer = stringDuplicate(_memBuffer);

    return _preprocess(_preproc);
}

// ------------------------------------------------------------------------------------------------
const char* getLastError(GLCCPreprocessor* _preproc)
{
    if (!_preproc) {
        return NULL;
    }

    return _preproc->mErrorString;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocess(GLCCPreprocessor* _preproc)
{
    GLCCint errCode = GLCCError_Ok;
    // In the C preprocessor, phase 1 is reading into memory. If we're here, we've already
    // done that.

    if ((errCode = _preprocessPhaseTwo(_preproc)) != GLCCError_Ok)
        return errCode;

    if ((errCode = _preprocessPhaseThree(_preproc)) != GLCCError_Ok)
        return errCode;

    return _preprocessPhaseFour(_preproc);
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseTwo(GLCCPreprocessor* _preproc)
{
    // Phase Two is line continuation. We do this in-place in _preproc->mInputBuffer.

    // ANNOY: Line continuation isn't supported in all versions of GLSL--added in GLSL420.
    //     We could detect the #version here and error out if line continuations are used and
    //     the version is less than 420. Instead, we just record whether line continuation
    //     occurred and a later phase will croak. That simplifies the processing here.
    //
    // TODO: We should support a non-conformant behavior (which should probably be the default)
    //     that if you use line continuation, we insert an equivalent number of \ns after the next
    //     non-escaped EOL character. This would keep line numbers in sync for error purposes.

    size_t srcFp = 0;
    size_t dstFp = 0;
    size_t lineNum = 1;
    size_t charNum = 1;
    int contiguousLinesContinued = 0;
    bool anyContinuations = false;

    bool advanceDst = false;
    for (srcFp = 0; _preproc->mInputBuffer[srcFp]; ++srcFp) {
        char thisChar = _preproc->mInputBuffer[srcFp + 0];
        char nextChar = _preproc->mInputBuffer[srcFp + 1];
        int advanceSrc = 0;

        if (thisChar == '\\' && nextChar == '\n') {
            ++contiguousLinesContinued;
            anyContinuations = true;
            advanceDst = false;
            advanceSrc = 1;
        } else {
            if (_preproc->mOptions.mMaintainLineCount && thisChar == '\n') {
                while (contiguousLinesContinued-- > 0) {
                    // Combined with the '\n' we're going to pick up from this line, this will
                    // wind up with <SPACE><EOL> on each line.
                    _preproc->mInputBuffer[dstFp++] = '\n';
                    _preproc->mInputBuffer[dstFp++] = ' ';
                }
            }
            advanceDst = true;
        }

        // PERFORMANCE: Profile whether an extra branch here matters. We do this a lot. It could
        // be that the branch here costs more than it saves and it could be factored out.
        if (dstFp != srcFp && advanceDst) {
            _preproc->mInputBuffer[dstFp] = thisChar;
        }

        if (thisChar == '\n') {
            ++lineNum;
            charNum = 1;
        }

        // Move the srcFp forward (skipping characters) as necessary.
        srcFp += advanceSrc;

        if (advanceDst) {
            ++dstFp;
        }
    }

    // Write out the new '\0', then record whether we did any line continuations.
    _preproc->mInputBuffer[dstFp] = '\0';
    _preproc->mUsedLineContinuations = anyContinuations;

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseThree(GLCCPreprocessor* _preproc)
{
    // Phase three is comment processing. At this point, line continuations are gone, so any EOLs
    // that remain are "real", and will have effects on non-comment characters.
    // According to the C Preprocessor documentation:
    //     - Comments are replaced by one space
    //     - EOLs are preserved in both single and multi-line comments.
    // As with line continuations, we do this in-place in _preproc->mInputBuffer.

    enum ECommentMode {
        ECM_NoComment = 0,
        ECM_SingleLine,
        ECM_MultiLine
    };

    ECommentMode commentMode = ECM_NoComment;
    size_t srcFp = 0;
    size_t dstFp = 0;
    size_t lineNum = 1;
    size_t charNum = 1;

    bool advanceDst = false;
    for (srcFp = 0; _preproc->mInputBuffer[srcFp]; ++srcFp) {
        char thisChar = _preproc->mInputBuffer[srcFp + 0];
        char nextChar = _preproc->mInputBuffer[srcFp + 1];

        switch(commentMode) {
            case ECM_NoComment:
            {
                if (thisChar == '/') {
                    if (nextChar == '/') {
                        // Entering a single line comment. Write a space.
                        _preproc->mInputBuffer[dstFp++] = ' ';
                        commentMode = ECM_SingleLine;
                        // Move the source location. This is for consistency--but not needed for single line
                        // comments. It *is* required for multi-line comments.
                        ++srcFp;
                        break;
                    } else if (nextChar == '*') {
                        // Entering multi-line comment. Write a space.
                        _preproc->mInputBuffer[dstFp++] = ' ';
                        commentMode = ECM_MultiLine;
                        // We must move the src pointer here--otherwise we would recognize /*/
                        // as a begin and end of a comment string.
                        ++srcFp;
                        break;
                    }
                }

                _preproc->mInputBuffer[dstFp++] = thisChar;
                break;
            }

            case ECM_SingleLine:
            {
                if (thisChar == '\n') {
                    commentMode = ECM_NoComment;
                    _preproc->mInputBuffer[dstFp++] = thisChar;
                }
                break;
            }

            case ECM_MultiLine:
            {
                if (thisChar == '\n') {
                    // Write out the newline, they are preserved.
                    _preproc->mInputBuffer[dstFp++] = thisChar;
                }

                if (thisChar == '*' && nextChar == '/') {
                    commentMode = ECM_NoComment;
                    // Advance the src pointer, otherwise we'd recognize */* as a finish->start comment.
                    ++srcFp;
                }

                break;
            }

            default:
                assert(!"Error in parser.");
                break;
        };
    }

    _preproc->mInputBuffer[dstFp] = '\0';

    return GLCCError_Ok;
}

// ------------------------------------------------------------------------------------------------
GLCCint _preprocessPhaseFour(GLCCPreprocessor* _preproc)
{
    // Phase four is what people think of when they think of the preprocessor. This does
    // processing on preprocessor directives, macro substitution, etc.
    // Because of the complexity of this phase, we use a real parser here rather than a hand-
    // rolled parser like the ones used for phase two and phase three.

    // I deferred complaining about the #version directive--in case the author used line
    // coninuations here, too.

    // ANNOY: The preprocessor has to be both a line parser and a line-independent parser. This
    //     is the result of a particular intersection of rules. Preprocessor directives that
    //     begin with # are processed in a line manner--they take over the complete line they
    //     appear on. However, macro substitution has a particular corner case that's a bit
    //     dumb. If you have a function-like macro, it doesn't perform macro substitution unless
    //     the call-site looks like a function call. But that site could be split over multiple
    //     lines, meaning that we have to actually do light parsing on that portion of the file.
    //     For this reason, you'll find that the lexxer/parser for this have rules to basically
    //     determine when they do and do not care about EOLs.

    printf("%s", _preproc->mInputBuffer);

    return ReportError(GLCCError_NotImplemented, _preproc, "Phase %d has not yet been implemented. %s", 4, "food");
}
<|endoftext|>


<commit_before>/* Copyright 2016 Artem Sharganov and Iakov Kirilenko
 *
 * 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 "audioSynthDevices.h"

#include <QtMultimedia/QAudioDeviceInfo>
#include <qmath.h>

AudioSynthDevice::AudioSynthDevice(QObject *parent, int sampleRate, int sampleSize)
	: QIODevice(parent)
	, mBuffer(0)
	, mPos(0)
	, mHzFreq(0)
	, mSampleRate(sampleRate)
	, mSampleSize(sampleSize)
{
  open(QIODevice::ReadOnly);
}

AudioSynthDevice::~AudioSynthDevice()
{
}

void AudioSynthDevice::start(int hzFreq)
{
  reset();
  mPos = 0;
  newCall = true;
  mHzFreq = hzFreq;
	if (mBuffered) {
		const qint64 length = (mSampleRate * (mSampleSize / 8));
		mBuffer.resize(length);
		generate(mBuffer.data(), length, hzFreq);
	}
  emit readyRead();
}

void AudioSynthDevice::stop()
{
	reset();
	mHzFreq = 0;
}

// Modefied coupled first-order form algorithm with fixed point arithmetic
int AudioSynthDevice::generate(char *data, int length, int hzFreq)
{
  if(hzFreq == 0) return 0;

	const int channelBytes = mSampleSize / 8;

	qint64 maxlen = length / channelBytes;

	static const int M = 1 << 30;
	const auto w = hzFreq * M_PI / mSampleRate;
	const long long b1 = 2.0 * cos(w) * M;
	static const int AMPLITUDE = (1 << (mSampleSize - 1)) - 1;

	unsigned char *ptr = reinterpret_cast<unsigned char *>(data);

	// Need to save values between readData(...) calls, so static
	static long long y0 = 0;
	static decltype(y0) y1 = 0;
	static decltype(y0) y2 = 0;

	if (newCall) {
		y1 = M * std::sin(-w);
		y2 = M * std::sin(-2 * w);
		newCall = false;
	}

	int i = 0;

	for (i = 0; i < maxlen; ++i) {
		y0 = b1 * y1 / M - y2;
		y2 = b1 * y0 / M - y1;
		y1 = b1 * y2 / M - y0;

		if (mSampleSize == 8) {
			const qint8 val = static_cast<qint8>(y0 * AMPLITUDE / M);
			*reinterpret_cast<quint8*>(ptr) = val;
		} else if(mSampleSize == 16) {
			const qint16 val = static_cast<qint16>(y0 * AMPLITUDE / M);
			*reinterpret_cast<quint16*>(ptr) = val;
		}

		ptr += channelBytes;
	}

	return i * channelBytes;
}

qint64 AudioSynthDevice::readData(char *data, qint64 len)
{
	if (mBuffered) {
		qint64 total = 0;
		while (len - total > 0) {
			const qint64 chunk = qMin((mBuffer.size() - mPos), len - total);
			memcpy(data + total, mBuffer.constData() + mPos, chunk);
			mPos = (mPos + chunk) % mBuffer.size();
			total += chunk;
		}

		return total;
	} else {
		return generate(data, len, mHzFreq);
	}
}

qint64 AudioSynthDevice::writeData(const char *data, qint64 len)
{
	Q_UNUSED(data);
	Q_UNUSED(len);

	return 0;
}

qint64 AudioSynthDevice::bytesAvailable() const
{
	return mBuffer.size() + QIODevice::bytesAvailable();
}
<commit_msg>markup fixes<commit_after>/* Copyright 2016 Artem Sharganov and Iakov Kirilenko
 *
 * 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 "audioSynthDevices.h"

#include <QtMultimedia/QAudioDeviceInfo>
#include <qmath.h>

AudioSynthDevice::AudioSynthDevice(QObject *parent, int sampleRate, int sampleSize)
	: QIODevice(parent)
	, mBuffer(0)
	, mPos(0)
	, mHzFreq(0)
	, mSampleRate(sampleRate)
	, mSampleSize(sampleSize)
{
	open(QIODevice::ReadOnly);
}

AudioSynthDevice::~AudioSynthDevice()
{
}

void AudioSynthDevice::start(int hzFreq)
{
	reset();
	mPos = 0;
	newCall = true;
	mHzFreq = hzFreq;
	if (mBuffered) {
		const qint64 length = (mSampleRate * (mSampleSize / 8));
		mBuffer.resize(length);
		generate(mBuffer.data(), length, hzFreq);
	}
	emit readyRead();
}

void AudioSynthDevice::stop()
{
	reset();
	mHzFreq = 0;
}

// Modefied coupled first-order form algorithm with fixed point arithmetic
int AudioSynthDevice::generate(char *data, int length, int hzFreq)
{
	if(hzFreq == 0) return 0;

	const int channelBytes = mSampleSize / 8;

	qint64 maxlen = length / channelBytes;

	static const int M = 1 << 30;
	const auto w = hzFreq * M_PI / mSampleRate;
	const long long b1 = 2.0 * cos(w) * M;
	static const int AMPLITUDE = (1 << (mSampleSize - 1)) - 1;

	unsigned char *ptr = reinterpret_cast<unsigned char *>(data);

	// Need to save values between readData(...) calls, so static
	static long long y0 = 0;
	static decltype(y0) y1 = 0;
	static decltype(y0) y2 = 0;

	if (newCall) {
		y1 = M * std::sin(-w);
		y2 = M * std::sin(-2 * w);
		newCall = false;
	}

	int i = 0;

	for (i = 0; i < maxlen; ++i) {
		y0 = b1 * y1 / M - y2;
		y2 = b1 * y0 / M - y1;
		y1 = b1 * y2 / M - y0;

		if (mSampleSize == 8) {
			const qint8 val = static_cast<qint8>(y0 * AMPLITUDE / M);
			*reinterpret_cast<quint8*>(ptr) = val;
		} else if(mSampleSize == 16) {
			const qint16 val = static_cast<qint16>(y0 * AMPLITUDE / M);
			*reinterpret_cast<quint16*>(ptr) = val;
		}

		ptr += channelBytes;
	}

	return i * channelBytes;
}

qint64 AudioSynthDevice::readData(char *data, qint64 len)
{
	if (mBuffered) {
		qint64 total = 0;
		while (len - total > 0) {
			const qint64 chunk = qMin((mBuffer.size() - mPos), len - total);
			memcpy(data + total, mBuffer.constData() + mPos, chunk);
			mPos = (mPos + chunk) % mBuffer.size();
			total += chunk;
		}

		return total;
	} else {
		return generate(data, len, mHzFreq);
	}
}

qint64 AudioSynthDevice::writeData(const char *data, qint64 len)
{
	Q_UNUSED(data);
	Q_UNUSED(len);

	return 0;
}

qint64 AudioSynthDevice::bytesAvailable() const
{
	return mBuffer.size() + QIODevice::bytesAvailable();
}
<|endoftext|>


<commit_before>#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Texture2D>

#include <osgDB/FileUtils>
#include <osgDB/ReadFile>

#include <osgUtil/Optimizer>

#include <osgProducer/Viewer>

char vertexShaderSource_simple[] =
    "uniform vec4 coeff; \n"
    "\n"
    "void main(void) \n"
    "{ \n"
    "\n"
    "    gl_TexCoord[0] = gl_Vertex; \n"
    "    gl_Vertex.z = gl_Vertex.x*coeff[0] + gl_Vertex.x*gl_Vertex.x* coeff[1] + \n"
    "                  gl_Vertex.y*coeff[2] + gl_Vertex.y*gl_Vertex.y* coeff[3]; \n"
    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    "}\n";

char fragmentShaderSource[] =
    "uniform sampler2D baseTexture; \n"
    "\n"
    "void main(void) \n"
    "{ \n"
    "    gl_FragColor = texture2D( baseTexture, gl_TexCoord[0].xy); \n"
    "}\n";

class UniformVarying : public osg::Uniform::Callback
{
    virtual void operator () (osg::Uniform* uniform, osg::NodeVisitor* nv)
    {
        const osg::FrameStamp* fs = nv->getFrameStamp();
        float value = sinf(fs->getReferenceTime());
        uniform->set(osg::Vec4(value,-value,-value,value));
    }
};

osg::Node* createModel()
{
    osg::Geode* geode = new osg::Geode;

    osg::Geometry* geom = new osg::Geometry;
    geode->addDrawable(geom);

    // dimensions for ~one million triangles :-)
    unsigned int num_x = 708;
    unsigned int num_y = 708;

    osg::Vec3Array* vertices = new osg::Vec3Array( num_x * num_y );

    float dx = 1.0f/(float)(num_x-1);
    float dy = 1.0f/(float)(num_y-1);
    osg::Vec3 row(0.0f,0.0f,0.0);

    unsigned int vert_no = 0;
    for(unsigned int iy=0; iy<num_y; ++iy)
    {
        osg::Vec3 column = row;
        for(unsigned int ix=0;ix<num_x;++ix)
        {
            (*vertices)[vert_no++] = column;
            column.x() += dx;
        }
        row.y() += dy;
    }

    geom->setVertexArray(vertices);

    for(unsigned int iy=0; iy<num_y-1; ++iy)
    {
        unsigned int element_no = 0;
        osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(GL_TRIANGLE_STRIP, num_x*2);
        unsigned int index = iy * num_x;
        for(unsigned int ix = 0; ix<num_x; ++ix)
        {
            (*elements)[element_no++] = index + num_x;
            (*elements)[element_no++] = index++;
        }
        geom->addPrimitiveSet(elements);
    }

    geom->setUseVertexBufferObjects(true);

    osg::StateSet* stateset = geom->getOrCreateStateSet();

    osg::Program* program = new osg::Program;
    stateset->setAttribute(program);

    osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource_simple);
    program->addShader(vertex_shader);

    osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
    program->addShader(fragment_shader);

    osg::Uniform* xCoeff = new osg::Uniform("coeff",osg::Vec4(1.0,-1.0f,-1.0f,1.0f));
    xCoeff->setUpdateCallback(new UniformVarying);
    stateset->addUniform(xCoeff);

    osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile("lz.rgb"));
    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::NEAREST);
    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::NEAREST);
    stateset->setTextureAttributeAndModes(0,texture);

    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
    stateset->addUniform(baseTextureSampler);

    return geode;

}

int main(int argc, char *argv[])
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrate support for ARB_vertex_program.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // load the nodes from the commandline arguments.
    osg::Node* model = createModel();
    if (!model)
    {
        return 1;
    }

    // add a viewport to the viewer and attach the scene graph.
    viewer.setSceneData(model);

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}
<commit_msg>Added matrix and simple vertex shader paths.<commit_after>#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Texture2D>

#include <osgDB/FileUtils>
#include <osgDB/ReadFile>

#include <osgUtil/Optimizer>

#include <osgProducer/Viewer>

///////////////////////////////////////////////////////////////////
// vertex shader using just Vec4 coefficients
char vertexShaderSource_simple[] =
    "uniform vec4 coeff; \n"
    "\n"
    "void main(void) \n"
    "{ \n"
    "\n"
    "    gl_TexCoord[0] = gl_Vertex; \n"
    "    gl_Vertex.z = gl_Vertex.x*coeff[0] + gl_Vertex.x*gl_Vertex.x* coeff[1] + \n"
    "                  gl_Vertex.y*coeff[2] + gl_Vertex.y*gl_Vertex.y* coeff[3]; \n"
    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    "}\n";

//////////////////////////////////////////////////////////////////
// vertex shader using full Matrix4 coefficients
char vertexShaderSource_matrix[] =
    "uniform vec4  origin; \n"
    "uniform mat4  coeffMatrix; \n"
    "\n"
    "void main(void) \n"
    "{ \n"
    "\n"
    "    gl_TexCoord[0] = gl_Vertex; \n"
    "    vec4 v = vec4(gl_Vertex.x, gl_Vertex.x*gl_Vertex.x, gl_Vertex.y, gl_Vertex.y*gl_Vertex.y ); \n"
    "    gl_Position = gl_ModelViewProjectionMatrix * (origin + coeffMatrix * v);\n"
    "}\n";

//////////////////////////////////////////////////////////////////
// fragment shader
//
char fragmentShaderSource[] =
    "uniform sampler2D baseTexture; \n"
    "\n"
    "void main(void) \n"
    "{ \n"
    "    gl_FragColor = texture2D( baseTexture, gl_TexCoord[0].xy); \n"
    "}\n";

class UniformVarying : public osg::Uniform::Callback
{
    virtual void operator () (osg::Uniform* uniform, osg::NodeVisitor* nv)
    {
        const osg::FrameStamp* fs = nv->getFrameStamp();
        float value = sinf(fs->getReferenceTime());
        uniform->set(osg::Vec4(value,-value,-value,value));
    }
};

osg::Node* createModel(const std::string& shader)
{
    osg::Geode* geode = new osg::Geode;

    osg::Geometry* geom = new osg::Geometry;
    geode->addDrawable(geom);

    // dimensions for ~one million triangles :-)
    unsigned int num_x = 708;
    unsigned int num_y = 708;

    osg::Vec3Array* vertices = new osg::Vec3Array( num_x * num_y );

    float dx = 1.0f/(float)(num_x-1);
    float dy = 1.0f/(float)(num_y-1);
    osg::Vec3 row(0.0f,0.0f,0.0);

    unsigned int vert_no = 0;
    for(unsigned int iy=0; iy<num_y; ++iy)
    {
        osg::Vec3 column = row;
        for(unsigned int ix=0;ix<num_x;++ix)
        {
            (*vertices)[vert_no++] = column;
            column.x() += dx;
        }
        row.y() += dy;
    }

    geom->setVertexArray(vertices);

    for(unsigned int iy=0; iy<num_y-1; ++iy)
    {
        unsigned int element_no = 0;
        osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(GL_TRIANGLE_STRIP, num_x*2);
        unsigned int index = iy * num_x;
        for(unsigned int ix = 0; ix<num_x; ++ix)
        {
            (*elements)[element_no++] = index + num_x;
            (*elements)[element_no++] = index++;
        }
        geom->addPrimitiveSet(elements);
    }

    geom->setUseVertexBufferObjects(true);

    osg::StateSet* stateset = geom->getOrCreateStateSet();

    osg::Program* program = new osg::Program;
    stateset->setAttribute(program);

    if (shader=="simple")
    {
        osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource_simple);
        program->addShader(vertex_shader);

        osg::Uniform* coeff = new osg::Uniform("coeff",osg::Vec4(1.0,-1.0f,-1.0f,1.0f));
        coeff->setUpdateCallback(new UniformVarying);
        stateset->addUniform(coeff);
    }
    else if (shader=="matrix")
    {
        osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource_matrix);
        program->addShader(vertex_shader);

        osg::Uniform* origin = new osg::Uniform("origin",osg::Vec4(0.0f,0.0f,0.0f,1.0f));
        stateset->addUniform(origin);

        osg::Uniform* coeffMatrix = new osg::Uniform("coeffMatrix",
            osg::Matrix(1.0f,0.0f,1.0f,0.0f,
                        0.0f,0.0f,-1.0f,0.0f,
                        0.0f,1.0f,-1.0f,0.0f,
                        0.0f,0.0f,1.0f,0.0f));

        stateset->addUniform(coeffMatrix);
    }
    else if (shader=="texture")
    {

    }

    osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
    program->addShader(fragment_shader);

    osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile("lz.rgb"));
    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::NEAREST);
    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::NEAREST);
    stateset->setTextureAttributeAndModes(0,texture);

    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
    stateset->addUniform(baseTextureSampler);

    return geode;

}

int main(int argc, char *argv[])
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrate support for ARB_vertex_program.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    std::string shader("simple");
    while(arguments.read("-s",shader)) {}

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // load the nodes from the commandline arguments.
    osg::Node* model = createModel(shader);
    if (!model)
    {
        return 1;
    }

    // add a viewport to the viewer and attach the scene graph.
    viewer.setSceneData(model);

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkExtractImageFilter.h"
#include "mitkImageCast.h"
#include "mitkPlaneGeometry.h"
#include "mitkITKImageImport.h"
#include "mitkImageTimeSelector.h"

#include <itkExtractImageFilter.h>

mitk::ExtractImageFilter::ExtractImageFilter()
:m_SliceIndex(0),
 m_SliceDimension(0),
 m_TimeStep(0)
{
}

mitk::ExtractImageFilter::~ExtractImageFilter()
{
}

void mitk::ExtractImageFilter::GenerateData()
{
   Image::ConstPointer input = ImageToImageFilter::GetInput(0);

   if ( (input->GetDimension() > 4) || (input->GetDimension() < 2) )
   {
     std::cerr << "mitk::ExtractImageFilter:GenerateData works only with 3D images, sorry." << std::endl;
     itkExceptionMacro("mitk::ExtractImageFilter works only with 3D and 3D+t images, sorry.");
     return;
   }
   else if (input->GetDimension() == 4)
   {
     ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
     timeSelector->SetInput( input );
     timeSelector->SetTimeNr( m_TimeStep );
     timeSelector->UpdateLargestPossibleRegion();
     input = timeSelector->GetOutput();
   }
   else if (input->GetDimension() == 2)
   {
     Image::Pointer resultImage = ImageToImageFilter::GetOutput();
     resultImage = const_cast<Image*>(input.GetPointer());
     ImageToImageFilter::SetNthOutput( 0, resultImage );
     return;
   }

  if ( m_SliceDimension >= input->GetDimension() )
  {
    std::cerr << "mitk::ExtractImageFilter:GenerateData  m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl;
    itkExceptionMacro("This is not a sensible value for m_SliceDimension.");
    return;
  }

   AccessFixedDimensionByItk( input, ItkImageProcessing, 3 );
}

template<typename TPixel, unsigned int VImageDimension>
void mitk::ExtractImageFilter::ItkImageProcessing( itk::Image<TPixel,VImageDimension>* itkImage )
{
  // use the itk::ExtractImageFilter to get a 2D image
  typedef itk::Image< TPixel, VImageDimension >   ImageType3D;
  typedef itk::Image< TPixel, VImageDimension-1 > ImageType2D;

  typename ImageType3D::RegionType inSliceRegion = itkImage->GetLargestPossibleRegion();

  inSliceRegion.SetSize( m_SliceDimension, 0 );

  typedef itk::ExtractImageFilter<ImageType3D, ImageType2D> ExtractImageFilterType;

  typename ExtractImageFilterType::Pointer sliceExtractor = ExtractImageFilterType::New();
  sliceExtractor->SetInput( itkImage );

  inSliceRegion.SetIndex( m_SliceDimension, m_SliceIndex );

  sliceExtractor->SetExtractionRegion( inSliceRegion );

  // calculate the output
  sliceExtractor->UpdateLargestPossibleRegion();

  typename ImageType2D::Pointer slice = sliceExtractor->GetOutput();
  // possible bug in itk::ExtractImageFilter: or in CastToItkImage ?
  // direction maxtrix is wrong/broken/not working with mitk::Image::InitializeByItkImage
  // solution here: we overwrite it with an unity matrix
  typename ImageType2D::DirectionType imageDirection;
  imageDirection.SetIdentity();
  slice->SetDirection(imageDirection);

  // re-import to MITK
  Image::Pointer resultImage = ImageToImageFilter::GetOutput();
  GrabItkImageMemory(slice, resultImage, NULL, false);
}

/*
 * What is the input requested region that is required to produce the output
 * requested region? By default, the largest possible region is always
 * required but this is overridden in many subclasses. For instance, for an
 * image processing filter where an output pixel is a simple function of an
 * input pixel, the input requested region will be set to the output
 * requested region. For an image processing filter where an output pixel is
 * a function of the pixels in a neighborhood of an input pixel, then the
 * input requested region will need to be larger than the output requested
 * region (to avoid introducing artificial boundary conditions). This
 * function should never request an input region that is outside the the
 * input largest possible region (i.e. implementations of this method should
 * crop the input requested region at the boundaries of the input largest
 * possible region).
 */
void mitk::ExtractImageFilter::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  ImageToImageFilter::InputImagePointer input = const_cast< ImageToImageFilter::InputImageType* > ( this->GetInput() );
  Image::Pointer output = this->GetOutput();

  if (input->GetDimension() == 2)
  {
    input->SetRequestedRegionToLargestPossibleRegion();
    return;
  }

  Image::RegionType requestedRegion;
  requestedRegion = output->GetRequestedRegion();
  requestedRegion.SetIndex(0, 0);
  requestedRegion.SetIndex(1, 0);
  requestedRegion.SetIndex(2, 0);
  requestedRegion.SetSize(0, input->GetDimension(0));
  requestedRegion.SetSize(1, input->GetDimension(1));
  requestedRegion.SetSize(2, input->GetDimension(2));

  requestedRegion.SetIndex( m_SliceDimension, m_SliceIndex ); // only one slice needed
  requestedRegion.SetSize( m_SliceDimension, 1 );

  input->SetRequestedRegion( &requestedRegion );
}

/*
 * Generate the information decribing the output data. The default
 * implementation of this method will copy information from the input to the
 * output. A filter may override this method if its output will have different
 * information than its input. For instance, a filter that shrinks an image will
 * need to provide an implementation for this method that changes the spacing of
 * the pixels. Such filters should call their superclass' implementation of this
 * method prior to changing the information values they need (i.e.
 * GenerateOutputInformation() should call
 * Superclass::GenerateOutputInformation() prior to changing the information.
 */
void mitk::ExtractImageFilter::GenerateOutputInformation()
{
 Image::Pointer output = this->GetOutput();
 Image::ConstPointer input = this->GetInput();
 if (input.IsNull()) return;

 if ( m_SliceDimension >= input->GetDimension() && input->GetDimension() != 2 )
 {
   std::cerr << "mitk::ExtractImageFilter:GenerateOutputInformation  m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl;
   itkExceptionMacro("This is not a sensible value for m_SliceDimension.");
   return;
 }

 unsigned int sliceDimension( m_SliceDimension );
 if ( input->GetDimension() == 2)
 {
   sliceDimension = 2;
 }

  unsigned int i(0);
  unsigned int tmpDimensions[2];

  switch ( sliceDimension )
  {
    default:
    case 2:
      // orientation = PlaneGeometry::Transversal;
      tmpDimensions[0] = input->GetDimension(0);
      tmpDimensions[1] = input->GetDimension(1);
      break;
    case 1:
      // orientation = PlaneGeometry::Frontal;
      tmpDimensions[0] = input->GetDimension(0);
      tmpDimensions[1] = input->GetDimension(2);
      break;
    case 0:
      // orientation = PlaneGeometry::Sagittal;
      tmpDimensions[0] = input->GetDimension(1);
      tmpDimensions[1] = input->GetDimension(2);
      break;
  }

  output->Initialize(input->GetPixelType(), 2, tmpDimensions, 1 /*input->GetNumberOfChannels()*/);

  // initialize the spacing of the output
/*
  Vector3D spacing = input->GetSlicedGeometry()->GetSpacing();
  if(input->GetDimension()>=2)
    spacing[2]=spacing[1];
  else
    spacing[2] = 1.0;
  output->GetSlicedGeometry()->SetSpacing(spacing);
*/

  output->SetPropertyList(input->GetPropertyList()->Clone());

  // set a nice geometry for display and point transformations
  Geometry3D* inputImageGeometry = ImageToImageFilter::GetInput(0)->GetGeometry();
  if (!inputImageGeometry)
  {
    std::cerr << "In ExtractImageFilter::ItkImageProcessing: Input image has no geometry!" << std::endl;
    return;
  }

  PlaneGeometry::PlaneOrientation orientation = PlaneGeometry::Transversal;

  switch ( sliceDimension )
  {
    default:
    case 2:
      orientation = PlaneGeometry::Transversal;
      break;
    case 1:
      orientation = PlaneGeometry::Frontal;
      break;
    case 0:
      orientation = PlaneGeometry::Sagittal;
      break;
   }

  PlaneGeometry::Pointer planeGeometry = PlaneGeometry::New();
  planeGeometry->InitializeStandardPlane( inputImageGeometry, orientation, (ScalarType)m_SliceIndex + 0.5 , true, false );
  Image::Pointer resultImage = ImageToImageFilter::GetOutput();
  resultImage->SetGeometry( planeGeometry );
}

<commit_msg>FIX (#1318): SliceBasedSegmentation broken<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkExtractImageFilter.h"
#include "mitkImageCast.h"
#include "mitkPlaneGeometry.h"
#include "mitkITKImageImport.h"
#include "mitkImageTimeSelector.h"

#include <itkExtractImageFilter.h>

mitk::ExtractImageFilter::ExtractImageFilter()
:m_SliceIndex(0),
 m_SliceDimension(0),
 m_TimeStep(0)
{
}

mitk::ExtractImageFilter::~ExtractImageFilter()
{
}

void mitk::ExtractImageFilter::GenerateData()
{
   Image::ConstPointer input = ImageToImageFilter::GetInput(0);

   if ( (input->GetDimension() > 4) || (input->GetDimension() < 2) )
   {
     std::cerr << "mitk::ExtractImageFilter:GenerateData works only with 3D images, sorry." << std::endl;
     itkExceptionMacro("mitk::ExtractImageFilter works only with 3D and 3D+t images, sorry.");
     return;
   }
   else if (input->GetDimension() == 4)
   {
     ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();
     timeSelector->SetInput( input );
     timeSelector->SetTimeNr( m_TimeStep );
     timeSelector->UpdateLargestPossibleRegion();
     input = timeSelector->GetOutput();
   }
   else if (input->GetDimension() == 2)
   {
     Image::Pointer resultImage = ImageToImageFilter::GetOutput();
     resultImage = const_cast<Image*>(input.GetPointer());
     ImageToImageFilter::SetNthOutput( 0, resultImage );
     return;
   }

  if ( m_SliceDimension >= input->GetDimension() )
  {
    std::cerr << "mitk::ExtractImageFilter:GenerateData  m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl;
    itkExceptionMacro("This is not a sensible value for m_SliceDimension.");
    return;
  }

   AccessFixedDimensionByItk( input, ItkImageProcessing, 3 );

  // set a nice geometry for display and point transformations
  Geometry3D* inputImageGeometry = ImageToImageFilter::GetInput(0)->GetGeometry();
  if (!inputImageGeometry)
  {
    std::cerr << "In ExtractImageFilter::ItkImageProcessing: Input image has no geometry!" << std::endl;
    return;
  }

  PlaneGeometry::PlaneOrientation orientation = PlaneGeometry::Transversal;

  switch ( m_SliceDimension )
  {
    default:
    case 2:
      orientation = PlaneGeometry::Transversal;
      break;
    case 1:
      orientation = PlaneGeometry::Frontal;
      break;
    case 0:
      orientation = PlaneGeometry::Sagittal;
      break;
   }

  PlaneGeometry::Pointer planeGeometry = PlaneGeometry::New();
  planeGeometry->InitializeStandardPlane( inputImageGeometry, orientation, (ScalarType)m_SliceIndex + 0.5 , true, false );
  Image::Pointer resultImage = ImageToImageFilter::GetOutput();
  resultImage->SetGeometry( planeGeometry );
}

template<typename TPixel, unsigned int VImageDimension>
void mitk::ExtractImageFilter::ItkImageProcessing( itk::Image<TPixel,VImageDimension>* itkImage )
{
  // use the itk::ExtractImageFilter to get a 2D image
  typedef itk::Image< TPixel, VImageDimension >   ImageType3D;
  typedef itk::Image< TPixel, VImageDimension-1 > ImageType2D;

  typename ImageType3D::RegionType inSliceRegion = itkImage->GetLargestPossibleRegion();

  inSliceRegion.SetSize( m_SliceDimension, 0 );

  typedef itk::ExtractImageFilter<ImageType3D, ImageType2D> ExtractImageFilterType;

  typename ExtractImageFilterType::Pointer sliceExtractor = ExtractImageFilterType::New();
  sliceExtractor->SetInput( itkImage );

  inSliceRegion.SetIndex( m_SliceDimension, m_SliceIndex );

  sliceExtractor->SetExtractionRegion( inSliceRegion );

  // calculate the output
  sliceExtractor->UpdateLargestPossibleRegion();

  typename ImageType2D::Pointer slice = sliceExtractor->GetOutput();
  // possible bug in itk::ExtractImageFilter: or in CastToItkImage ?
  // direction maxtrix is wrong/broken/not working with mitk::Image::InitializeByItkImage
  // solution here: we overwrite it with an unity matrix
  typename ImageType2D::DirectionType imageDirection;
  imageDirection.SetIdentity();
  slice->SetDirection(imageDirection);

  // re-import to MITK
  Image::Pointer resultImage = ImageToImageFilter::GetOutput();
  GrabItkImageMemory(slice, resultImage, NULL, false);
}

/*
 * What is the input requested region that is required to produce the output
 * requested region? By default, the largest possible region is always
 * required but this is overridden in many subclasses. For instance, for an
 * image processing filter where an output pixel is a simple function of an
 * input pixel, the input requested region will be set to the output
 * requested region. For an image processing filter where an output pixel is
 * a function of the pixels in a neighborhood of an input pixel, then the
 * input requested region will need to be larger than the output requested
 * region (to avoid introducing artificial boundary conditions). This
 * function should never request an input region that is outside the the
 * input largest possible region (i.e. implementations of this method should
 * crop the input requested region at the boundaries of the input largest
 * possible region).
 */
void mitk::ExtractImageFilter::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  ImageToImageFilter::InputImagePointer input = const_cast< ImageToImageFilter::InputImageType* > ( this->GetInput() );
  Image::Pointer output = this->GetOutput();

  if (input->GetDimension() == 2)
  {
    input->SetRequestedRegionToLargestPossibleRegion();
    return;
  }

  Image::RegionType requestedRegion;
  requestedRegion = output->GetRequestedRegion();
  requestedRegion.SetIndex(0, 0);
  requestedRegion.SetIndex(1, 0);
  requestedRegion.SetIndex(2, 0);
  requestedRegion.SetSize(0, input->GetDimension(0));
  requestedRegion.SetSize(1, input->GetDimension(1));
  requestedRegion.SetSize(2, input->GetDimension(2));

  requestedRegion.SetIndex( m_SliceDimension, m_SliceIndex ); // only one slice needed
  requestedRegion.SetSize( m_SliceDimension, 1 );

  input->SetRequestedRegion( &requestedRegion );
}

/*
 * Generate the information decribing the output data. The default
 * implementation of this method will copy information from the input to the
 * output. A filter may override this method if its output will have different
 * information than its input. For instance, a filter that shrinks an image will
 * need to provide an implementation for this method that changes the spacing of
 * the pixels. Such filters should call their superclass' implementation of this
 * method prior to changing the information values they need (i.e.
 * GenerateOutputInformation() should call
 * Superclass::GenerateOutputInformation() prior to changing the information.
 */
void mitk::ExtractImageFilter::GenerateOutputInformation()
{
 Image::Pointer output = this->GetOutput();
 Image::ConstPointer input = this->GetInput();
 if (input.IsNull()) return;

 if ( m_SliceDimension >= input->GetDimension() && input->GetDimension() != 2 )
 {
   std::cerr << "mitk::ExtractImageFilter:GenerateOutputInformation  m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl;
   itkExceptionMacro("This is not a sensible value for m_SliceDimension.");
   return;
 }

 unsigned int sliceDimension( m_SliceDimension );
 if ( input->GetDimension() == 2)
 {
   sliceDimension = 2;
 }

  unsigned int i(0);
  unsigned int tmpDimensions[2];

  switch ( sliceDimension )
  {
    default:
    case 2:
      // orientation = PlaneGeometry::Transversal;
      tmpDimensions[0] = input->GetDimension(0);
      tmpDimensions[1] = input->GetDimension(1);
      break;
    case 1:
      // orientation = PlaneGeometry::Frontal;
      tmpDimensions[0] = input->GetDimension(0);
      tmpDimensions[1] = input->GetDimension(2);
      break;
    case 0:
      // orientation = PlaneGeometry::Sagittal;
      tmpDimensions[0] = input->GetDimension(1);
      tmpDimensions[1] = input->GetDimension(2);
      break;
  }

  output->Initialize(input->GetPixelType(), 2, tmpDimensions, 1 /*input->GetNumberOfChannels()*/);

  // initialize the spacing of the output
/*
  Vector3D spacing = input->GetSlicedGeometry()->GetSpacing();
  if(input->GetDimension()>=2)
    spacing[2]=spacing[1];
  else
    spacing[2] = 1.0;
  output->GetSlicedGeometry()->SetSpacing(spacing);
*/

  output->SetPropertyList(input->GetPropertyList()->Clone());
}

<|endoftext|>