SuperTuxKart 1.5 upstream source (from official release tarball)

This commit is contained in:
Benjamin
2026-06-11 20:04:02 +02:00
commit 2957e51aaa
8551 changed files with 1801800 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,225 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__
#define __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__
#include "IAnimatedMeshSceneNode.h"
#include "IAnimatedMesh.h"
#include "matrix4.h"
#include <memory>
namespace GE
{
class GERenderInfo;
}
namespace irr
{
namespace scene
{
class IDummyTransformationSceneNode;
class CAnimatedMeshSceneNode : public IAnimatedMeshSceneNode
{
private:
core::array<u32> m_animation_set;
std::shared_ptr<GE::GERenderInfo> m_first_render_info;
public:
//! constructor
CAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));
//! destructor
virtual ~CAnimatedMeshSceneNode();
//! sets the current frame. from now on the animation is played from this frame.
virtual void setCurrentFrame(f32 frame);
//! frame
virtual void OnRegisterSceneNode();
//! OnAnimate() is called just before rendering the whole scene.
virtual void OnAnimate(u32 timeMs);
//! renders the node.
virtual void render();
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! sets the frames between the animation is looped.
//! the default is 0 - MaximalFrameCount of the mesh.
virtual bool setFrameLoop(s32 begin, s32 end);
//! Sets looping mode which is on by default. If set to false,
//! animations will not be looped.
virtual void setLoopMode(bool playAnimationLooped);
//! returns the current loop mode
virtual bool getLoopMode() const;
//! Sets a callback interface which will be called if an animation
//! playback has ended. Set this to 0 to disable the callback again.
virtual void setAnimationEndCallback(IAnimationEndCallBack* callback=0);
//! sets the speed with which the animation is played
virtual void setAnimationSpeed(f32 framesPerSecond);
//! gets the speed with which the animation is played
virtual f32 getAnimationSpeed() const;
//! Sets the animation strength (how important the animation is)
/** \param strength: The importance of the animation: 1.f keeps the original animation, 0.f is no animation. */
virtual void setAnimationStrength(f32 strength);
//! Gets the animation strength (how important the animation is)
/** \return The importance of the animation: 1.f keeps the original animation, 0.f is no animation. */
virtual f32 getAnimationStrength() const;
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hirachy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
virtual video::SMaterial& getMaterial(u32 i);
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const;
//! Returns a pointer to a child node, which has the same transformation as
//! the corrsesponding joint, if the mesh in this scene node is a skinned mesh.
virtual IBoneSceneNode* getJointNode(const c8* jointName);
//! same as getJointNode(const c8* jointName), but based on id
virtual IBoneSceneNode* getJointNode(u32 jointID);
//! Gets joint count.
virtual u32 getJointCount() const;
//! Deprecated command, please use getJointNode.
virtual ISceneNode* getMS3DJointNode(const c8* jointName);
//! Deprecated command, please use getJointNode.
virtual ISceneNode* getXJointNode(const c8* jointName);
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
//! Returns the current displayed frame number.
virtual f32 getFrameNr() const;
//! Returns the current start frame number.
virtual s32 getStartFrame() const;
//! Returns the current end frame number.
virtual s32 getEndFrame() const;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
virtual void setReadOnlyMaterials(bool readonly);
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const;
//! Sets a new mesh
virtual void setMesh(IAnimatedMesh* mesh);
//! Returns the current mesh
virtual IAnimatedMesh* getMesh(void) { return Mesh; }
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_ANIMATED_MESH; }
//! updates the absolute position based on the relative and the parents position
virtual void updateAbsolutePosition();
//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set)
virtual void setJointMode(E_JOINT_UPDATE_ON_RENDER mode);
//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2)
//! you must call animateJoints(), or the mesh will not animate
virtual void setTransitionTime(f32 Time);
//! updates the joint positions of this mesh
virtual void animateJoints(bool CalculateAbsolutePositions=true);
//! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected)
virtual void setRenderFromIdentity( bool On );
//! Creates a clone of this scene node and its children.
/** \param newParent An optional new parent.
\param newManager An optional new scene manager.
\return The newly created clone of this node. */
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
virtual u32 getAnimationSetNum() { return m_animation_set.size() / 2; }
virtual s32 getAnimationSet() const;
virtual void addAnimationSet(u32 start, u32 end)
{
m_animation_set.push_back(start);
m_animation_set.push_back(end);
}
virtual void removeAllAnimationSet() { m_animation_set.clear(); }
virtual void useAnimationSet(u32 set_num);
virtual void setFrameLoopOnce(s32 begin, s32 end);
virtual core::array<u32>& getAnimationSetFrames() { return m_animation_set; }
virtual void resetFirstRenderInfo(std::shared_ptr<GE::GERenderInfo> ri);
protected:
//! Get a static mesh for the current frame of this animated mesh
virtual IMesh* getMeshForCurrentFrame();
void buildFrameNr(u32 timeMs);
virtual void checkJoints();
void beginTransition();
core::array<video::SMaterial> Materials;
core::aabbox3d<f32> Box;
IAnimatedMesh* Mesh;
s32 StartFrame;
s32 EndFrame;
f32 FramesPerSecond;
f32 CurrentFrameNr;
f32 AnimationStrength;
u32 LastTimeMs;
u32 TransitionTime; //Transition time in millisecs
f32 Transiting; //is mesh transiting (plus cache of TransitionTime)
f32 TransitingBlend; //0-1, calculated on buildFrameNr
//0-unused, 1-get joints only, 2-set joints only, 3-move and set
E_JOINT_UPDATE_ON_RENDER JointMode;
bool JointsUsed;
bool Looping;
bool ReadOnlyMaterials;
bool RenderFromIdentity;
IAnimationEndCallBack* LoopCallBack;
s32 PassCount;
core::array<IBoneSceneNode* > JointChildSceneNodes;
core::array<core::matrix4> PretransitingSave;
};
} // end namespace scene
} // end namespace irr
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+712
View File
@@ -0,0 +1,712 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ATTRIBUTES_H_INCLUDED__
#define __C_ATTRIBUTES_H_INCLUDED__
#include "IAttributes.h"
#include "IAttribute.h"
namespace irr
{
namespace video
{
class ITexture;
class IVideoDriver;
}
namespace io
{
//! Implementation of the IAttributes interface
class CAttributes : public IAttributes
{
public:
CAttributes(video::IVideoDriver* driver=0);
~CAttributes();
//! Returns amount of attributes in this collection of attributes.
virtual u32 getAttributeCount() const;
//! Returns attribute name by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const c8* getAttributeName(s32 index);
//! Returns the type of an attribute
//! \param attributeName: Name for the attribute
virtual E_ATTRIBUTE_TYPE getAttributeType(const c8* attributeName);
//! Returns attribute type by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual E_ATTRIBUTE_TYPE getAttributeType(s32 index);
//! Returns the type string of the attribute
//! \param attributeName: String for the attribute type
virtual const wchar_t* getAttributeTypeString(const c8* attributeName);
//! Returns the type string of the attribute by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const wchar_t* getAttributeTypeString(s32 index);
//! Returns if an attribute with a name exists
virtual bool existsAttribute(const c8* attributeName);
//! Returns attribute index from name, -1 if not found
virtual s32 findAttribute(const c8* attributeName) const;
//! Removes all attributes
virtual void clear();
//! Reads attributes from a xml file.
//! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes'.
//! IF set to false, the first appearing list attributes are read.
virtual bool read(io::IXMLReader* reader, bool readCurrentElementOnly=false,
const wchar_t* nonDefaultElementName = 0);
//! Write these attributes into a xml file
virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* nonDefaultElementName=0);
/*
Integer Attribute
*/
//! Adds an attribute as integer
virtual void addInt(const c8* attributeName, s32 value);
//! Sets an attribute as integer value
virtual void setAttribute(const c8* attributeName, s32 value);
//! Gets an attribute as integer value
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual s32 getAttributeAsInt(const c8* attributeName) const;
//! Gets an attribute as integer value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual s32 getAttributeAsInt(s32 index) const;
//! Sets an attribute as integer value
virtual void setAttribute(s32 index, s32 value);
/*
Float Attribute
*/
//! Adds an attribute as float
virtual void addFloat(const c8* attributeName, f32 value);
//! Sets a attribute as float value
virtual void setAttribute(const c8* attributeName, f32 value);
//! Gets an attribute as float value
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual f32 getAttributeAsFloat(const c8* attributeName);
//! Gets an attribute as float value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual f32 getAttributeAsFloat(s32 index);
//! Sets an attribute as float value
virtual void setAttribute(s32 index, f32 value);
/*
String Attribute
*/
//! Adds an attribute as string
virtual void addString(const c8* attributeName, const c8* value);
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const c8* value);
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
//! or 0 if attribute is not set.
virtual core::stringc getAttributeAsString(const c8* attributeName);
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param target: Buffer where the string is copied to.
virtual void getAttributeAsString(const c8* attributeName, c8* target);
//! Returns attribute value as string by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::stringc getAttributeAsString(s32 index);
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
virtual void setAttribute(s32 index, const c8* value);
// wide strings
//! Adds an attribute as string
virtual void addString(const c8* attributeName, const wchar_t* value);
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const wchar_t* value);
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
//! or 0 if attribute is not set.
virtual core::stringw getAttributeAsStringW(const c8* attributeName);
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param target: Buffer where the string is copied to.
virtual void getAttributeAsStringW(const c8* attributeName, wchar_t* target);
//! Returns attribute value as string by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::stringw getAttributeAsStringW(s32 index);
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
virtual void setAttribute(s32 index, const wchar_t* value);
/*
Binary Data Attribute
*/
//! Adds an attribute as binary data
virtual void addBinary(const c8* attributeName, void* data, s32 dataSizeInBytes);
//! Sets an attribute as binary data
virtual void setAttribute(const c8* attributeName, void* data, s32 dataSizeInBytes);
//! Gets an attribute as binary data
//! \param attributeName: Name of the attribute to get.
virtual void getAttributeAsBinaryData(const c8* attributeName, void* outData, s32 maxSizeInBytes);
//! Gets an attribute as binary data
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void getAttributeAsBinaryData(s32 index, void* outData, s32 maxSizeInBytes);
//! Sets an attribute as binary data
virtual void setAttribute(s32 index, void* data, s32 dataSizeInBytes);
/*
Array Attribute
*/
//! Adds an attribute as wide string array
virtual void addArray(const c8* attributeName, const core::array<core::stringw>& value);
//! Sets an attribute value as a wide string array.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const core::array<core::stringw>& value);
//! Gets an attribute as an array of wide strings.
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
//! or 0 if attribute is not set.
virtual core::array<core::stringw> getAttributeAsArray(const c8* attributeName);
//! Returns attribute value as an array of wide strings by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::array<core::stringw> getAttributeAsArray(s32 index);
//! Sets an attribute as an array of wide strings
virtual void setAttribute(s32 index, const core::array<core::stringw>& value);
/*
Bool Attribute
*/
//! Adds an attribute as bool
virtual void addBool(const c8* attributeName, bool value);
//! Sets an attribute as boolean value
virtual void setAttribute(const c8* attributeName, bool value);
//! Gets an attribute as boolean value
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual bool getAttributeAsBool(const c8* attributeName);
//! Gets an attribute as boolean value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual bool getAttributeAsBool(s32 index);
//! Sets an attribute as boolean value
virtual void setAttribute(s32 index, bool value);
/*
Enumeration Attribute
*/
//! Adds an attribute as enum
virtual void addEnum(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals);
//! Adds an attribute as enum
virtual void addEnum(const c8* attributeName, s32 enumValue, const c8* const* enumerationLiterals);
//! Sets an attribute as enumeration
virtual void setAttribute(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals);
//! Gets an attribute as enumeration
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual const c8* getAttributeAsEnumeration(const c8* attributeName);
//! Gets an attribute as enumeration
//! \param attributeName: Name of the attribute to get.
//! \param enumerationLiteralsToUse: Use these enumeration literals to get the index value instead of the set ones.
//! This is useful when the attribute list maybe was read from an xml file, and only contains the enumeration string, but
//! no information about its index.
//! \return Returns value of the attribute previously set by setAttribute()
virtual s32 getAttributeAsEnumeration(const c8* attributeName, const c8* const* enumerationLiteralsToUse);
//! Gets an attribute as enumeration
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual s32 getAttributeAsEnumeration(s32 index, const c8* const* enumerationLiteralsToUse);
//! Gets an attribute as enumeration
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const c8* getAttributeAsEnumeration(s32 index);
//! Gets the list of enumeration literals of an enumeration attribute
//! \param attributeName: Name of the attribute to get.
virtual void getAttributeEnumerationLiteralsOfEnumeration(const c8* attributeName, core::array<core::stringc>& outLiterals);
//! Gets the list of enumeration literals of an enumeration attribute
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void getAttributeEnumerationLiteralsOfEnumeration(s32 index, core::array<core::stringc>& outLiterals);
//! Sets an attribute as enumeration
virtual void setAttribute(s32 index, const c8* enumValue, const c8* const* enumerationLiterals);
/*
SColor Attribute
*/
//! Adds an attribute as color
virtual void addColor(const c8* attributeName, video::SColor value);
//! Sets a attribute as color
virtual void setAttribute(const c8* attributeName, video::SColor color);
//! Gets an attribute as color
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual video::SColor getAttributeAsColor(const c8* attributeName);
//! Gets an attribute as color
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::SColor getAttributeAsColor(s32 index);
//! Sets an attribute as color
virtual void setAttribute(s32 index, video::SColor color);
/*
SColorf Attribute
*/
//! Adds an attribute as floating point color
virtual void addColorf(const c8* attributeName, video::SColorf value);
//! Sets a attribute as floating point color
virtual void setAttribute(const c8* attributeName, video::SColorf color);
//! Gets an attribute as floating point color
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual video::SColorf getAttributeAsColorf(const c8* attributeName);
//! Gets an attribute as floating point color
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::SColorf getAttributeAsColorf(s32 index);
//! Sets an attribute as floating point color
virtual void setAttribute(s32 index, video::SColorf color);
/*
Vector3d Attribute
*/
//! Adds an attribute as 3d vector
virtual void addVector3d(const c8* attributeName, core::vector3df value);
//! Sets a attribute as 3d vector
virtual void setAttribute(const c8* attributeName, core::vector3df v);
//! Gets an attribute as 3d vector
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::vector3df getAttributeAsVector3d(const c8* attributeName);
//! Gets an attribute as 3d vector
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::vector3df getAttributeAsVector3d(s32 index);
//! Sets an attribute as vector
virtual void setAttribute(s32 index, core::vector3df v);
/*
Vector2d Attribute
*/
//! Adds an attribute as 2d vector
virtual void addVector2d(const c8* attributeName, core::vector2df value);
//! Sets a attribute as 2d vector
virtual void setAttribute(const c8* attributeName, core::vector2df v);
//! Gets an attribute as 2d vector
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::vector2df getAttributeAsVector2d(const c8* attributeName);
//! Gets an attribute as 3d vector
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::vector2df getAttributeAsVector2d(s32 index);
//! Sets an attribute as vector
virtual void setAttribute(s32 index, core::vector2df v);
/*
Position2d Attribute
*/
//! Adds an attribute as 2d position
virtual void addPosition2d(const c8* attributeName, core::position2di value);
//! Sets a attribute as 2d position
virtual void setAttribute(const c8* attributeName, core::position2di v);
//! Gets an attribute as position
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::position2di getAttributeAsPosition2d(const c8* attributeName);
//! Gets an attribute as position
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::position2di getAttributeAsPosition2d(s32 index);
//! Sets an attribute as 2d position
virtual void setAttribute(s32 index, core::position2di v);
/*
Rectangle Attribute
*/
//! Adds an attribute as rectangle
virtual void addRect(const c8* attributeName, core::rect<s32> value);
//! Sets an attribute as rectangle
virtual void setAttribute(const c8* attributeName, core::rect<s32> v);
//! Gets an attribute as rectangle
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::rect<s32> getAttributeAsRect(const c8* attributeName);
//! Gets an attribute as rectangle
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::rect<s32> getAttributeAsRect(s32 index);
//! Sets an attribute as rectangle
virtual void setAttribute(s32 index, core::rect<s32> v);
/*
Dimension2d Attribute
*/
//! Adds an attribute as dimension2d
virtual void addDimension2d(const c8* attributeName, core::dimension2d<u32> value);
//! Sets an attribute as dimension2d
virtual void setAttribute(const c8* attributeName, core::dimension2d<u32> v);
//! Gets an attribute as dimension2d
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::dimension2d<u32> getAttributeAsDimension2d(const c8* attributeName) const;
//! Gets an attribute as dimension2d
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::dimension2d<u32> getAttributeAsDimension2d(s32 index) const;
//! Sets an attribute as dimension2d
virtual void setAttribute(s32 index, core::dimension2d<u32> v);
/*
matrix attribute
*/
//! Adds an attribute as matrix
virtual void addMatrix(const c8* attributeName, const core::matrix4& v);
//! Sets an attribute as matrix
virtual void setAttribute(const c8* attributeName, const core::matrix4& v);
//! Gets an attribute as a matrix4
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::matrix4 getAttributeAsMatrix(const c8* attributeName);
//! Gets an attribute as matrix
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::matrix4 getAttributeAsMatrix(s32 index);
//! Sets an attribute as matrix
virtual void setAttribute(s32 index, const core::matrix4& v);
/*
quaternion attribute
*/
//! Adds an attribute as quaternion
virtual void addQuaternion(const c8* attributeName, core::quaternion v);
//! Sets an attribute as quaternion
virtual void setAttribute(const c8* attributeName, core::quaternion v);
//! Gets an attribute as a quaternion
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::quaternion getAttributeAsQuaternion(const c8* attributeName);
//! Gets an attribute as quaternion
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::quaternion getAttributeAsQuaternion(s32 index);
//! Sets an attribute as quaternion
virtual void setAttribute(s32 index, core::quaternion v);
/*
3d bounding box
*/
//! Adds an attribute as axis aligned bounding box
virtual void addBox3d(const c8* attributeName, core::aabbox3df v);
//! Sets an attribute as axis aligned bounding box
virtual void setAttribute(const c8* attributeName, core::aabbox3df v);
//! Gets an attribute as a axis aligned bounding box
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::aabbox3df getAttributeAsBox3d(const c8* attributeName);
//! Gets an attribute as axis aligned bounding box
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::aabbox3df getAttributeAsBox3d(s32 index);
//! Sets an attribute as axis aligned bounding box
virtual void setAttribute(s32 index, core::aabbox3df v);
/*
plane
*/
//! Adds an attribute as 3d plane
virtual void addPlane3d(const c8* attributeName, core::plane3df v);
//! Sets an attribute as 3d plane
virtual void setAttribute(const c8* attributeName, core::plane3df v);
//! Gets an attribute as a 3d plane
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::plane3df getAttributeAsPlane3d(const c8* attributeName);
//! Gets an attribute as 3d plane
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::plane3df getAttributeAsPlane3d(s32 index);
//! Sets an attribute as 3d plane
virtual void setAttribute(s32 index, core::plane3df v);
/*
3d triangle
*/
//! Adds an attribute as 3d triangle
virtual void addTriangle3d(const c8* attributeName, core::triangle3df v);
//! Sets an attribute as 3d trianle
virtual void setAttribute(const c8* attributeName, core::triangle3df v);
//! Gets an attribute as a 3d triangle
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::triangle3df getAttributeAsTriangle3d(const c8* attributeName);
//! Gets an attribute as 3d triangle
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::triangle3df getAttributeAsTriangle3d(s32 index);
//! Sets an attribute as 3d triangle
virtual void setAttribute(s32 index, core::triangle3df v);
/*
line 2d
*/
//! Adds an attribute as a 2d line
virtual void addLine2d(const c8* attributeName, core::line2df v);
//! Sets an attribute as a 2d line
virtual void setAttribute(const c8* attributeName, core::line2df v);
//! Gets an attribute as a 2d line
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::line2df getAttributeAsLine2d(const c8* attributeName);
//! Gets an attribute as a 2d line
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::line2df getAttributeAsLine2d(s32 index);
//! Sets an attribute as a 2d line
virtual void setAttribute(s32 index, core::line2df v);
/*
line 3d
*/
//! Adds an attribute as a 3d line
virtual void addLine3d(const c8* attributeName, core::line3df v);
//! Sets an attribute as a 3d line
virtual void setAttribute(const c8* attributeName, core::line3df v);
//! Gets an attribute as a 3d line
//! \param attributeName: Name of the attribute to get.
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::line3df getAttributeAsLine3d(const c8* attributeName);
//! Gets an attribute as a 3d line
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::line3df getAttributeAsLine3d(s32 index);
//! Sets an attribute as a 3d line
virtual void setAttribute(s32 index, core::line3df v);
/*
Texture Attribute
*/
//! Adds an attribute as texture reference
virtual void addTexture(const c8* attributeName, video::ITexture* texture, const io::path& filename = "");
//! Sets an attribute as texture reference
virtual void setAttribute(const c8* attributeName, video::ITexture* texture, const io::path& filename = "");
//! Gets an attribute as texture reference
//! \param attributeName: Name of the attribute to get.
virtual video::ITexture* getAttributeAsTexture(const c8* attributeName);
//! Gets an attribute as texture reference
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::ITexture* getAttributeAsTexture(s32 index);
//! Sets an attribute as texture reference
virtual void setAttribute(s32 index, video::ITexture* texture, const io::path& filename = "");
/*
User Pointer Attribute
*/
//! Adds an attribute as user pointner
virtual void addUserPointer(const c8* attributeName, void* userPointer);
//! Sets an attribute as user pointer
virtual void setAttribute(const c8* attributeName, void* userPointer);
//! Gets an attribute as user pointer
//! \param attributeName: Name of the attribute to get.
virtual void* getAttributeAsUserPointer(const c8* attributeName);
//! Gets an attribute as user pointer
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void* getAttributeAsUserPointer(s32 index);
//! Sets an attribute as user pointer
virtual void setAttribute(s32 index, void* userPointer);
protected:
void readAttributeFromXML(io::IXMLReader* reader);
core::array<IAttribute*> Attributes;
IAttribute* getAttributeP(const c8* attributeName) const;
video::IVideoDriver* Driver;
};
} // end namespace io
} // end namespace irr
#endif
@@ -0,0 +1,294 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CBillboardSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop, video::SColor colorBottom)
: IBillboardSceneNode(parent, mgr, id, position)
{
#ifdef _DEBUG
setDebugName("CBillboardSceneNode");
#endif
setSize(size);
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
vertices[0].TCoords.set(1.0f, 1.0f);
vertices[0].Color = colorBottom;
vertices[1].TCoords.set(1.0f, 0.0f);
vertices[1].Color = colorTop;
vertices[2].TCoords.set(0.0f, 0.0f);
vertices[2].Color = colorTop;
vertices[3].TCoords.set(0.0f, 1.0f);
vertices[3].Color = colorBottom;
}
//! pre render event
void CBillboardSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CBillboardSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// make billboard look to camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
if ( horizontal.getLength() == 0 )
{
horizontal.set(up.Y,up.X,up.Z);
}
horizontal.normalize();
core::vector3df topHorizontal = horizontal * 0.5f * TopEdgeWidth;
horizontal *= 0.5f * Size.Width;
// pointing down!
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
vertical *= 0.5f * Size.Height;
view *= -1.0f;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
/* Vertices are:
2--1
|\ |
| \|
3--0
*/
vertices[0].Pos = pos + horizontal + vertical;
vertices[1].Pos = pos + topHorizontal - vertical;
vertices[2].Pos = pos - topHorizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
// draw
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBox, video::SColor(0,208,195,152));
}
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBillboardSceneNode::getBoundingBox() const
{
return BBox;
}
//! sets the size of the billboard
void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
Size = size;
if (core::equals(Size.Width, 0.0f))
Size.Width = 1.0f;
TopEdgeWidth = Size.Width;
if (core::equals(Size.Height, 0.0f))
Size.Height = 1.0f;
const f32 avg = (Size.Width + Size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
}
void CBillboardSceneNode::setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth)
{
Size.set(bottomEdgeWidth, height);
TopEdgeWidth = topEdgeWidth;
if (core::equals(Size.Height, 0.0f))
Size.Height = 1.0f;
if (core::equals(Size.Width, 0.f) && core::equals(TopEdgeWidth, 0.f))
{
Size.Width = 1.0f;
TopEdgeWidth = 1.0f;
}
const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
}
video::SMaterial& CBillboardSceneNode::getMaterial(u32 i)
{
return Material;
}
//! returns amount of materials used by this scene node.
u32 CBillboardSceneNode::getMaterialCount() const
{
return 1;
}
//! gets the size of the billboard
const core::dimension2d<f32>& CBillboardSceneNode::getSize() const
{
return Size;
}
//! Gets the widths of the top and bottom edges of the billboard.
void CBillboardSceneNode::getSize(f32& height, f32& bottomEdgeWidth,
f32& topEdgeWidth) const
{
height = Size.Height;
bottomEdgeWidth = Size.Width;
topEdgeWidth = TopEdgeWidth;
}
//! Writes attributes of the scene node.
void CBillboardSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IBillboardSceneNode::serializeAttributes(out, options);
out->addFloat("Width", Size.Width);
out->addFloat("TopEdgeWidth", TopEdgeWidth);
out->addFloat("Height", Size.Height);
out->addColor("Shade_Top", vertices[1].Color);
out->addColor("Shade_Down", vertices[0].Color);
}
//! Reads attributes of the scene node.
void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IBillboardSceneNode::deserializeAttributes(in, options);
Size.Width = in->getAttributeAsFloat("Width");
Size.Height = in->getAttributeAsFloat("Height");
if (in->existsAttribute("TopEdgeWidth"))
{
TopEdgeWidth = in->getAttributeAsFloat("TopEdgeWidth");
if (Size.Width != TopEdgeWidth)
setSize(Size.Height, Size.Width, TopEdgeWidth);
}
else
setSize(Size);
vertices[1].Color = in->getAttributeAsColor("Shade_Top");
vertices[0].Color = in->getAttributeAsColor("Shade_Down");
vertices[2].Color = vertices[1].Color;
vertices[3].Color = vertices[0].Color;
}
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
void CBillboardSceneNode::setColor(const video::SColor& overallColor)
{
for(u32 vertex = 0; vertex < 4; ++vertex)
vertices[vertex].Color = overallColor;
}
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
void CBillboardSceneNode::setColor(const video::SColor& topColor,
const video::SColor& bottomColor)
{
vertices[0].Color = bottomColor;
vertices[1].Color = topColor;
vertices[2].Color = topColor;
vertices[3].Color = bottomColor;
}
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
void CBillboardSceneNode::getColor(video::SColor& topColor,
video::SColor& bottomColor) const
{
bottomColor = vertices[0].Color;
topColor = vertices[1].Color;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CBillboardSceneNode* nb = new CBillboardSceneNode(newParent,
newManager, ID, RelativeTranslation, Size);
nb->cloneMembers(this, newManager);
nb->Material = Material;
nb->TopEdgeWidth = this->TopEdgeWidth;
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,99 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h"
#include "S3DVertex.h"
namespace irr
{
namespace scene
{
//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element,
//! which always looks to the camera.
class CBillboardSceneNode : virtual public IBillboardSceneNode
{
public:
//! constructor
CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop=video::SColor(0xFFFFFFFF),
video::SColor colorBottom=video::SColor(0xFFFFFFFF));
//! pre render event
virtual void OnRegisterSceneNode();
//! render
virtual void render();
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! sets the size of the billboard
virtual void setSize(const core::dimension2d<f32>& size);
//! Sets the widths of the top and bottom edges of the billboard independently.
virtual void setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth);
//! gets the size of the billboard
virtual const core::dimension2d<f32>& getSize() const;
//! Gets the widths of the top and bottom edges of the billboard.
virtual void getSize(f32& height, f32& bottomEdgeWidth, f32& topEdgeWidth) const;
virtual video::SMaterial& getMaterial(u32 i);
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const;
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
virtual void setColor(const video::SColor& overallColor);
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
virtual void setColor(const video::SColor& topColor,
const video::SColor& bottomColor);
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
virtual void getColor(video::SColor& topColor,
video::SColor& bottomColor) const;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_BILLBOARD; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
protected:
//! Size.Width is the bottom edge width
core::dimension2d<f32> Size;
f32 TopEdgeWidth;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
video::S3DVertex vertices[4];
u16 indices[6];
};
} // end namespace scene
} // end namespace irr
#endif
+812
View File
@@ -0,0 +1,812 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef _C_BLIT_H_INCLUDED_
#define _C_BLIT_H_INCLUDED_
#include "SoftwareDriver2_helper.h"
namespace irr
{
struct SBlitJob
{
AbsRectangle Dest;
AbsRectangle Source;
u32 argb;
void * src;
void * dst;
s32 width;
s32 height;
u32 srcPitch;
u32 dstPitch;
u32 srcPixelMul;
u32 dstPixelMul;
bool stretch;
float x_stretch;
float y_stretch;
SBlitJob() : stretch(false) {}
};
// Bitfields Cohen Sutherland
enum eClipCode
{
CLIPCODE_EMPTY = 0,
CLIPCODE_BOTTOM = 1,
CLIPCODE_TOP = 2,
CLIPCODE_LEFT = 4,
CLIPCODE_RIGHT = 8
};
inline u32 GetClipCode( const AbsRectangle &r, const core::position2d<s32> &p )
{
u32 code = CLIPCODE_EMPTY;
if ( p.X < r.x0 )
code = CLIPCODE_LEFT;
else
if ( p.X > r.x1 )
code = CLIPCODE_RIGHT;
if ( p.Y < r.y0 )
code |= CLIPCODE_TOP;
else
if ( p.Y > r.y1 )
code |= CLIPCODE_BOTTOM;
return code;
}
/*
*/
inline void GetClip(AbsRectangle &clipping, video::IImage * t)
{
clipping.x0 = 0;
clipping.y0 = 0;
clipping.x1 = t->getDimension().Width - 1;
clipping.y1 = t->getDimension().Height - 1;
}
/*
return alpha in [0;256] Granularity from 32-Bit ARGB
add highbit alpha ( alpha > 127 ? + 1 )
*/
static inline u32 extractAlpha(const u32 c)
{
return ( c >> 24 ) + ( c >> 31 );
}
/*
return alpha in [0;255] Granularity and 32-Bit ARGB
add highbit alpha ( alpha > 127 ? + 1 )
*/
static inline u32 packAlpha(const u32 c)
{
return (c > 127 ? c - 1 : c) << 24;
}
/*!
Scale Color by (1/value)
value 0 - 256 ( alpha )
*/
inline u32 PixelLerp32(const u32 source, const u32 value)
{
u32 srcRB = source & 0x00FF00FF;
u32 srcXG = (source & 0xFF00FF00) >> 8;
srcRB *= value;
srcXG *= value;
srcRB >>= 8;
//srcXG >>= 8;
srcXG &= 0xFF00FF00;
srcRB &= 0x00FF00FF;
return srcRB | srcXG;
}
/*!
*/
static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
if (job->stretch)
{
const u32 *src = static_cast<const u32*>(job->src);
u32 *dst = static_cast<u32*>(job->dst);
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
dst[dx] = src[src_x];
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
const u32 widthPitch = job->width * job->dstPixelMul;
const void *src = (void*) job->src;
void *dst = (void*) job->dst;
for ( u32 dy = 0; dy != h; ++dy )
{
memcpy( dst, src, widthPitch );
src = (void*) ( (u8*) (src) + job->srcPitch );
dst = (void*) ( (u8*) (dst) + job->dstPitch );
}
}
}
/*!
*/
static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u32 *src = static_cast<const u32*>(job->src);
u16 *dst = static_cast<u16*>(job->dst);
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
//16 bit Blitter depends on pre-multiplied color
const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) );
dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
}
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
for ( u32 dx = 0; dx != w; ++dx )
{
//16 bit Blitter depends on pre-multiplied color
const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) );
dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
}
src = (u32*) ( (u8*) (src) + job->srcPitch );
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
}
/*!
*/
static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u8 *src = static_cast<const u8*>(job->src);
u16 *dst = static_cast<u16*>(job->dst);
if (job->stretch)
{
const float wscale = 3.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u8*)(job->src) + job->srcPitch*src_y;
for ( u32 dx = 0; dx < w; ++dx )
{
const u8* src_x = src+(u32)(dx*wscale);
dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]);
}
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
const u8* s = src;
for ( u32 dx = 0; dx != w; ++dx )
{
dst[dx] = video::RGBA16(s[0], s[1], s[2]);
s += 3;
}
src = src+job->srcPitch;
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
}
/*!
*/
static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u16 *src = static_cast<const u16*>(job->src);
u32 *dst = static_cast<u32*>(job->dst);
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]);
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
for ( u32 dx = 0; dx != w; ++dx )
{
dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] );
}
src = (u16*) ( (u8*) (src) + job->srcPitch );
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
}
static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u16 *src = static_cast<const u16*>(job->src);
u8 *dst = static_cast<u8*>(job->dst);
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]);
u8 * writeTo = &dst[dx * 3];
*writeTo++ = (color >> 16)& 0xFF;
*writeTo++ = (color >> 8) & 0xFF;
*writeTo++ = color & 0xFF;
}
dst += job->dstPitch;
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
for ( u32 dx = 0; dx != w; ++dx )
{
u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]);
u8 * writeTo = &dst[dx * 3];
*writeTo++ = (color >> 16)& 0xFF;
*writeTo++ = (color >> 8) & 0xFF;
*writeTo++ = color & 0xFF;
}
src = (u16*) ( (u8*) (src) + job->srcPitch );
dst += job->dstPitch;
}
}
}
/*!
*/
static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u8 *src = static_cast<const u8*>(job->src);
u32 *dst = static_cast<u32*>(job->dst);
if (job->stretch)
{
const float wscale = 3.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (const u8*)job->src+(job->srcPitch*src_y);
for ( u32 dx = 0; dx < w; ++dx )
{
const u8* s = src+(u32)(dx*wscale);
dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
for ( s32 dy = 0; dy != job->height; ++dy )
{
const u8* s = src;
for ( s32 dx = 0; dx != job->width; ++dx )
{
dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
s += 3;
}
src = src + job->srcPitch;
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
}
static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u32 *src = static_cast<const u32*>(job->src);
u8 *dst = static_cast<u8*>(job->dst);
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = src[(u32)(dx*wscale)];
u8 * writeTo = &dst[dx * 3];
*writeTo++ = (src_x >> 16)& 0xFF;
*writeTo++ = (src_x >> 8) & 0xFF;
*writeTo++ = src_x & 0xFF;
}
dst += job->dstPitch;
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
for ( u32 dx = 0; dx != w; ++dx )
{
u8 * writeTo = &dst[dx * 3];
*writeTo++ = (src[dx] >> 16)& 0xFF;
*writeTo++ = (src[dx] >> 8) & 0xFF;
*writeTo++ = src[dx] & 0xFF;
}
src = (u32*) ( (u8*) (src) + job->srcPitch );
dst += job->dstPitch;
}
}
}
/*!
*/
static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u32 rdx = w>>1;
const u32 *src = (u32*) job->src;
u32 *dst = (u32*) job->dst;
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
const u32 off = core::if_c_a_else_b(w&1, (u32)((w-1)*wscale), 0);
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < rdx; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
dst[dx] = PixelBlend16_simd( dst[dx], src[src_x] );
}
if ( off )
{
((u16*) dst)[off] = PixelBlend16( ((u16*) dst)[off], ((u16*) src)[off] );
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
const u32 off = core::if_c_a_else_b(w&1, w-1, 0);
for (u32 dy = 0; dy != h; ++dy )
{
for (u32 dx = 0; dx != rdx; ++dx )
{
dst[dx] = PixelBlend16_simd( dst[dx], src[dx] );
}
if ( off )
{
((u16*) dst)[off] = PixelBlend16( ((u16*) dst)[off], ((u16*) src)[off] );
}
src = (u32*) ( (u8*) (src) + job->srcPitch );
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
}
/*!
*/
static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job )
{
const u32 w = job->width;
const u32 h = job->height;
const u32 *src = (u32*) job->src;
u32 *dst = (u32*) job->dst;
if (job->stretch)
{
const float wscale = 1.f/job->x_stretch;
const float hscale = 1.f/job->y_stretch;
for ( u32 dy = 0; dy < h; ++dy )
{
const u32 src_y = (u32)(dy*hscale);
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
for ( u32 dx = 0; dx < w; ++dx )
{
const u32 src_x = (u32)(dx*wscale);
dst[dx] = PixelBlend32( dst[dx], src[src_x] );
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
else
{
for ( u32 dy = 0; dy != h; ++dy )
{
for ( u32 dx = 0; dx != w; ++dx )
{
dst[dx] = PixelBlend32( dst[dx], src[dx] );
}
src = (u32*) ( (u8*) (src) + job->srcPitch );
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
}
/*!
*/
static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job )
{
u16 *src = (u16*) job->src;
u16 *dst = (u16*) job->dst;
u16 blend = video::A8R8G8B8toA1R5G5B5 ( job->argb );
for ( s32 dy = 0; dy != job->height; ++dy )
{
for ( s32 dx = 0; dx != job->width; ++dx )
{
if ( 0 == (src[dx] & 0x8000) )
continue;
dst[dx] = PixelMul16_2( src[dx], blend );
}
src = (u16*) ( (u8*) (src) + job->srcPitch );
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
/*!
*/
static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job )
{
u32 *src = (u32*) job->src;
u32 *dst = (u32*) job->dst;
for ( s32 dy = 0; dy != job->height; ++dy )
{
for ( s32 dx = 0; dx != job->width; ++dx )
{
dst[dx] = PixelBlend32( dst[dx], PixelMul32_2( src[dx], job->argb ) );
}
src = (u32*) ( (u8*) (src) + job->srcPitch );
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
/*!
*/
static void executeBlit_Color_16_to_16( const SBlitJob * job )
{
const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb);
u16 *dst = (u16*) job->dst;
for ( s32 dy = 0; dy != job->height; ++dy )
{
memset16(dst, c, job->srcPitch);
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
/*!
*/
static void executeBlit_Color_32_to_32( const SBlitJob * job )
{
u32 *dst = (u32*) job->dst;
for ( s32 dy = 0; dy != job->height; ++dy )
{
memset32( dst, job->argb, job->srcPitch );
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
/*!
*/
static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job )
{
u16 *dst = (u16*) job->dst;
const u16 alpha = extractAlpha( job->argb ) >> 3;
if ( 0 == alpha )
return;
const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb );
for ( s32 dy = 0; dy != job->height; ++dy )
{
for ( s32 dx = 0; dx != job->width; ++dx )
{
dst[dx] = 0x8000 | PixelBlend16( dst[dx], src, alpha );
}
dst = (u16*) ( (u8*) (dst) + job->dstPitch );
}
}
/*!
*/
static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )
{
u32 *dst = (u32*) job->dst;
const u32 alpha = extractAlpha( job->argb );
const u32 src = job->argb;
for ( s32 dy = 0; dy != job->height; ++dy )
{
for ( s32 dx = 0; dx != job->width; ++dx )
{
dst[dx] = (job->argb & 0xFF000000 ) | PixelBlend32( dst[dx], src, alpha );
}
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
}
}
// Blitter Operation
enum eBlitter
{
BLITTER_INVALID = 0,
BLITTER_COLOR,
BLITTER_COLOR_ALPHA,
BLITTER_TEXTURE,
BLITTER_TEXTURE_ALPHA_BLEND,
BLITTER_TEXTURE_ALPHA_COLOR_BLEND
};
typedef void (*tExecuteBlit) ( const SBlitJob * job );
/*!
*/
struct blitterTable
{
eBlitter operation;
s32 destFormat;
s32 sourceFormat;
tExecuteBlit func;
};
static const blitterTable blitTable[] =
{
{ BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x },
{ BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 },
{ BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
{ BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 },
{ BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
{ BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 },
{ BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 },
{ BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 },
{ BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 },
{ BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 },
{ BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 },
{ BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 },
{ BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },
{ BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },
{ BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },
{ BLITTER_INVALID, -1, -1, 0 }
};
static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source )
{
video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 );
video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 );
const blitterTable * b = blitTable;
while ( b->operation != BLITTER_INVALID )
{
if ( b->operation == operation )
{
if (( b->destFormat == -1 || b->destFormat == destFormat ) &&
( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) )
return b->func;
else
if ( b->destFormat == -2 && ( sourceFormat == destFormat ) )
return b->func;
}
b += 1;
}
return 0;
}
// bounce clipping to texture
inline void setClip ( AbsRectangle &out, const core::rect<s32> *clip,
const video::IImage * tex, s32 passnative )
{
if ( clip && 0 == tex && passnative )
{
out.x0 = clip->UpperLeftCorner.X;
out.x1 = clip->LowerRightCorner.X;
out.y0 = clip->UpperLeftCorner.Y;
out.y1 = clip->LowerRightCorner.Y;
return;
}
const s32 w = tex ? tex->getDimension().Width : 0;
const s32 h = tex ? tex->getDimension().Height : 0;
if ( clip )
{
out.x0 = core::s32_clamp ( clip->UpperLeftCorner.X, 0, w );
out.x1 = core::s32_clamp ( clip->LowerRightCorner.X, out.x0, w );
out.y0 = core::s32_clamp ( clip->UpperLeftCorner.Y, 0, h );
out.y1 = core::s32_clamp ( clip->LowerRightCorner.Y, out.y0, h );
}
else
{
out.x0 = 0;
out.y0 = 0;
out.x1 = w;
out.y1 = h;
}
}
/*!
a generic 2D Blitter
*/
static s32 Blit(eBlitter operation,
video::IImage * dest,
const core::rect<s32> *destClipping,
const core::position2d<s32> *destPos,
video::IImage * const source,
const core::rect<s32> *sourceClipping,
u32 argb)
{
tExecuteBlit blitter = getBlitter2( operation, dest, source );
if ( 0 == blitter )
{
return 0;
}
// Clipping
AbsRectangle sourceClip;
AbsRectangle destClip;
AbsRectangle v;
SBlitJob job;
setClip ( sourceClip, sourceClipping, source, 1 );
setClip ( destClip, destClipping, dest, 0 );
v.x0 = destPos ? destPos->X : 0;
v.y0 = destPos ? destPos->Y : 0;
v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 );
v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 );
if ( !intersect( job.Dest, destClip, v ) )
return 0;
job.width = job.Dest.x1 - job.Dest.x0;
job.height = job.Dest.y1 - job.Dest.y0;
job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 );
job.Source.x1 = job.Source.x0 + job.width;
job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 );
job.Source.y1 = job.Source.y0 + job.height;
job.argb = argb;
if ( source )
{
job.srcPitch = source->getPitch();
job.srcPixelMul = source->getBytesPerPixel();
job.src = (void*) ( (u8*) source->lock() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );
}
else
{
// use srcPitch for color operation on dest
job.srcPitch = job.width * dest->getBytesPerPixel();
}
job.dstPitch = dest->getPitch();
job.dstPixelMul = dest->getBytesPerPixel();
job.dst = (void*) ( (u8*) dest->lock() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );
blitter( &job );
if ( source )
source->unlock();
if ( dest )
dest->unlock();
return 1;
}
}
#endif
@@ -0,0 +1,127 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
#include "CBoneSceneNode.h"
namespace irr
{
namespace scene
{
//! constructor
CBoneSceneNode::CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
u32 boneIndex, const c8* boneName)
: IBoneSceneNode(parent, mgr, id), BoneIndex(boneIndex),
AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL)
{
#ifdef _DEBUG
setDebugName("CBoneSceneNode");
#endif
setName(boneName);
}
//! Returns the index of the bone
u32 CBoneSceneNode::getBoneIndex() const
{
return BoneIndex;
}
//! Sets the animation mode of the bone. Returns true if successful.
bool CBoneSceneNode::setAnimationMode(E_BONE_ANIMATION_MODE mode)
{
AnimationMode = mode;
return true;
}
//! Gets the current animation mode of the bone
E_BONE_ANIMATION_MODE CBoneSceneNode::getAnimationMode() const
{
return AnimationMode;
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBoneSceneNode::getBoundingBox() const
{
return Box;
}
/*
//! Returns the relative transformation of the scene node.
core::matrix4 CBoneSceneNode::getRelativeTransformation() const
{
return core::matrix4(); // RelativeTransformation;
}
*/
void CBoneSceneNode::OnAnimate(u32 timeMs)
{
if (IsVisible)
{
// animate this node with all animators
ISceneNodeAnimatorList::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
(*ait)->animateNode(this, timeMs);
// update absolute position
//updateAbsolutePosition();
// perform the post render process on all children
for (unsigned i = 0; i < Children.size(); ++i)
Children[i]->OnAnimate(timeMs);
}
}
void CBoneSceneNode::helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node)
{
Node->updateAbsolutePosition();
for (unsigned i = 0; i < Node->getChildren().size(); ++i)
{
helper_updateAbsolutePositionOfAllChildren( Node->getChildren()[i] );
}
}
void CBoneSceneNode::updateAbsolutePositionOfAllChildren()
{
helper_updateAbsolutePositionOfAllChildren( this );
}
void CBoneSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IBoneSceneNode::serializeAttributes(out, options);
out->addInt("BoneIndex", BoneIndex);
out->addEnum("AnimationMode", AnimationMode, BoneAnimationModeNames);
}
void CBoneSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
BoneIndex = in->getAttributeAsInt("BoneIndex");
AnimationMode = (E_BONE_ANIMATION_MODE)in->getAttributeAsEnumeration("AnimationMode", BoneAnimationModeNames);
// for legacy files (before 1.5)
const core::stringc boneName = in->getAttributeAsString("BoneName");
setName(boneName);
IBoneSceneNode::deserializeAttributes(in, options);
// TODO: add/replace bone in parent with bone from mesh
}
} // namespace scene
} // namespace irr
#endif
@@ -0,0 +1,85 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BONE_SCENE_NODE_H_INCLUDED__
#define __C_BONE_SCENE_NODE_H_INCLUDED__
// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes
#include "IBoneSceneNode.h"
namespace irr
{
namespace scene
{
class CBoneSceneNode : public IBoneSceneNode
{
public:
//! constructor
CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr,
s32 id=-1, u32 boneIndex=0, const c8* boneName=0);
//! Returns the index of the bone
virtual u32 getBoneIndex() const;
//! Sets the animation mode of the bone. Returns true if successful.
virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode);
//! Gets the current animation mode of the bone
virtual E_BONE_ANIMATION_MODE getAnimationMode() const;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
/*
//! Returns the relative transformation of the scene node.
//virtual core::matrix4 getRelativeTransformation() const;
*/
virtual void OnAnimate(u32 timeMs);
virtual void updateAbsolutePosition()
{
if (SkinningSpace == EBSS_GLOBAL) return;
IBoneSceneNode::updateAbsolutePosition();
}
virtual void updateAbsolutePositionOfAllChildren();
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! How the relative transformation of the bone is used
virtual void setSkinningSpace( E_BONE_SKINNING_SPACE space )
{
SkinningSpace=space;
}
virtual E_BONE_SKINNING_SPACE getSkinningSpace() const
{
return SkinningSpace;
}
private:
void helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node);
u32 BoneIndex;
core::aabbox3d<f32> Box;
E_BONE_ANIMATION_MODE AnimationMode;
E_BONE_SKINNING_SPACE SkinningSpace;
};
} // end namespace scene
} // end namespace irr
#endif
@@ -0,0 +1,385 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CCameraSceneNode.h"
#include "ISceneManager.h"
#include "IVideoDriver.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::vector3df& lookat)
: ICameraSceneNode(parent, mgr, id, position),
Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),
InputReceiverEnabled(true), TargetAndRotationAreBound(false)
{
#ifdef _DEBUG
setDebugName("CCameraSceneNode");
#endif
// set default projection
Fovy = core::PI / 2.5f; // Field of view, in radians.
const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0;
if (d)
Aspect = (f32)d->getCurrentRenderTargetSize().Width /
(f32)d->getCurrentRenderTargetSize().Height;
else
Aspect = 4.0f / 3.0f; // Aspect ratio.
recalculateProjectionMatrix();
recalculateViewArea();
}
//! Disables or enables the camera to get key or mouse inputs.
void CCameraSceneNode::setInputReceiverEnabled(bool enabled)
{
InputReceiverEnabled = enabled;
}
//! Returns if the input receiver of the camera is currently enabled.
bool CCameraSceneNode::isInputReceiverEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return InputReceiverEnabled;
}
//! Sets the projection matrix of the camera.
/** The core::matrix4 class has some methods
to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH
\param projection: The new projection matrix of the camera. */
void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)
{
IsOrthogonal = isOrthogonal;
ViewArea.getTransform ( video::ETS_PROJECTION ) = projection;
}
//! Gets the current projection matrix of the camera
//! \return Returns the current projection matrix of the camera.
const core::matrix4& CCameraSceneNode::getProjectionMatrix() const
{
return ViewArea.getTransform ( video::ETS_PROJECTION );
}
//! Gets the current view matrix of the camera
//! \return Returns the current view matrix of the camera.
const core::matrix4& CCameraSceneNode::getViewMatrix() const
{
return ViewArea.getTransform ( video::ETS_VIEW );
}
//! Sets a custom view matrix affector. The matrix passed here, will be
//! multiplied with the view matrix when it gets updated.
//! This allows for custom camera setups like, for example, a reflection camera.
/** \param affector: The affector matrix. */
void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)
{
Affector = affector;
}
//! Gets the custom view matrix affector.
const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const
{
return Affector;
}
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
bool CCameraSceneNode::OnEvent(const SEvent& event)
{
if (!InputReceiverEnabled)
return false;
// send events to event receiving animators
ISceneNodeAnimatorList::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
if ((*ait)->isEventReceiverEnabled() && (*ait)->OnEvent(event))
return true;
// if nobody processed the event, return false
return false;
}
//! sets the look at target of the camera
//! \param pos: Look at target of the camera.
void CCameraSceneNode::setTarget(const core::vector3df& pos)
{
Target = pos;
if(TargetAndRotationAreBound)
{
const core::vector3df toTarget = Target - getAbsolutePosition();
ISceneNode::setRotation(toTarget.getHorizontalAngle());
}
}
//! Sets the rotation of the node.
/** This only modifies the relative rotation of the node.
If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's target to match the rotation.
\param rotation New rotation of the node in degrees. */
void CCameraSceneNode::setRotation(const core::vector3df& rotation)
{
if(TargetAndRotationAreBound)
Target = getAbsolutePosition() + rotation.rotationToDirection();
ISceneNode::setRotation(rotation);
}
//! Gets the current look at target of the camera
//! \return Returns the current look at target of the camera
const core::vector3df& CCameraSceneNode::getTarget() const
{
return Target;
}
//! sets the up vector of the camera
//! \param pos: New upvector of the camera.
void CCameraSceneNode::setUpVector(const core::vector3df& pos)
{
UpVector = pos;
}
//! Gets the up vector of the camera.
//! \return Returns the up vector of the camera.
const core::vector3df& CCameraSceneNode::getUpVector() const
{
return UpVector;
}
f32 CCameraSceneNode::getNearValue() const
{
return ZNear;
}
f32 CCameraSceneNode::getFarValue() const
{
return ZFar;
}
f32 CCameraSceneNode::getAspectRatio() const
{
return Aspect;
}
f32 CCameraSceneNode::getFOV() const
{
return Fovy;
}
void CCameraSceneNode::setNearValue(f32 f)
{
ZNear = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setFarValue(f32 f)
{
ZFar = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setAspectRatio(f32 f)
{
Aspect = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setFOV(f32 f)
{
Fovy = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::recalculateProjectionMatrix()
{
ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar);
}
//! prerender
void CCameraSceneNode::OnRegisterSceneNode()
{
if ( SceneManager->getActiveCamera () == this )
SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CCameraSceneNode::render()
{
core::vector3df pos = getAbsolutePosition();
core::vector3df tgtv = Target - pos;
tgtv.normalize();
// if upvector and vector to the target are the same, we have a
// problem. so solve this problem:
core::vector3df up = UpVector;
up.normalize();
f32 dp = tgtv.dotProduct(up);
if ( core::equals(core::abs_<f32>(dp), 1.f) )
{
up.X += 0.5f;
}
ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up);
ViewArea.getTransform(video::ETS_VIEW) *= Affector;
recalculateViewArea();
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if ( driver)
{
driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) );
driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) );
}
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CCameraSceneNode::getBoundingBox() const
{
return ViewArea.getBoundingBox();
}
//! returns the view frustum. needed sometimes by bsp or lod render nodes.
const SViewFrustum* CCameraSceneNode::getViewFrustum() const
{
return &ViewArea;
}
void CCameraSceneNode::recalculateViewArea()
{
ViewArea.cameraPosition = getAbsolutePosition();
core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION),
ViewArea.getTransform(video::ETS_VIEW));
ViewArea.setFrom(m);
}
//! Writes attributes of the scene node.
void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ICameraSceneNode::serializeAttributes(out, options);
out->addVector3d("Target", Target);
out->addVector3d("UpVector", UpVector);
out->addFloat("Fovy", Fovy);
out->addFloat("Aspect", Aspect);
out->addFloat("ZNear", ZNear);
out->addFloat("ZFar", ZFar);
out->addBool("Binding", TargetAndRotationAreBound);
out->addBool("ReceiveInput", InputReceiverEnabled);
}
//! Reads attributes of the scene node.
void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
ICameraSceneNode::deserializeAttributes(in, options);
Target = in->getAttributeAsVector3d("Target");
UpVector = in->getAttributeAsVector3d("UpVector");
Fovy = in->getAttributeAsFloat("Fovy");
Aspect = in->getAttributeAsFloat("Aspect");
ZNear = in->getAttributeAsFloat("ZNear");
ZFar = in->getAttributeAsFloat("ZFar");
TargetAndRotationAreBound = in->getAttributeAsBool("Binding");
if ( in->findAttribute("ReceiveInput") )
InputReceiverEnabled = in->getAttributeAsBool("InputReceiverEnabled");
recalculateProjectionMatrix();
recalculateViewArea();
}
//! Set the binding between the camera's rotation adn target.
void CCameraSceneNode::bindTargetAndRotation(bool bound)
{
TargetAndRotationAreBound = bound;
}
//! Gets the binding between the camera's rotation and target.
bool CCameraSceneNode::getTargetAndRotationBinding(void) const
{
return TargetAndRotationAreBound;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
ICameraSceneNode::clone(newParent, newManager);
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CCameraSceneNode* nb = new CCameraSceneNode(newParent,
newManager, ID, RelativeTranslation, Target);
nb->ISceneNode::cloneMembers(this, newManager);
nb->ICameraSceneNode::cloneMembers(this);
nb->Target = Target;
nb->UpVector = UpVector;
nb->Fovy = Fovy;
nb->Aspect = Aspect;
nb->ZNear = ZNear;
nb->ZFar = ZFar;
nb->ViewArea = ViewArea;
nb->Affector = Affector;
nb->InputReceiverEnabled = InputReceiverEnabled;
nb->TargetAndRotationAreBound = TargetAndRotationAreBound;
if ( newParent )
nb->drop();
return nb;
}
} // end namespace
} // end namespace
@@ -0,0 +1,172 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_CAMERA_SCENE_NODE_H_INCLUDED__
#define __C_CAMERA_SCENE_NODE_H_INCLUDED__
#include "ICameraSceneNode.h"
#include "SViewFrustum.h"
namespace irr
{
namespace scene
{
class CCameraSceneNode : public ICameraSceneNode
{
public:
//! constructor
CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& lookat = core::vector3df(0,0,100));
//! Sets the projection matrix of the camera.
/** The core::matrix4 class has some methods
to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH.
Note that the matrix will only stay as set by this method until one of
the following Methods are called: setNearValue, setFarValue, setAspectRatio, setFOV.
\param projection The new projection matrix of the camera.
\param isOrthogonal Set this to true if the matrix is an orthogonal one (e.g.
from matrix4::buildProjectionMatrixOrthoLH(). */
virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal = false);
//! Gets the current projection matrix of the camera
//! \return Returns the current projection matrix of the camera.
virtual const core::matrix4& getProjectionMatrix() const;
//! Gets the current view matrix of the camera
//! \return Returns the current view matrix of the camera.
virtual const core::matrix4& getViewMatrix() const;
//! Sets a custom view matrix affector.
/** \param affector: The affector matrix. */
virtual void setViewMatrixAffector(const core::matrix4& affector);
//! Gets the custom view matrix affector.
virtual const core::matrix4& getViewMatrixAffector() const;
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
virtual bool OnEvent(const SEvent& event);
//! Sets the look at target of the camera
/** If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's scene node rotation to match the target.
\param pos: Look at target of the camera. */
virtual void setTarget(const core::vector3df& pos);
//! Sets the rotation of the node.
/** This only modifies the relative rotation of the node.
If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's target to match the rotation.
\param rotation New rotation of the node in degrees. */
virtual void setRotation(const core::vector3df& rotation);
//! Gets the current look at target of the camera
/** \return The current look at target of the camera */
virtual const core::vector3df& getTarget() const;
//! Sets the up vector of the camera.
//! \param pos: New upvector of the camera.
virtual void setUpVector(const core::vector3df& pos);
//! Gets the up vector of the camera.
//! \return Returns the up vector of the camera.
virtual const core::vector3df& getUpVector() const;
//! Gets distance from the camera to the near plane.
//! \return Value of the near plane of the camera.
virtual f32 getNearValue() const;
//! Gets the distance from the camera to the far plane.
//! \return Value of the far plane of the camera.
virtual f32 getFarValue() const;
//! Get the aspect ratio of the camera.
//! \return The aspect ratio of the camera.
virtual f32 getAspectRatio() const;
//! Gets the field of view of the camera.
//! \return Field of view of the camera
virtual f32 getFOV() const;
//! Sets the value of the near clipping plane. (default: 1.0f)
virtual void setNearValue(f32 zn);
//! Sets the value of the far clipping plane (default: 2000.0f)
virtual void setFarValue(f32 zf);
//! Sets the aspect ratio (default: 4.0f / 3.0f)
virtual void setAspectRatio(f32 aspect);
//! Sets the field of view (Default: PI / 3.5f)
virtual void setFOV(f32 fovy);
//! PreRender event
virtual void OnRegisterSceneNode();
//! Render
virtual void render();
//! Returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! Returns the view area. Sometimes needed by bsp or lod render nodes.
virtual const SViewFrustum* getViewFrustum() const;
//! Disables or enables the camera to get key or mouse inputs.
//! If this is set to true, the camera will respond to key inputs
//! otherwise not.
virtual void setInputReceiverEnabled(bool enabled);
//! Returns if the input receiver of the camera is currently enabled.
virtual bool isInputReceiverEnabled() const;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_CAMERA; }
//! Binds the camera scene node's rotation to its target position and vice vera, or unbinds them.
virtual void bindTargetAndRotation(bool bound);
//! Queries if the camera scene node's rotation and its target position are bound together.
virtual bool getTargetAndRotationBinding(void) const;
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
protected:
void recalculateProjectionMatrix();
void recalculateViewArea();
core::vector3df Target;
core::vector3df UpVector;
f32 Fovy; // Field of view, in radians.
f32 Aspect; // Aspect ratio.
f32 ZNear; // value of the near view-plane.
f32 ZFar; // Z-value of the far view-plane.
SViewFrustum ViewArea;
core::matrix4 Affector;
bool InputReceiverEnabled;
bool TargetAndRotationAreBound;
};
} // end namespace
} // end namespace
#endif
@@ -0,0 +1,759 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CColorConverter.h"
#include "SColor.h"
#include "os.h"
#include "irrString.h"
namespace irr
{
namespace video
{
//! converts a monochrome bitmap to A1R5G5B5 data
void CColorConverter::convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
s32 shift = 7;
if (flip)
out -= width;
for (s32 x=0; x<width; ++x)
{
out[x] = *in>>shift & 0x01 ? (s16)0xffff : (s16)0x8000;
if ((--shift)<0) // 8 pixel done
{
shift=7;
++in;
}
}
if (shift != 7) // width did not fill last byte
++in;
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 4 bit palettized image to A1R5G5B5
void CColorConverter::convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip)
{
if (!in || !out || !palette)
return;
if (flip)
out += width*height;
for (s32 y=0; y<height; ++y)
{
s32 shift = 4;
if (flip)
out -= width;
for (s32 x=0; x<width; ++x)
{
out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)((*in >> shift) & 0xf)]);
if (shift==0)
{
shift = 4;
++in;
}
else
shift = 0;
}
if (shift == 0) // odd width
++in;
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 8 bit palettized image into A1R5G5B5
void CColorConverter::convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip)
{
if (!in || !out || !palette)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width; // one line back
for (s32 x=0; x<width; ++x)
{
out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)(*in)]);
++in;
}
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const s32 lineWidth = 3 * width;
if (flip)
out += lineWidth * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= lineWidth; // one line back
for (s32 x=0; x< lineWidth; x += 3)
{
if ( palette )
{
#ifdef __BIG_ENDIAN__
out[x+0] = palette[ (in[0] << 2 ) + 0];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 2];
#else
out[x+0] = palette[ (in[0] << 2 ) + 2];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 0];
#endif
}
else
{
out[x+0] = in[0];
out[x+1] = in[0];
out[x+2] = in[0];
}
++in;
}
if (!flip)
out += lineWidth;
in += linepad;
}
}
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const u32 lineWidth = 4 * width;
if (flip)
out += lineWidth * height;
u32 x;
u32 c;
for (u32 y=0; y < (u32) height; ++y)
{
if (flip)
out -= lineWidth; // one line back
if ( palette )
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
((u32*)out)[x] = ((u32*)palette)[ c ];
}
}
else
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
#ifdef __BIG_ENDIAN__
((u32*)out)[x] = c << 24 | c << 16 | c << 8 | 0x000000FF;
#else
((u32*)out)[x] = 0xFF000000 | c << 16 | c << 8 | c;
#endif
}
}
if (!flip)
out += lineWidth;
in += width + linepad;
}
}
//! converts 16bit data to 16bit data
void CColorConverter::convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width;
#ifdef __BIG_ENDIAN__
for (s32 x=0; x<width; ++x)
out[x]=os::Byteswap::byteswap(in[x]);
#else
memcpy(out, in, width*sizeof(s16));
#endif
if (!flip)
out += width;
in += width;
in += linepad;
}
}
//! copies R8G8B8 24bit data to 24bit data
void CColorConverter::convert24BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, s32 linepad, bool flip, bool bgr)
{
if (!in || !out)
return;
const s32 lineWidth = 3 * width;
if (flip)
out += lineWidth * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= lineWidth;
if (bgr)
{
for (s32 x=0; x<lineWidth; x+=3)
{
out[x+0] = in[x+2];
out[x+1] = in[x+1];
out[x+2] = in[x+0];
}
}
else
{
memcpy(out,in,lineWidth);
}
if (!flip)
out += lineWidth;
in += lineWidth;
in += linepad;
}
}
//! Resizes the surface to a new size and converts it at the same time
//! to an A8R8G8B8 format, returning the pointer to the new buffer.
void CColorConverter::convert16bitToA8R8G8B8andResize(const s16* in, s32* out, s32 newWidth, s32 newHeight, s32 currentWidth, s32 currentHeight)
{
if (!newWidth || !newHeight)
return;
// note: this is very very slow. (i didn't want to write a fast version.
// but hopefully, nobody wants to convert surfaces every frame.
f32 sourceXStep = (f32)currentWidth / (f32)newWidth;
f32 sourceYStep = (f32)currentHeight / (f32)newHeight;
f32 sy;
s32 t;
for (s32 x=0; x<newWidth; ++x)
{
sy = 0.0f;
for (s32 y=0; y<newHeight; ++y)
{
t = in[(s32)(((s32)sy)*currentWidth + x*sourceXStep)];
t = (((t >> 15)&0x1)<<31) | (((t >> 10)&0x1F)<<19) |
(((t >> 5)&0x1F)<<11) | (t&0x1F)<<3;
out[(s32)(y*newWidth + x)] = t;
sy+=sourceYStep;
}
}
}
//! copies X8R8G8B8 32 bit data
void CColorConverter::convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width;
#ifdef __BIG_ENDIAN__
for (s32 x=0; x<width; ++x)
out[x]=os::Byteswap::byteswap(in[x]);
#else
memcpy(out, in, width*sizeof(s32));
#endif
if (!flip)
out += width;
in += width;
in += linepad;
}
}
void CColorConverter::convert_A1R5G5B5toR8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = (*sB & 0x7c00) >> 7;
dB[1] = (*sB & 0x03e0) >> 2;
dB[0] = (*sB & 0x1f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = (*sB & 0x7c00) >> 7;
dB[1] = (*sB & 0x03e0) >> 2;
dB[2] = (*sB & 0x1f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP)
{
const u16* sB = (const u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = (*sB<<1)|(*sB>>15);
++sB; ++dB;
}
}
void CColorConverter::convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A1R5G5B5toA8R8G8B8(*sB++);
}
void CColorConverter::convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 2);
}
void CColorConverter::convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A1R5G5B5toR5G6B5(*sB++);
}
void CColorConverter::convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
// sB[3] is alpha
dB[0] = sB[2];
dB[1] = sB[1];
dB[2] = sB[0];
sB += 4;
dB += 3;
}
}
void CColorConverter::convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
// sB[3] is alpha
dB[0] = sB[0];
dB[1] = sB[1];
dB[2] = sB[2];
sB += 4;
dB += 3;
}
}
void CColorConverter::convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 4);
}
void CColorConverter::convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u32* sB = (u32*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A8R8G8B8toA1R5G5B5(*sB++);
}
void CColorConverter::convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[2] >> 3;
s32 g = sB[1] >> 2;
s32 b = sB[0] >> 3;
dB[0] = (r << 11) | (g << 5) | (b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
u8 r = sB[2] & 0xe0;
u8 g = (sB[1] & 0xe0) >> 3;
u8 b = (sB[0] & 0xc0) >> 6;
dB[0] = (r | g | b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 3);
}
void CColorConverter::convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8* )sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = 0xff000000 | (sB[0]<<16) | (sB[1]<<8) | sB[2];
sB += 3;
++dB;
}
}
void CColorConverter::convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[0] >> 3;
s32 g = sB[1] >> 3;
s32 b = sB[2] >> 3;
dB[0] = (0x8000) | (r << 10) | (g << 5) | (b);
sB += 3;
dB += 1;
}
}
void CColorConverter::convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8* )sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = 0xff000000 | (sB[2]<<16) | (sB[1]<<8) | sB[0];
sB += 3;
++dB;
}
}
void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP)
{
const u32* sB = (const u32*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB++ = (*sB<<8) | (*sB>>24);
++sB;
}
}
void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP)
{
const u32* sB = (const u32*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB++ = (*sB&0xff00ff00)|((*sB&0x00ff0000)>>16)|((*sB&0x000000ff)<<16);
++sB;
}
}
void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = sB[3];
dB[1] = sB[2];
dB[2] = sB[1];
dB[3] = sB[0];
sB += 4;
dB += 4;
}
}
void CColorConverter::convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = sB[0];
dB[1] = sB[1];
dB[0] = sB[2];
sB += 3;
dB += 3;
}
}
void CColorConverter::convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[0] >> 3;
s32 g = sB[1] >> 2;
s32 b = sB[2] >> 3;
dB[0] = (r << 11) | (g << 5) | (b);
sB += 3;
dB += 1;
}
}
void CColorConverter::convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 2);
}
void CColorConverter::convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = (*sB & 0xf800) >> 8;
dB[1] = (*sB & 0x07e0) >> 3;
dB[2] = (*sB & 0x001f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = (*sB & 0xf800) >> 8;
dB[1] = (*sB & 0x07e0) >> 3;
dB[0] = (*sB & 0x001f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = R5G6B5toA8R8G8B8(*sB++);
}
void CColorConverter::convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = R5G6B5toA1R5G5B5(*sB++);
}
void CColorConverter::convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN,
void* dP, ECOLOR_FORMAT dF)
{
switch (sF)
{
case ECF_A1R5G5B5:
switch (dF)
{
case ECF_A1R5G5B5:
convert_A1R5G5B5toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_A1R5G5B5toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_A1R5G5B5toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_A1R5G5B5toR8G8B8(sP, sN, dP);
break;
#ifndef _DEBUG
default:
break;
#endif
}
break;
case ECF_R5G6B5:
switch (dF)
{
case ECF_A1R5G5B5:
convert_R5G6B5toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_R5G6B5toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_R5G6B5toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_R5G6B5toR8G8B8(sP, sN, dP);
break;
#ifndef _DEBUG
default:
break;
#endif
}
break;
case ECF_A8R8G8B8:
switch (dF)
{
case ECF_A1R5G5B5:
convert_A8R8G8B8toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_A8R8G8B8toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_A8R8G8B8toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_A8R8G8B8toR8G8B8(sP, sN, dP);
break;
#ifndef _DEBUG
default:
break;
#endif
}
break;
case ECF_R8G8B8:
switch (dF)
{
case ECF_A1R5G5B5:
convert_R8G8B8toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_R8G8B8toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_R8G8B8toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_R8G8B8toR8G8B8(sP, sN, dP);
break;
#ifndef _DEBUG
default:
break;
#endif
}
break;
default:
break;
}
}
} // end namespace video
} // end namespace irr
@@ -0,0 +1,96 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_COLOR_CONVERTER_H_INCLUDED__
#define __C_COLOR_CONVERTER_H_INCLUDED__
#include "irrTypes.h"
#include "IImage.h"
namespace irr
{
namespace video
{
class CColorConverter
{
public:
//! converts a monochrome bitmap to A1R5G5B5
static void convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false);
//! converts a 4 bit palettized image to A1R5G5B5
static void convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false);
//! converts a 8 bit palettized image to A1R5G5B5
static void convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
static void convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8
static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts R8G8B8 16 bit data to A1R5G5B5 data
static void convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false);
//! copies R8G8B8 24 bit data to 24 data, and flips and
//! mirrors the image during the process.
static void convert24BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, s32 linepad=0, bool flip=false, bool bgr=false);
//! Resizes the surface to a new size and converts it at the same time
//! to an A8R8G8B8 format, returning the pointer to the new buffer.
static void convert16bitToA8R8G8B8andResize(const s16* in, s32* out, s32 newWidth, s32 newHeight, s32 currentWidth, s32 currentHeight);
//! copies X8R8G8B8 32 bit data, and flips and
//! mirrors the image during the process.
static void convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip=false);
//! functions for converting one image format to another efficiently
//! and hopefully correctly.
//!
//! \param sP pointer to source pixel data
//! \param sN number of source pixels to copy
//! \param dP pointer to destination data buffer. must be big enough
//! to hold sN pixels in the output format.
static void convert_A1R5G5B5toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN,
void* dP, ECOLOR_FORMAT dF);
};
} // end namespace video
} // end namespace irr
#endif
@@ -0,0 +1,684 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016-2017 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "IrrCompileConfig.h"
#if defined(_IRR_COMPILE_WITH_EGL_)
#include <cassert>
#include <cstdio>
#include <cstring>
#include <vector>
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include "stk_android_native_app_glue.h"
#endif
#include "CContextEGL.h"
#include "os.h"
using namespace irr;
ContextManagerEGL::ContextManagerEGL()
{
m_egl_window = 0;
m_egl_display = EGL_NO_DISPLAY;
m_egl_surface = EGL_NO_SURFACE;
m_egl_context = EGL_NO_CONTEXT;
m_egl_config = 0;
m_egl_version = 0;
m_is_legacy_device = false;
m_initialized = false;
eglGetPlatformDisplay = NULL;
memset(&m_creation_params, 0, sizeof(ContextEGLParams));
}
ContextManagerEGL::~ContextManagerEGL()
{
close();
}
bool ContextManagerEGL::init(const ContextEGLParams& params)
{
if (m_initialized)
return false;
m_creation_params = params;
m_egl_window = m_creation_params.window;
bool success = initExtensions();
if (!success)
{
os::Printer::log("Error: Could not initialize EGL extensions.\n");
close();
return false;
}
success = initDisplay();
if (!success)
{
os::Printer::log("Error: Could not initialize EGL display.\n");
close();
return false;
}
bool has_minimum_requirements = false;
if (m_creation_params.opengl_api == CEGL_API_OPENGL)
{
if (hasEGLExtension("EGL_KHR_create_context") || m_egl_version >= 150)
{
has_minimum_requirements = true;
eglBindAPI(EGL_OPENGL_API);
}
}
else if (m_creation_params.opengl_api == CEGL_API_OPENGL_ES)
{
if (m_egl_version >= 130)
{
has_minimum_requirements = true;
eglBindAPI(EGL_OPENGL_ES_API);
}
}
if (!has_minimum_requirements)
{
os::Printer::log("Error: EGL version is too old.\n");
close();
return false;
}
success = chooseConfig();
if (!success)
{
os::Printer::log("Error: Couldn't get EGL config.\n");
close();
return false;
}
success = createSurface();
if (!success)
{
os::Printer::log("Error: Couldn't create EGL surface.\n");
close();
return false;
}
success = createContext();
if (!success)
{
os::Printer::log("Error: Couldn't create OpenGL context.\n");
close();
return false;
}
success = eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface,
m_egl_context);
if (!success)
{
checkEGLError();
os::Printer::log("Error: Couldn't make context current for EGL display.\n");
close();
return false;
}
eglSwapInterval(m_egl_display, m_creation_params.swap_interval);
m_initialized = true;
return true;
}
bool ContextManagerEGL::initExtensions()
{
if (hasEGLExtension("EGL_KHR_platform_base"))
{
eglGetPlatformDisplay = (eglGetPlatformDisplay_t)
eglGetProcAddress("eglGetPlatformDisplay");
}
else if (hasEGLExtension("EGL_EXT_platform_base"))
{
eglGetPlatformDisplay = (eglGetPlatformDisplay_t)
eglGetProcAddress("eglGetPlatformDisplayEXT");
}
return true;
}
bool ContextManagerEGL::initDisplay()
{
EGLNativeDisplayType display = m_creation_params.display;
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
display = EGL_DEFAULT_DISPLAY;
#endif
EGLenum platform = 0;
switch (m_creation_params.platform)
{
case CEGL_PLATFORM_ANDROID:
platform = EGL_PLATFORM_ANDROID;
break;
case CEGL_PLATFORM_GBM:
platform = EGL_PLATFORM_GBM;
break;
case CEGL_PLATFORM_WAYLAND:
platform = EGL_PLATFORM_WAYLAND;
break;
case CEGL_PLATFORM_X11:
platform = EGL_PLATFORM_X11;
break;
case CEGL_PLATFORM_DEFAULT:
break;
}
if (m_creation_params.platform != CEGL_PLATFORM_DEFAULT &&
eglGetPlatformDisplay != NULL)
{
m_egl_display = eglGetPlatformDisplay(platform, (void*)display, NULL);
}
if (m_egl_display == EGL_NO_DISPLAY)
{
m_egl_display = eglGetDisplay(display);
}
if (m_egl_display == EGL_NO_DISPLAY && display != EGL_DEFAULT_DISPLAY)
{
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
if (m_egl_display == EGL_NO_DISPLAY)
{
return false;
}
int egl_version_major = 0;
int egl_version_minor = 0;
bool success = eglInitialize(m_egl_display, &egl_version_major,
&egl_version_minor);
if (success)
{
m_egl_version = 100 * egl_version_major + 10 * egl_version_minor;
}
return success;
}
bool ContextManagerEGL::chooseConfig()
{
std::vector<EGLint> config_attribs;
config_attribs.push_back(EGL_RED_SIZE);
config_attribs.push_back(8);
config_attribs.push_back(EGL_GREEN_SIZE);
config_attribs.push_back(8);
config_attribs.push_back(EGL_BLUE_SIZE);
config_attribs.push_back(8);
config_attribs.push_back(EGL_ALPHA_SIZE);
config_attribs.push_back(m_creation_params.with_alpha_channel ? 8 : 0);
config_attribs.push_back(EGL_DEPTH_SIZE);
config_attribs.push_back(16);
// config_attribs.push_back(EGL_BUFFER_SIZE);
// config_attribs.push_back(24);
// config_attribs.push_back(EGL_STENCIL_SIZE);
// config_attribs.push_back(stencil_buffer);
// config_attribs.push_back(EGL_SAMPLE_BUFFERS);
// config_attribs.push_back(antialias ? 1 : 0);
// config_attribs.push_back(EGL_SAMPLES);
// config_attribs.push_back(antialias);
if (m_creation_params.opengl_api == CEGL_API_OPENGL)
{
config_attribs.push_back(EGL_RENDERABLE_TYPE);
config_attribs.push_back(EGL_OPENGL_BIT);
}
else if (m_creation_params.opengl_api == CEGL_API_OPENGL_ES)
{
config_attribs.push_back(EGL_RENDERABLE_TYPE);
config_attribs.push_back(EGL_OPENGL_ES2_BIT);
}
if (m_creation_params.surface_type == CEGL_SURFACE_WINDOW)
{
config_attribs.push_back(EGL_SURFACE_TYPE);
config_attribs.push_back(EGL_WINDOW_BIT);
}
else if (m_creation_params.surface_type == CEGL_SURFACE_PBUFFER)
{
config_attribs.push_back(EGL_SURFACE_TYPE);
config_attribs.push_back(EGL_PBUFFER_BIT);
}
config_attribs.push_back(EGL_NONE);
config_attribs.push_back(0);
EGLint num_configs = 0;
bool success = eglChooseConfig(m_egl_display, &config_attribs[0],
&m_egl_config, 1, &num_configs);
if (!success || m_egl_config == NULL || num_configs < 1)
{
config_attribs[1] = 5; //EGL_RED_SIZE
config_attribs[3] = 6; //EGL_GREEN_SIZE
config_attribs[5] = 5; //EGL_BLUE_SIZE
config_attribs[7] = 0; //EGL_ALPHA_SIZE
config_attribs[9] = 1; //EGL_DEPTH_SIZE
success = eglChooseConfig(m_egl_display, &config_attribs[0],
&m_egl_config, 1, &num_configs);
}
if (!success || m_egl_config == NULL || num_configs < 1)
{
return false;
}
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
EGLint format = 0;
eglGetConfigAttrib(m_egl_display, m_egl_config, EGL_NATIVE_VISUAL_ID,
&format);
ANativeWindow_setBuffersGeometry(m_egl_window, 0, 0, format);
#endif
return true;
}
bool ContextManagerEGL::createSurface()
{
unsigned int colorspace_attr_pos = 0;
unsigned int largest_pbuffer_attr_pos = 0;
std::vector<EGLint> attribs;
if (m_creation_params.opengl_api == CEGL_API_OPENGL &&
m_creation_params.handle_srgb == true)
{
if (hasEGLExtension("EGL_KHR_gl_colorspace") || m_egl_version >= 150)
{
attribs.push_back(EGL_GL_COLORSPACE);
attribs.push_back(EGL_GL_COLORSPACE_SRGB);
colorspace_attr_pos = attribs.size() - 1;
}
}
if (m_creation_params.surface_type == CEGL_SURFACE_PBUFFER)
{
attribs.push_back(EGL_WIDTH);
attribs.push_back(m_creation_params.pbuffer_width);
attribs.push_back(EGL_HEIGHT);
attribs.push_back(m_creation_params.pbuffer_height);
attribs.push_back(EGL_LARGEST_PBUFFER);
attribs.push_back(EGL_FALSE);
largest_pbuffer_attr_pos = attribs.size() - 1;
}
attribs.push_back(EGL_NONE);
attribs.push_back(0);
if (m_egl_surface == EGL_NO_SURFACE)
{
if (m_creation_params.surface_type == CEGL_SURFACE_WINDOW)
{
m_egl_surface = eglCreateWindowSurface(m_egl_display, m_egl_config,
m_egl_window, &attribs[0]);
}
else if (m_creation_params.surface_type == CEGL_SURFACE_PBUFFER)
{
m_egl_surface = eglCreatePbufferSurface(m_egl_display, m_egl_config,
&attribs[0]);
}
}
if (m_egl_surface == EGL_NO_SURFACE && colorspace_attr_pos > 0)
{
attribs[colorspace_attr_pos] = EGL_GL_COLORSPACE_LINEAR;
if (m_creation_params.surface_type == CEGL_SURFACE_WINDOW)
{
m_egl_surface = eglCreateWindowSurface(m_egl_display, m_egl_config,
m_egl_window, &attribs[0]);
}
else if (m_creation_params.surface_type == CEGL_SURFACE_PBUFFER)
{
m_egl_surface = eglCreatePbufferSurface(m_egl_display, m_egl_config,
&attribs[0]);
}
}
if (m_egl_surface == EGL_NO_SURFACE && largest_pbuffer_attr_pos > 0)
{
attribs[largest_pbuffer_attr_pos] = EGL_TRUE;
if (m_creation_params.surface_type == CEGL_SURFACE_PBUFFER)
{
m_egl_surface = eglCreatePbufferSurface(m_egl_display, m_egl_config,
&attribs[0]);
}
}
return m_egl_surface != EGL_NO_SURFACE;
}
bool ContextManagerEGL::createContext()
{
m_is_legacy_device = false;
if (m_creation_params.opengl_api == CEGL_API_OPENGL_ES)
{
if (!m_creation_params.force_legacy_device)
{
if (m_egl_context == EGL_NO_CONTEXT)
{
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_CLIENT_VERSION);
context_attribs.push_back(3);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
}
if (m_egl_context == EGL_NO_CONTEXT)
{
m_is_legacy_device = true;
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_CLIENT_VERSION);
context_attribs.push_back(2);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
}
else if (m_creation_params.opengl_api == CEGL_API_OPENGL)
{
if (!m_creation_params.force_legacy_device)
{
if (m_egl_context == EGL_NO_CONTEXT)
{
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION);
context_attribs.push_back(4);
context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION);
context_attribs.push_back(3);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
if (m_egl_context == EGL_NO_CONTEXT)
{
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION);
context_attribs.push_back(3);
context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION);
context_attribs.push_back(3);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
if (m_egl_context == EGL_NO_CONTEXT)
{
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION);
context_attribs.push_back(3);
context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION);
context_attribs.push_back(1);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
}
if (m_egl_context == EGL_NO_CONTEXT)
{
m_is_legacy_device = true;
std::vector<EGLint> context_attribs;
context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION);
context_attribs.push_back(2);
context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION);
context_attribs.push_back(1);
context_attribs.push_back(EGL_NONE);
context_attribs.push_back(0);
m_egl_context = eglCreateContext(m_egl_display,
m_egl_config,
EGL_NO_CONTEXT,
&context_attribs[0]);
}
}
return m_egl_context != EGL_NO_CONTEXT;
}
void ContextManagerEGL::close()
{
if (m_egl_display != EGL_NO_DISPLAY)
{
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
if (m_egl_context != EGL_NO_CONTEXT)
{
eglDestroyContext(m_egl_display, m_egl_context);
m_egl_context = EGL_NO_CONTEXT;
}
if (m_egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_egl_display, m_egl_surface);
m_egl_surface = EGL_NO_SURFACE;
}
if (m_egl_display != EGL_NO_DISPLAY)
{
eglTerminate(m_egl_display);
m_egl_display = EGL_NO_DISPLAY;
}
eglReleaseThread();
}
bool ContextManagerEGL::swapBuffers()
{
bool success = eglSwapBuffers(m_egl_display, m_egl_surface);
#ifdef DEBUG
if (!success)
{
eglGetError();
}
#endif
return success;
}
bool ContextManagerEGL::makeCurrent()
{
bool success = eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface,
m_egl_context);
return success;
}
void ContextManagerEGL::reloadEGLSurface(void* window)
{
if (!m_initialized)
return;
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
m_egl_window = (ANativeWindow*)window;
if (!m_egl_window)
{
os::Printer::log("Error: Invalid EGL window.\n");
}
#endif
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglDestroySurface(m_egl_display, m_egl_surface);
m_egl_surface = EGL_NO_SURFACE;
bool success = createSurface();
if (!success)
{
os::Printer::log("Error: Could not create EGL surface.");
}
success = eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface,
m_egl_context);
if (!success)
{
checkEGLError();
os::Printer::log("Error: Couldn't make context current for EGL display.\n");
}
}
bool ContextManagerEGL::getSurfaceDimensions(int* width, int* height)
{
if (!eglQuerySurface(m_egl_display, m_egl_surface, EGL_WIDTH, width))
return false;
if (!eglQuerySurface(m_egl_display, m_egl_surface, EGL_HEIGHT, height))
return false;
return true;
}
bool ContextManagerEGL::hasEGLExtension(const char* extension)
{
const char* extensions = eglQueryString(m_egl_display, EGL_EXTENSIONS);
if (extensions && strstr(extensions, extension) != NULL)
{
return true;
}
return false;
}
bool ContextManagerEGL::checkEGLError()
{
bool result = true;
switch (eglGetError())
{
case EGL_SUCCESS:
result = false;
break;
case EGL_NOT_INITIALIZED:
os::Printer::log("Error: EGL_NOT_INITIALIZED\n");
break;
case EGL_BAD_ACCESS:
os::Printer::log("Error: EGL_BAD_ACCESS\n");
break;
case EGL_BAD_ALLOC:
os::Printer::log("Error: EGL_BAD_ALLOC\n");
break;
case EGL_BAD_ATTRIBUTE:
os::Printer::log("Error: EGL_BAD_ATTRIBUTE\n");
break;
case EGL_BAD_CONTEXT:
os::Printer::log("Error: EGL_BAD_CONTEXT\n");
break;
case EGL_BAD_CONFIG:
os::Printer::log("Error: EGL_BAD_CONFIG\n");
break;
case EGL_BAD_CURRENT_SURFACE:
os::Printer::log("Error: EGL_BAD_CURRENT_SURFACE\n");
break;
case EGL_BAD_DISPLAY:
os::Printer::log("Error: EGL_BAD_DISPLAY\n");
break;
case EGL_BAD_SURFACE:
os::Printer::log("Error: EGL_BAD_SURFACE\n");
break;
case EGL_BAD_MATCH:
os::Printer::log("Error: EGL_BAD_MATCH\n");
break;
case EGL_BAD_PARAMETER:
os::Printer::log("Error: EGL_BAD_PARAMETER\n");
break;
case EGL_BAD_NATIVE_PIXMAP:
os::Printer::log("Error: EGL_BAD_NATIVE_PIXMAP\n");
break;
case EGL_BAD_NATIVE_WINDOW:
os::Printer::log("Error: EGL_BAD_NATIVE_WINDOW\n");
break;
case EGL_CONTEXT_LOST:
os::Printer::log("Error: EGL_CONTEXT_LOST\n");
break;
default:
os::Printer::log("Error: Unknown EGL error.\n");
break;
};
return result;
}
#endif
+133
View File
@@ -0,0 +1,133 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016-2017 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef CONTEXT_EGL_HPP
#define CONTEXT_EGL_HPP
#include "IrrCompileConfig.h"
#if defined(_IRR_COMPILE_WITH_EGL_)
#include <EGL/egl.h>
#ifndef EGL_CONTEXT_MAJOR_VERSION
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
#endif
#ifndef EGL_CONTEXT_MINOR_VERSION
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
#endif
#ifndef EGL_GL_COLORSPACE
#define EGL_GL_COLORSPACE 0x309D
#endif
#ifndef EGL_GL_COLORSPACE_SRGB
#define EGL_GL_COLORSPACE_SRGB 0x3089
#endif
#ifndef EGL_GL_COLORSPACE_LINEAR
#define EGL_GL_COLORSPACE_LINEAR 0x308A
#endif
#ifndef EGL_PLATFORM_ANDROID
#define EGL_PLATFORM_ANDROID 0x3141
#endif
#ifndef EGL_PLATFORM_GBM
#define EGL_PLATFORM_GBM 0x31D7
#endif
#ifndef EGL_PLATFORM_WAYLAND
#define EGL_PLATFORM_WAYLAND 0x31D8
#endif
#ifndef EGL_PLATFORM_X11
#define EGL_PLATFORM_X11 0x31D5
#endif
enum ContextEGLOpenGLAPI
{
CEGL_API_OPENGL,
CEGL_API_OPENGL_ES
};
enum ContextEGLSurfaceType
{
CEGL_SURFACE_WINDOW,
CEGL_SURFACE_PBUFFER
};
enum ContextEGLPlatform
{
CEGL_PLATFORM_ANDROID,
CEGL_PLATFORM_GBM,
CEGL_PLATFORM_WAYLAND,
CEGL_PLATFORM_X11,
CEGL_PLATFORM_DEFAULT
};
struct ContextEGLParams
{
ContextEGLOpenGLAPI opengl_api;
ContextEGLSurfaceType surface_type;
ContextEGLPlatform platform;
EGLNativeWindowType window;
EGLNativeDisplayType display;
bool force_legacy_device;
bool handle_srgb;
bool with_alpha_channel;
int swap_interval;
int pbuffer_width;
int pbuffer_height;
};
class ContextManagerEGL
{
private:
EGLNativeWindowType m_egl_window;
EGLDisplay m_egl_display;
EGLSurface m_egl_surface;
EGLContext m_egl_context;
EGLConfig m_egl_config;
ContextEGLParams m_creation_params;
bool m_is_legacy_device;
bool m_initialized;
int m_egl_version;
typedef EGLDisplay (*eglGetPlatformDisplay_t) (EGLenum, void*, const EGLint*);
eglGetPlatformDisplay_t eglGetPlatformDisplay;
bool initExtensions();
bool initDisplay();
bool chooseConfig();
bool createSurface();
bool createContext();
bool hasEGLExtension(const char* extension);
bool checkEGLError();
public:
ContextManagerEGL();
~ContextManagerEGL();
bool init(const ContextEGLParams& params);
void close();
void reloadEGLSurface(void* window);
bool swapBuffers();
bool makeCurrent();
bool isLegacyDevice() {return m_is_legacy_device;}
bool getSurfaceDimensions(int* width, int* height);
};
#endif
#endif
@@ -0,0 +1,201 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CCubeSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include "os.h"
namespace irr
{
namespace scene
{
/*
011 111
/6,8------/5 y
/ | / | ^ z
/ | / | | /
010 3,9-------2 | |/
| 7- - -10,4 101 *---->x
| / | /
|/ | /
0------11,1/
000 100
*/
//! constructor
CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
s32 id, const core::vector3df& position,
const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale),
Mesh(0), Size(size)
{
#ifdef _DEBUG
setDebugName("CCubeSceneNode");
#endif
setSize();
}
CCubeSceneNode::~CCubeSceneNode()
{
if (Mesh)
Mesh->drop();
}
void CCubeSceneNode::setSize()
{
if (Mesh)
Mesh->drop();
Mesh = SceneManager->getGeometryCreator()->createCubeMesh(core::vector3df(Size));
}
//! renders the node.
void CCubeSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
// for debug purposes only:
video::SMaterial mat = Mesh->getMeshBuffer(0)->getMaterial();
// overwrite half transparency
if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)
mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
driver->setMaterial(mat);
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
// for debug purposes only:
if (DebugDataVisible)
{
video::SMaterial m;
m.Lighting = false;
m.AntiAliasing=0;
driver->setMaterial(m);
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), video::SColor(255,255,255,255));
}
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
{
driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(),
video::SColor(255,190,128,128));
}
if (DebugDataVisible & scene::EDS_NORMALS)
{
// draw normals
const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
const u32 count = Mesh->getMeshBufferCount();
for (u32 i=0; i != count; ++i)
{
driver->drawMeshBufferNormals(Mesh->getMeshBuffer(i), debugNormalLength, debugNormalColor);
}
}
// show mesh
if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
{
m.Wireframe = true;
driver->setMaterial(m);
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
}
}
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CCubeSceneNode::getBoundingBox() const
{
return Mesh->getMeshBuffer(0)->getBoundingBox();
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CCubeSceneNode::removeChild(ISceneNode* child)
{
return ISceneNode::removeChild(child);
}
void CCubeSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! returns the material based on the zero based index i.
video::SMaterial& CCubeSceneNode::getMaterial(u32 i)
{
return Mesh->getMeshBuffer(0)->getMaterial();
}
//! returns amount of materials used by this scene node.
u32 CCubeSceneNode::getMaterialCount() const
{
return 1;
}
//! Writes attributes of the scene node.
void CCubeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
out->addFloat("Size", Size);
}
//! Reads attributes of the scene node.
void CCubeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
f32 newSize = in->getAttributeAsFloat("Size");
newSize = core::max_(newSize, 0.0001f);
if (newSize != Size)
{
Size = newSize;
setSize();
}
ISceneNode::deserializeAttributes(in, options);
}
//! Creates a clone of this scene node and its children.
ISceneNode* CCubeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CCubeSceneNode* nb = new CCubeSceneNode(Size, newParent,
newManager, ID, RelativeTranslation);
nb->cloneMembers(this, newManager);
nb->getMaterial(0) = getMaterial(0);
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,87 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_CUBE_SCENE_NODE_H_INCLUDED__
#define __C_CUBE_SCENE_NODE_H_INCLUDED__
#include "IMeshSceneNode.h"
#include "SMesh.h"
namespace irr
{
namespace scene
{
class CCubeSceneNode : public IMeshSceneNode
{
public:
//! constructor
CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));
virtual ~CCubeSceneNode();
virtual void OnRegisterSceneNode();
//! renders the node.
virtual void render();
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hirachy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
virtual video::SMaterial& getMaterial(u32 i);
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_CUBE; }
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
//! Sets a new mesh to display
virtual void setMesh(IMesh* mesh) {}
//! Returns the current mesh
virtual IMesh* getMesh(void) { return Mesh; }
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
virtual void setReadOnlyMaterials(bool readonly) {}
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const { return false; }
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
private:
void setSize();
IMesh* Mesh;
f32 Size;
};
} // end namespace scene
} // end namespace irr
#endif
File diff suppressed because it is too large Load Diff
+499
View File
@@ -0,0 +1,499 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_VIDEO_DIRECTX_9_H_INCLUDED__
#define __C_VIDEO_DIRECTX_9_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#ifdef _IRR_WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "CNullDriver.h"
#include "SIrrCreationParameters.h"
#include "IMaterialRendererServices.h"
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#ifdef _IRR_COMPILE_WITH_CG_
#include "Cg/cg.h"
#include "Cg/cgD3D9.h"
#endif
namespace irr
{
namespace video
{
struct SDepthSurface : public IReferenceCounted
{
SDepthSurface() : Surface(0)
{
#ifdef _DEBUG
setDebugName("SDepthSurface");
#endif
}
virtual ~SDepthSurface()
{
if (Surface)
Surface->Release();
}
IDirect3DSurface9* Surface;
core::dimension2du Size;
};
class CD3D9Driver : public CNullDriver, IMaterialRendererServices
{
public:
friend class CD3D9Texture;
//! constructor
CD3D9Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io);
//! destructor
virtual ~CD3D9Driver();
//! applications must call this method before performing any rendering. returns false if failed.
virtual bool beginScene(bool backBuffer=true, bool zBuffer=true,
SColor color=SColor(255,0,0,0),
const SExposedVideoData& videoData=SExposedVideoData(),
core::rect<s32>* sourceRect=0);
//! applications must call this method after performing any rendering. returns false if failed.
virtual bool endScene();
//! queries the features of the driver, returns true if feature is available
virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const;
//! sets transformation
virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat);
//! sets a material
virtual void setMaterial(const SMaterial& material);
//! sets a render target
virtual bool setRenderTarget(video::ITexture* texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0));
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0));
//! sets a viewport
virtual void setViewPort(const core::rect<s32>& area);
//! gets the area of the current viewport
virtual const core::rect<s32>& getViewPort() const;
struct SHWBufferLink_d3d9 : public SHWBufferLink
{
SHWBufferLink_d3d9(const scene::IMeshBuffer *_MeshBuffer):
SHWBufferLink(_MeshBuffer),
vertexBuffer(0), indexBuffer(0),
vertexBufferSize(0), indexBufferSize(0) {}
IDirect3DVertexBuffer9* vertexBuffer;
IDirect3DIndexBuffer9* indexBuffer;
u32 vertexBufferSize;
u32 indexBufferSize;
};
bool updateVertexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer);
bool updateIndexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer);
//! updates hardware buffer if needed
virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer);
//! Create hardware buffer from mesh
virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb);
//! Delete hardware buffer (only some drivers can)
virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer);
//! Draw hardware buffer
virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer);
//! Create occlusion query.
/** Use node for identification and mesh for occlusion test. */
virtual void addOcclusionQuery(scene::ISceneNode* node,
const scene::IMesh* mesh=0);
//! Remove occlusion query.
virtual void removeOcclusionQuery(scene::ISceneNode* node);
//! Run occlusion query. Draws mesh stored in query.
/** If the mesh shall not be rendered visible, use
overrideMaterial to disable the color and depth buffer. */
virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false);
//! Update occlusion query. Retrieves results from GPU.
/** If the query shall not block, set the flag to false.
Update might not occur in this case, though */
virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true);
//! Return query result.
/** Return value is the number of visible pixels/fragments.
The value is a safe approximation, i.e. can be larger then the
actual value of pixels. */
virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const;
//! draws a vertex primitive list
virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType);
//! draws a vertex primitive list in 2d
virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType);
//! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
virtual void draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false);
//! Draws a part of the texture into the rectangle.
virtual void draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false);
//! Draws a set of 2d images, using a color and the alpha channel of the texture.
virtual void draw2DImageBatch(const video::ITexture* texture,
const core::array<core::position2d<s32> >& positions,
const core::array<core::rect<s32> >& sourceRects,
const core::rect<s32>* clipRect=0,
SColor color=SColor(255,255,255,255),
bool useAlphaChannelOfTexture=false);
//!Draws an 2d rectangle with a gradient.
virtual void draw2DRectangle(const core::rect<s32>& pos,
SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
const core::rect<s32>* clip);
//! Draws a 2d line.
virtual void draw2DLine(const core::position2d<s32>& start,
const core::position2d<s32>& end,
SColor color=SColor(255,255,255,255));
//! Draws a pixel.
virtual void drawPixel(u32 x, u32 y, const SColor & color);
//! Draws a 3d line.
virtual void draw3DLine(const core::vector3df& start,
const core::vector3df& end, SColor color = SColor(255,255,255,255));
//! initialises the Direct3D API
bool initDriver(HWND hwnd, bool pureSoftware);
//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
//! driver, it would return "Direct3D8.1".
virtual const wchar_t* getName() const;
//! deletes all dynamic lights there are
virtual void deleteAllDynamicLights();
//! adds a dynamic light, returning an index to the light
//! \param light: the light data to use to create the light
//! \return An index to the light, or -1 if an error occurs
virtual s32 addDynamicLight(const SLight& light);
//! Turns a dynamic light on or off
//! \param lightIndex: the index returned by addDynamicLight
//! \param turnOn: true to turn the light on, false to turn it off
virtual void turnLightOn(s32 lightIndex, bool turnOn);
//! returns the maximal amount of dynamic lights the device can handle
virtual u32 getMaximalDynamicLightAmount() const;
//! Sets the dynamic ambient light color. The default color is
//! (0,0,0,0) which means it is dark.
//! \param color: New color of the ambient light.
virtual void setAmbientLight(const SColorf& color);
//! Draws a shadow volume into the stencil buffer.
virtual void drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail=true, u32 debugDataVisible=0);
//! Fills the stencil shadow with color.
virtual void drawStencilShadow(bool clearStencilBuffer=false,
video::SColor leftUpEdge = video::SColor(0,0,0,0),
video::SColor rightUpEdge = video::SColor(0,0,0,0),
video::SColor leftDownEdge = video::SColor(0,0,0,0),
video::SColor rightDownEdge = video::SColor(0,0,0,0));
//! Returns the maximum amount of primitives (mostly vertices) which
//! the device is able to render with one drawIndexedTriangleList
//! call.
virtual u32 getMaximalPrimitiveCount() const;
//! Enables or disables a texture creation flag.
virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled);
//! Sets the fog mode.
virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start,
f32 end, f32 density, bool pixelFog, bool rangeFog);
//! Only used by the internal engine. Used to notify the driver that
//! the window was resized.
virtual void OnResize(const core::dimension2d<u32>& size);
//! Can be called by an IMaterialRenderer to make its work easier.
virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates);
//! Returns type of video driver
virtual E_DRIVER_TYPE getDriverType() const;
//! Returns the transformation set by setTransform
virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const;
//! Sets a vertex shader constant.
virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1);
//! Sets a pixel shader constant.
virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1);
//! Sets a constant for the vertex shader based on a name.
virtual bool setVertexShaderConstant(const c8* name, const f32* floats, int count);
//! Bool interface for the above.
virtual bool setVertexShaderConstant(const c8* name, const bool* bools, int count);
//! Int interface for the above.
virtual bool setVertexShaderConstant(const c8* name, const s32* ints, int count);
//! Sets a constant for the pixel shader based on a name.
virtual bool setPixelShaderConstant(const c8* name, const f32* floats, int count);
//! Bool interface for the above.
virtual bool setPixelShaderConstant(const c8* name, const bool* bools, int count);
//! Int interface for the above.
virtual bool setPixelShaderConstant(const c8* name, const s32* ints, int count);
//! Returns a pointer to the IVideoDriver interface. (Implementation for
//! IMaterialRendererServices)
virtual IVideoDriver* getVideoDriver();
//! Creates a render target texture.
virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN, const bool useStencil = false);
//! Clears the ZBuffer.
virtual void clearZBuffer();
//! Returns an image created from the last rendered frame.
virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER);
//! Set/unset a clipping plane.
virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false);
//! Enable/disable a clipping plane.
virtual void enableClipPlane(u32 index, bool enable);
//! Returns the graphics card vendor name.
virtual core::stringc getVendorInfo() {return VendorName;}
//! Enable the 2d override material
virtual void enableMaterial2D(bool enable=true);
//! Check if the driver was recently reset.
virtual bool checkDriverReset() {return DriverWasReset;}
// removes the depth struct from the DepthSurface array
void removeDepthSurface(SDepthSurface* depth);
//! Get the current color format of the color buffer
/** \return Color format of the color buffer. */
virtual ECOLOR_FORMAT getColorFormat() const;
//! Returns the maximum texture size supported.
virtual core::dimension2du getMaxTextureSize() const;
//! Get the current color format of the color buffer
/** \return Color format of the color buffer as D3D color value. */
D3DFORMAT getD3DColorFormat() const;
//! Get D3D color format from Irrlicht color format.
D3DFORMAT getD3DFormatFromColorFormat(ECOLOR_FORMAT format) const;
//! Get Irrlicht color format from D3D color format.
ECOLOR_FORMAT getColorFormatFromD3DFormat(D3DFORMAT format) const;
//! Get Cg context
#ifdef _IRR_COMPILE_WITH_CG_
const CGcontext& getCgContext();
#endif
virtual void enableScissorTest(const core::rect<s32>& r);
virtual void disableScissorTest();
private:
//! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates.
enum E_RENDER_MODE
{
ERM_NONE = 0, // no render state has been set yet.
ERM_2D, // 2d drawing rendermode
ERM_3D, // 3d rendering mode
ERM_STENCIL_FILL, // stencil fill mode
ERM_SHADOW_VOLUME_ZFAIL, // stencil volume draw mode
ERM_SHADOW_VOLUME_ZPASS // stencil volume draw mode
};
//! sets right vertex shader
void setVertexShader(video::E_VERTEX_TYPE newType);
//! sets the needed renderstates
bool setRenderStates3DMode();
//! sets the needed renderstates
void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel);
//! sets the needed renderstates
void setRenderStatesStencilFillMode(bool alpha);
//! sets the needed renderstates
void setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible);
//! sets the current Texture
bool setActiveTexture(u32 stage, const video::ITexture* texture);
//! resets the device
bool reset();
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
//! returns the current size of the screen or rendertarget
virtual const core::dimension2d<u32>& getCurrentRenderTargetSize() const;
//! Check if a proper depth buffer for the RTT is available, otherwise create it.
void checkDepthBuffer(ITexture* tex);
//! Adds a new material renderer to the VideoDriver, using pixel and/or
//! vertex shaders to render geometry.
s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback,
E_MATERIAL_TYPE baseMaterial, s32 userData);
//! Adds a new material renderer to the VideoDriver, based on a high level shading
//! language.
virtual s32 addHighLevelShaderMaterial(
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
const c8* geometryShaderProgram,
const c8* geometryShaderEntryPointName = "main",
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
u32 verticesOut = 0,
IShaderConstantSetCallBack* callback = 0,
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
s32 userData = 0,
E_GPU_SHADING_LANGUAGE shadingLang = EGSL_DEFAULT);
void createMaterialRenderers();
void draw2D3DVertexPrimitiveList(const void* vertices,
u32 vertexCount, const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType, bool is3D);
D3DTEXTUREADDRESS getTextureWrapMode(const u8 clamp);
inline D3DCOLORVALUE colorToD3D(const SColor& col)
{
const f32 f = 1.0f / 255.0f;
D3DCOLORVALUE v;
v.r = col.getRed() * f;
v.g = col.getGreen() * f;
v.b = col.getBlue() * f;
v.a = col.getAlpha() * f;
return v;
}
E_RENDER_MODE CurrentRenderMode;
D3DPRESENT_PARAMETERS present;
SMaterial Material, LastMaterial;
bool ResetRenderStates; // bool to make all renderstates be reseted if set.
bool Transformation3DChanged;
const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES];
bool LastTextureMipMapsAvailable[MATERIAL_MAX_TEXTURES];
core::matrix4 Matrices[ETS_COUNT]; // matrizes of the 3d mode we need to restore when we switch back from the 2d mode.
HINSTANCE D3DLibrary;
IDirect3D9* pID3D;
IDirect3DDevice9* pID3DDevice;
IDirect3DSurface9* PrevRenderTarget;
core::dimension2d<u32> CurrentRendertargetSize;
HWND WindowId;
core::rect<s32>* SceneSourceRect;
D3DCAPS9 Caps;
SIrrlichtCreationParameters Params;
E_VERTEX_TYPE LastVertexType;
SColorf AmbientLight;
core::stringc VendorName;
u16 VendorID;
core::array<SDepthSurface*> DepthBuffers;
u32 MaxTextureUnits;
u32 MaxUserClipPlanes;
u32 MaxMRTs;
u32 NumSetMRTs;
f32 MaxLightDistance;
s32 LastSetLight;
enum E_CACHE_2D_ATTRIBUTES
{
EC2D_ALPHA = 0x1,
EC2D_TEXTURE = 0x2,
EC2D_ALPHA_CHANNEL = 0x4
};
ECOLOR_FORMAT ColorFormat;
D3DFORMAT D3DColorFormat;
bool DeviceLost;
bool DriverWasReset;
bool OcclusionQuerySupport;
bool AlphaToCoverageSupport;
#ifdef _IRR_COMPILE_WITH_CG_
CGcontext CgContext;
#endif
};
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
#endif // __C_VIDEO_DIRECTX_9_H_INCLUDED__
@@ -0,0 +1,429 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#define _IRR_D3D_NO_SHADER_DEBUGGING 1
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9HLSLMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
#include "IVideoDriver.h"
#include "os.h"
#include "irrString.h"
#ifndef _IRR_D3D_NO_SHADER_DEBUGGING
#include <stdio.h>
#endif
namespace irr
{
namespace video
{
//! Public constructor
CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver, s32& outMaterialTypeNr,
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, callback, baseMaterial, userData),
VSConstantsTable(0), PSConstantsTable(0)
{
#ifdef _DEBUG
setDebugName("CD3D9HLSLMaterialRenderer");
#endif
outMaterialTypeNr = -1;
// now create shaders
if (vsCompileTarget < 0 || vsCompileTarget > EVST_COUNT)
{
os::Printer::log("Invalid HLSL vertex shader compilation target", ELL_ERROR);
return;
}
if (!createHLSLVertexShader(vertexShaderProgram,
vertexShaderEntryPointName, VERTEX_SHADER_TYPE_NAMES[vsCompileTarget]))
return;
if (!createHLSLPixelShader(pixelShaderProgram,
pixelShaderEntryPointName, PIXEL_SHADER_TYPE_NAMES[psCompileTarget]))
return;
// register myself as new material
outMaterialTypeNr = Driver->addMaterialRenderer(this);
}
//! Destructor
CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer()
{
if (VSConstantsTable)
VSConstantsTable->Release();
if (PSConstantsTable)
PSConstantsTable->Release();
}
bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName)
{
if (!vertexShaderProgram)
return true;
LPD3DXBUFFER buffer = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile without debug info
HRESULT h = stubD3DXCompileShader(
vertexShaderProgram,
strlen(vertexShaderProgram),
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
0, // no flags
&buffer,
&errors,
&VSConstantsTable);
#else
// compile shader and emitt some debug informations to
// make it possible to debug the shader in visual studio
static int irr_dbg_hlsl_file_nr = 0;
++irr_dbg_hlsl_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.vsh", irr_dbg_hlsl_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(vertexShaderProgram, strlen(vertexShaderProgram), 1, f);
fflush(f);
fclose(f);
HRESULT h = stubD3DXCompileShaderFromFile(
tmp,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
&buffer,
&errors,
&VSConstantsTable);
#endif
if (FAILED(h))
{
os::Printer::log("HLSL vertex shader compilation failed:", ELL_ERROR);
if (errors)
{
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
errors->Release();
if (buffer)
buffer->Release();
}
return false;
}
if (errors)
errors->Release();
if (buffer)
{
if (FAILED(pID3DDevice->CreateVertexShader((DWORD*)buffer->GetBufferPointer(),
&VertexShader)))
{
os::Printer::log("Could not create hlsl vertex shader.", ELL_ERROR);
buffer->Release();
return false;
}
buffer->Release();
return true;
}
return false;
}
bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName)
{
if (!pixelShaderProgram)
return true;
LPD3DXBUFFER buffer = 0;
LPD3DXBUFFER errors = 0;
DWORD flags = 0;
#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
if (Driver->queryFeature(video::EVDF_VERTEX_SHADER_2_0) || Driver->queryFeature(video::EVDF_VERTEX_SHADER_3_0))
// this one's for newer DX SDKs which don't support ps_1_x anymore
// instead they'll silently compile 1_x as 2_x when using this flag
flags |= D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY;
#endif
#if defined(_IRR_D3D_USE_LEGACY_HLSL_COMPILER) && defined(D3DXSHADER_USE_LEGACY_D3DX9_31_DLL)
#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
else
#endif
flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
#endif
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile without debug info
HRESULT h = stubD3DXCompileShader(
pixelShaderProgram,
strlen(pixelShaderProgram),
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
flags,
&buffer,
&errors,
&PSConstantsTable);
#else
// compile shader and emitt some debug informations to
// make it possible to debug the shader in visual studio
static int irr_dbg_hlsl_file_nr = 0;
++irr_dbg_hlsl_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.psh", irr_dbg_hlsl_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(pixelShaderProgram, strlen(pixelShaderProgram), 1, f);
fflush(f);
fclose(f);
HRESULT h = stubD3DXCompileShaderFromFile(
tmp,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
flags | D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
&buffer,
&errors,
&PSConstantsTable);
#endif
if (FAILED(h))
{
os::Printer::log("HLSL pixel shader compilation failed:", ELL_ERROR);
if (errors)
{
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
errors->Release();
if (buffer)
buffer->Release();
}
return false;
}
if (errors)
errors->Release();
if (buffer)
{
if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)buffer->GetBufferPointer(),
&PixelShader)))
{
os::Printer::log("Could not create hlsl pixel shader.", ELL_ERROR);
buffer->Release();
return false;
}
buffer->Release();
return true;
}
return false;
}
bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name,
const f32* floats, int count)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (!tbl)
return false;
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
D3DXHANDLE hndl = tbl->GetConstantByName(NULL, name);
if (!hndl)
{
core::stringc s = "HLSL Variable to set not found: '";
s += name;
s += "'. Available variables are:";
os::Printer::log(s.c_str(), ELL_WARNING);
printHLSLVariables(tbl);
return false;
}
D3DXCONSTANT_DESC Description;
UINT ucount = 1;
tbl->GetConstantDesc(hndl, &Description, &ucount);
if(Description.RegisterSet != D3DXRS_SAMPLER)
{
HRESULT hr = tbl->SetFloatArray(pID3DDevice, hndl, floats, count);
if (FAILED(hr))
{
os::Printer::log("Error setting float array for HLSL variable", ELL_WARNING);
return false;
}
}
return true;
}
bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name,
const bool* bools, int count)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (!tbl)
return false;
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
D3DXHANDLE hndl = tbl->GetConstantByName(NULL, name);
if (!hndl)
{
core::stringc s = "HLSL Variable to set not found: '";
s += name;
s += "'. Available variables are:";
os::Printer::log(s.c_str(), ELL_WARNING);
printHLSLVariables(tbl);
return false;
}
D3DXCONSTANT_DESC Description;
UINT ucount = 1;
tbl->GetConstantDesc(hndl, &Description, &ucount);
if(Description.RegisterSet != D3DXRS_SAMPLER)
{
HRESULT hr = tbl->SetBoolArray(pID3DDevice, hndl, (BOOL*)bools, count);
if (FAILED(hr))
{
os::Printer::log("Error setting bool array for HLSL variable", ELL_WARNING);
return false;
}
}
return true;
}
bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name,
const s32* ints, int count)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (!tbl)
return false;
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
D3DXHANDLE hndl = tbl->GetConstantByName(NULL, name);
if (!hndl)
{
core::stringc s = "HLSL Variable to set not found: '";
s += name;
s += "'. Available variables are:";
os::Printer::log(s.c_str(), ELL_WARNING);
printHLSLVariables(tbl);
return false;
}
D3DXCONSTANT_DESC Description;
UINT ucount = 1;
tbl->GetConstantDesc(hndl, &Description, &ucount);
if(Description.RegisterSet != D3DXRS_SAMPLER)
{
HRESULT hr = tbl->SetIntArray(pID3DDevice, hndl, ints, count);
if (FAILED(hr))
{
os::Printer::log("Error setting int array for HLSL variable", ELL_WARNING);
return false;
}
}
return true;
}
bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (VSConstantsTable)
VSConstantsTable->SetDefaults(pID3DDevice);
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table)
{
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
// print out constant names
D3DXCONSTANTTABLE_DESC tblDesc;
HRESULT hr = table->GetDesc(&tblDesc);
if (!FAILED(hr))
{
for (int i=0; i<(int)tblDesc.Constants; ++i)
{
D3DXCONSTANT_DESC d;
UINT n = 1;
D3DXHANDLE cHndl = table->GetConstant(NULL, i);
if (!FAILED(table->GetConstantDesc(cHndl, &d, &n)))
{
core::stringc s = " '";
s += d.Name;
s += "' Registers:[begin:";
s += (int)d.RegisterIndex;
s += ", count:";
s += (int)d.RegisterCount;
s += "]";
os::Printer::log(s.c_str());
}
}
}
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
@@ -0,0 +1,85 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9ShaderMaterialRenderer.h"
#include "IGPUProgrammingServices.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class IShaderConstantSetCallBack;
class IMaterialRenderer;
//! Class for using vertex and pixel shaders via HLSL with D3D9
class CD3D9HLSLMaterialRenderer : public CD3D9ShaderMaterialRenderer
{
public:
//! Public constructor
CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr,
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData);
//! Destructor
~CD3D9HLSLMaterialRenderer();
//! sets a variable in the shader.
//! \param vertexShader: True if this should be set in the vertex shader, false if
//! in the pixel shader.
//! \param name: Name of the variable
//! \param floats: Pointer to array of floats
//! \param count: Amount of floats in array.
virtual bool setVariable(bool vertexShader, const c8* name, const f32* floats, int count);
//! Bool interface for the above.
virtual bool setVariable(bool vertexShader, const c8* name, const bool* bools, int count);
//! Int interface for the above.
virtual bool setVariable(bool vertexShader, const c8* name, const s32* ints, int count);
bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype);
protected:
bool createHLSLVertexShader(const char* vertexShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName);
bool createHLSLPixelShader(const char* pixelShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName);
void printHLSLVariables(LPD3DXCONSTANTTABLE table);
LPD3DXCONSTANTTABLE VSConstantsTable;
LPD3DXCONSTANTTABLE PSConstantsTable;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif
@@ -0,0 +1,615 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "IMaterialRenderer.h"
namespace irr
{
namespace video
{
namespace
{
D3DMATRIX UnitMatrixD3D9;
D3DMATRIX SphereMapMatrixD3D9;
inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i,
DWORD arg1, DWORD op, DWORD arg2)
{
dev->SetTextureStageState(i, D3DTSS_COLOROP, op);
dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1);
dev->SetTextureStageState(i, D3DTSS_COLORARG2, arg2);
}
inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1)
{
dev->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1);
}
inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i,
DWORD arg1, DWORD op, DWORD arg2)
{
dev->SetTextureStageState(i, D3DTSS_ALPHAOP, op);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG2, arg2);
}
inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1)
{
dev->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1);
}
} // anonymous namespace
//! Base class for all internal D3D9 material renderers
class CD3D9MaterialRenderer : public IMaterialRenderer
{
public:
//! Constructor
CD3D9MaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver)
: pID3DDevice(d3ddev), Driver(driver)
{
}
//! sets a variable in the shader.
//! \param vertexShader: True if this should be set in the vertex shader, false if
//! in the pixel shader.
//! \param name: Name of the variable
//! \param floats: Pointer to array of floats
//! \param count: Amount of floats in array.
virtual bool setVariable(bool vertexShader, const c8* name, const f32* floats, int count)
{
os::Printer::log("Invalid material to set variable in.");
return false;
}
//! Bool interface for the above.
virtual bool setVariable(bool vertexShader, const c8* name, const bool* bools, int count)
{
os::Printer::log("Invalid material to set variable in.");
return false;
}
//! Int interface for the above.
virtual bool setVariable(bool vertexShader, const c8* name, const s32* ints, int count)
{
os::Printer::log("Invalid material to set variable in.");
return false;
}
protected:
IDirect3DDevice9* pID3DDevice;
video::IVideoDriver* Driver;
};
//! Solid material renderer
class CD3D9MaterialRenderer_SOLID : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SOLID(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
};
//! Generic Texture Blend
class CD3D9MaterialRenderer_ONETEXTURE_BLEND : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_ONETEXTURE_BLEND(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType ||
material.MaterialTypeParam != lastMaterial.MaterialTypeParam ||
resetAllRenderstates)
{
E_BLEND_FACTOR srcFact,dstFact;
E_MODULATE_FUNC modulate;
u32 alphaSource;
unpack_textureBlendFunc ( srcFact, dstFact, modulate, alphaSource, material.MaterialTypeParam );
if (srcFact == EBF_SRC_COLOR && dstFact == EBF_ZERO)
{
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
else
{
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pID3DDevice->SetRenderState(D3DRS_SRCBLEND, getD3DBlend ( srcFact ) );
pID3DDevice->SetRenderState(D3DRS_DESTBLEND, getD3DBlend ( dstFact ) );
}
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, getD3DModulate(modulate), D3DTA_DIFFUSE);
if ( textureBlendFunc_hasAlpha ( srcFact ) || textureBlendFunc_hasAlpha ( dstFact ) )
{
if (alphaSource==EAS_VERTEX_COLOR)
{
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
}
else if (alphaSource==EAS_TEXTURE)
{
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
}
else
{
setTextureAlphaStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
}
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
}
//! Returns if the material is transparent.
/** The scene management needs to know this for being able to sort the
materials by opaque and transparent.
The return value could be optimized, but we'd need to know the
MaterialTypeParam for it. */
virtual bool isTransparent() const
{
return true;
}
private:
u32 getD3DBlend ( E_BLEND_FACTOR factor ) const
{
u32 r = 0;
switch ( factor )
{
case EBF_ZERO: r = D3DBLEND_ZERO; break;
case EBF_ONE: r = D3DBLEND_ONE; break;
case EBF_DST_COLOR: r = D3DBLEND_DESTCOLOR; break;
case EBF_ONE_MINUS_DST_COLOR: r = D3DBLEND_INVDESTCOLOR; break;
case EBF_SRC_COLOR: r = D3DBLEND_SRCCOLOR; break;
case EBF_ONE_MINUS_SRC_COLOR: r = D3DBLEND_INVSRCCOLOR; break;
case EBF_SRC_ALPHA: r = D3DBLEND_SRCALPHA; break;
case EBF_ONE_MINUS_SRC_ALPHA: r = D3DBLEND_INVSRCALPHA; break;
case EBF_DST_ALPHA: r = D3DBLEND_DESTALPHA; break;
case EBF_ONE_MINUS_DST_ALPHA: r = D3DBLEND_INVDESTALPHA; break;
case EBF_SRC_ALPHA_SATURATE: r = D3DBLEND_SRCALPHASAT; break;
}
return r;
}
u32 getD3DModulate ( E_MODULATE_FUNC func ) const
{
u32 r = D3DTOP_MODULATE;
switch ( func )
{
case EMFN_MODULATE_1X: r = D3DTOP_MODULATE; break;
case EMFN_MODULATE_2X: r = D3DTOP_MODULATE2X; break;
case EMFN_MODULATE_4X: r = D3DTOP_MODULATE4X; break;
}
return r;
}
bool transparent;
};
//! Solid 2 layer material renderer
class CD3D9MaterialRenderer_SOLID_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SOLID_2_LAYER(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
};
//! Transparent add color material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
}
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const
{
return true;
}
};
//! Transparent vertex alpha material renderer
class CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
}
}
//! Returns if the material is transparent. The scene managment needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const
{
return true;
}
};
//! Transparent alpha channel material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates
|| material.MaterialTypeParam != lastMaterial.MaterialTypeParam )
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
pID3DDevice->SetRenderState(D3DRS_ALPHAREF, core::floor32(material.MaterialTypeParam * 255.f));
pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
}
}
virtual void OnUnsetMaterial()
{
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
}
//! Returns if the material is transparent. The scene managment needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const
{
return true;
}
};
//! Transparent alpha channel material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
// 127 is required by EMT_TRANSPARENT_ALPHA_CHANNEL_REF
pID3DDevice->SetRenderState(D3DRS_ALPHAREF, 127);
pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
}
}
virtual void OnUnsetMaterial()
{
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
}
//! Returns if the material is transparent. The scene managment needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const
{
return false; // this material is not really transparent because it does no blending.
}
};
//! material renderer for all kinds of lightmaps
class CD3D9MaterialRenderer_LIGHTMAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_LIGHTMAP(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
if (material.MaterialType >= EMT_LIGHTMAP_LIGHTING)
{
// with lighting
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
else
{
setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE);
}
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE,
(material.MaterialType == EMT_LIGHTMAP_ADD)?
D3DTOP_ADD:
(material.MaterialType == EMT_LIGHTMAP_M4 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M4)?
D3DTOP_MODULATE4X:
(material.MaterialType == EMT_LIGHTMAP_M2 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M2)?
D3DTOP_MODULATE2X:
D3DTOP_MODULATE,
D3DTA_CURRENT);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
};
//! material renderer for detail maps
class CD3D9MaterialRenderer_DETAIL_MAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_DETAIL_MAP(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_ADDSIGNED, D3DTA_CURRENT);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
};
//! sphere map material renderer
class CD3D9MaterialRenderer_SPHERE_MAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SPHERE_MAP(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
pID3DDevice->SetTransform( D3DTS_TEXTURE0, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );
}
}
virtual void OnUnsetMaterial()
{
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0);
pID3DDevice->SetTransform( D3DTS_TEXTURE0, &UnitMatrixD3D9 );
}
};
//! reflection 2 layer material renderer
class CD3D9MaterialRenderer_REFLECTION_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_REFLECTION_2_LAYER(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
pID3DDevice->SetTransform( D3DTS_TEXTURE1, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
virtual void OnUnsetMaterial()
{
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1);
pID3DDevice->SetTransform( D3DTS_TEXTURE1, &UnitMatrixD3D9 );
}
};
//! reflection 2 layer material renderer
class CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(IDirect3DDevice9* p, video::IVideoDriver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 1, D3DTA_CURRENT);
pID3DDevice->SetTransform(D3DTS_TEXTURE1, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
}
}
virtual void OnUnsetMaterial()
{
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
pID3DDevice->SetTransform(D3DTS_TEXTURE1, &UnitMatrixD3D9);
}
//! Returns if the material is transparent. The scene managment needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const
{
return true;
}
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif
@@ -0,0 +1,306 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9NormalMapRenderer.h"
#include "IVideoDriver.h"
#include "IMaterialRendererServices.h"
#include "os.h"
#include "SLight.h"
namespace irr
{
namespace video
{
// 1.1 Shaders with two lights and vertex based attenuation
// Irrlicht Engine D3D9 render path normal map vertex shader
const char D3D9_NORMAL_MAP_VSH[] =
";Irrlicht Engine 0.8 D3D9 render path normal map vertex shader\n"\
"; c0-3: Transposed world matrix \n"\
"; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
"; c12: Light01 position \n"\
"; c13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\
"; c14: Light02 position \n"\
"; c15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\
"vs.1.1\n"\
"dcl_position v0 ; position \n"\
"dcl_normal v1 ; normal \n"\
"dcl_color v2 ; color \n"\
"dcl_texcoord0 v3 ; texture coord \n"\
"dcl_texcoord1 v4 ; tangent \n"\
"dcl_texcoord2 v5 ; binormal \n"\
"\n"\
"def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
"\n"\
"m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
"\n"\
"m3x3 r5, v4, c0 ; transform tangent U\n"\
"m3x3 r7, v1, c0 ; transform normal W\n"\
"m3x3 r6, v5, c0 ; transform binormal V\n"\
"\n"\
"m4x4 r4, v0, c0 ; vertex into world position\n"\
"add r2, c12, -r4 ; vtxpos - lightpos1\n"\
"add r3, c14, -r4 ; vtxpos - lightpos2\n"\
"\n"\
"dp3 r8.x, r5, r2 ; transform the light vector 1 with U, V, W\n"\
"dp3 r8.y, r6, r2 \n"\
"dp3 r8.z, r7, r2 \n"\
"dp3 r9.x, r5, r3 ; transform the light vector 2 with U, V, W\n"\
"dp3 r9.y, r6, r3 \n"\
"dp3 r9.z, r7, r3 \n"\
"\n"\
"dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
"rsq r8.w, r8.w \n"\
"mul r8, r8, r8.w \n"\
"dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
"rsq r9.w, r9.w \n"\
"mul r9, r9, r9.w \n"\
"\n"\
"mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
"mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
"\n"\
" ; calculate attenuation of light 1 \n"\
"dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x^2 + r2.y^2 + r2.z^2 \n"\
"mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
"rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
" ; calculate attenuation of light 2 \n"\
"dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x^2 + r3.y^2 + r3.z^2 \n"\
"mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
"rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
"mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
"mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
"mov oD0.a, v2.a ; move out original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader
const char D3D9_NORMAL_MAP_PSH_1_1[] =
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
"ps.1.1 \n"\
"tex t0 ; sample color map \n"\
"tex t1 ; sample normal map\n"\
"texcoord t2 ; fetch light vector 1\n"\
"texcoord t3 ; fetch light vector 2\n"\
"\n"\
"dp3_sat r0, t1_bx2, t2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1)\n"\
"mul r0, r0, v0 ; luminance1 * light color 1 \n"\
"\n"\
"dp3_sat r1, t1_bx2, t3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1)\n"\
"mad r0, r1, v1, r0 ; (luminance2 * light color 2) + luminance 1 \n"\
"\n"\
"mul r0.xyz, t0, r0 ; total luminance * base color\n"\
"+mov r0.a, v0.a ; write interpolated vertex alpha value \n"\
"\n"\
"";
// Higher-quality normal map pixel shader (requires PS 2.0)
// uses per-pixel normalization for improved accuracy
const char D3D9_NORMAL_MAP_PSH_2_0[] =
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
"ps_2_0 \n"\
"def c0, 0, 0, 0, 0\n"\
"def c1, 1.0, 1.0, 1.0, 1.0\n"\
"def c2, 2.0, 2.0, 2.0, 2.0\n"\
"def c3, -.5, -.5, -.5, -.5\n"\
"dcl t0\n"\
"dcl t1\n"\
"dcl t2\n"\
"dcl t3\n"\
"dcl v1\n"\
"dcl v0\n"\
"dcl_2d s0\n"\
"dcl_2d s1\n"\
"texld r0, t0, s0 ; sample color map into r0 \n"\
"texld r4, t0, s1 ; sample normal map into r4\n"\
"add r4, r4, c3 ; bias the normal vector\n"\
"add r5, t2, c3 ; bias the light 1 vector into r5\n"\
"add r6, t3, c3 ; bias the light 2 vector into r6\n"\
"nrm r1, r4 ; normalize the normal vector into r1\n"\
"nrm r2, r5 ; normalize the light1 vector into r2\n"\
"nrm r3, r6 ; normalize the light2 vector into r3\n"\
"dp3 r2, r2, r1 ; let r2 = normal DOT light 1 vector\n"\
"max r2, r2, c0 ; clamp result to positive numbers\n"\
"mul r2, r2, v0 ; let r2 = luminance1 * light color 1 \n"\
"dp3 r3, r3, r1 ; let r3 = normal DOT light 2 vector\n"\
"max r3, r3, c0 ; clamp result to positive numbers\n"\
"mad r2, r3, v1, r2 ; let r2 = (luminance2 * light color 2) + (luminance2 * light color 1) \n"\
"mul r2, r2, r0 ; let r2 = total luminance * base color\n"\
"mov r2.w, v0.w ; write interpolated vertex alpha value \n"\
"mov oC0, r2 ; copy r2 to the output register \n"\
"\n"\
"";
CD3D9NormalMapRenderer::CD3D9NormalMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial)
{
#ifdef _DEBUG
setDebugName("CD3D9NormalMapRenderer");
#endif
// set this as callback. We could have done this in
// the initialization list, but some compilers don't like it.
CallBack = this;
// basically, this thing simply compiles the hardcoded shaders
// if the hardware is able to do them, otherwise it maps to the
// base material
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) ||
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
{
// this hardware is not able to do shaders. Fall back to
// base material.
outMaterialTypeNr = driver->addMaterialRenderer(this);
return;
}
// check if already compiled normal map shaders are there.
video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID);
if (renderer)
{
// use the already compiled shaders
video::CD3D9NormalMapRenderer* nmr = (video::CD3D9NormalMapRenderer*)renderer;
VertexShader = nmr->VertexShader;
if (VertexShader)
VertexShader->AddRef();
PixelShader = nmr->PixelShader;
if (PixelShader)
PixelShader->AddRef();
outMaterialTypeNr = driver->addMaterialRenderer(this);
}
else
{
// compile shaders on our own
if (driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0))
{
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_2_0);
}
else
{
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_1_1);
}
}
// something failed, use base material
if (-1==outMaterialTypeNr)
driver->addMaterialRenderer(this);
}
CD3D9NormalMapRenderer::~CD3D9NormalMapRenderer()
{
if (CallBack == this)
CallBack = 0;
}
bool CD3D9NormalMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (vtxtype != video::EVT_TANGENTS)
{
os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
return false;
}
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
//! Returns the render capability of the material.
s32 CD3D9NormalMapRenderer::getRenderCapability() const
{
if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
return 0;
return 1;
}
//! Called by the engine when the vertex and/or pixel shader constants
//! for an material renderer should be set.
void CD3D9NormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();
// set transposed world matrix
services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
// set transposed worldViewProj matrix
core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
// here we've got to fetch the fixed function lights from the
// driver and set them as constants
u32 cnt = driver->getDynamicLightCount();
for (u32 i=0; i<2; ++i)
{
SLight light;
if (i<cnt)
light = driver->getDynamicLight(i);
else
{
light.DiffuseColor.set(0,0,0); // make light dark
light.Radius = 1.0f;
}
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
}
// this is not really necessary in d3d9 (used a def instruction), but to be sure:
f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
services->setVertexShaderConstant(c95, 95, 1);
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
@@ -0,0 +1,56 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
namespace irr
{
namespace video
{
//! Renderer for normal maps
class CD3D9NormalMapRenderer :
public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack
{
public:
CD3D9NormalMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial);
~CD3D9NormalMapRenderer();
//! Called by the engine when the vertex and/or pixel shader constants for an
//! material renderer should be set.
virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData);
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype);
//! Returns the render capability of the material.
virtual s32 getRenderCapability() const;
private:
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif
@@ -0,0 +1,410 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9ParallaxMapRenderer.h"
#include "IMaterialRendererServices.h"
#include "IVideoDriver.h"
#include "os.h"
#include "SLight.h"
//#define SHADER_EXTERNAL_DEBUG
#ifdef SHADER_EXTERNAL_DEBUG
#include "CReadFile.h"
#endif
namespace irr
{
namespace video
{
// 1.1/1.4 Shaders with two lights and vertex based attenuation
// Irrlicht Engine D3D9 render path normal map vertex shader
const char D3D9_PARALLAX_MAP_VSH[] =
";Irrlicht Engine 0.10 D3D9 render path parallax mapping vertex shader\n"\
"; c0-3: Transposed world matrix \n"\
"; c4: Eye position \n"\
"; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
"; c12: Light01 position \n"\
"; c13: x,y,z: Light01 color; .w: 1/LightRadius² \n"\
"; c14: Light02 position \n"\
"; c15: x,y,z: Light02 color; .w: 1/LightRadius² \n"\
"vs.1.1\n"\
"dcl_position v0 ; position \n"\
"dcl_normal v1 ; normal \n"\
"dcl_color v2 ; color \n"\
"dcl_texcoord0 v3 ; texture coord \n"\
"dcl_texcoord1 v4 ; tangent \n"\
"dcl_texcoord2 v5 ; binormal \n"\
"\n"\
"def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
"def c96, -1, 1, 1, 1 ; somewhere I've got a bug. flipping the vectors with this fixes it. \n"\
"\n"\
"m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
"\n"\
"m3x3 r5, v4, c0 ; transform tangent U\n"\
"m3x3 r7, v1, c0 ; transform normal W\n"\
"m3x3 r6, v5, c0 ; transform binormal V\n"\
"\n"\
"m4x4 r4, v0, c0 ; vertex into world position\n"\
"add r2, c12, -r4 ; vtxpos - light1 pos\n"\
"add r3, c14, -r4 ; vtxpos - light2 pos\n"\
"add r1, -c4, r4 ; eye - vtxpos \n"\
"\n"\
"dp3 r8.x, r5, r2 ; transform the light1 vector with U, V, W\n"\
"dp3 r8.y, r6, r2 \n"\
"dp3 r8.z, r7, r2 \n"\
"dp3 r9.x, r5, r3 ; transform the light2 vector with U, V, W\n"\
"dp3 r9.y, r6, r3 \n"\
"dp3 r9.z, r7, r3 \n"\
"dp3 r10.x, r5, r1 ; transform the eye vector with U, V, W\n"\
"dp3 r10.y, r6, r1 \n"\
"dp3 r10.z, r7, r1 \n"\
"\n"\
"dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
"rsq r8.w, r8.w \n"\
"mul r8, r8, r8.w \n"\
";mul r8, r8, c96 \n"\
"dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
"rsq r9.w, r9.w \n"\
"mul r9, r9, r9.w \n"\
";mul r9, r9, c96 \n"\
"dp3 r10.w, r10, r10 ; normalize eye vector (r10)\n"\
"rsq r10.w, r10.w \n"\
"mul r10, r10, r10.w \n"\
"mul r10, r10, c96 \n"\
"\n"\
"\n"\
"mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
"mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
"mad oT4.xyz, r10.xyz, c95, c95 ; move eye vector from -1..1 into 0..1 \n"\
"\n"\
" ; calculate attenuation of light 1 \n"\
"dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x² + r2.y² + r2.z² \n"\
"mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
"rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
" ; calculate attenuation of light 2 \n"\
"dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x² + r3.y² + r3.z² \n"\
"mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
"rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
"mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
"mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
"mov oD0.a, v2.a ; move out original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader version 1.4
const char D3D9_PARALLAX_MAP_PSH[] =
";Irrlicht Engine 0.10 D3D9 render path parallax mapping pixel shader \n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";t4: eye vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
" \n"\
"ps.1.4 \n"\
" \n"\
";def c6, 0.02f, 0.02f, 0.02f, 0.0f ; scale factor, now set in callback \n"\
"def c5, 0.5f, 0.5f, 0.5f, 0.0f ; for specular division \n"\
" \n"\
"texld r1, t1 ; sample (normal.x, normal.y, normal.z, height) \n"\
"texcrd r4.xyz, t4 ; fetch eye vector \n"\
"texcrd r0.xyz, t0 ; color map \n"\
" \n"\
"; original parallax mapping: \n"\
";mul r3, r1_bx2.wwww, c6; ; r3 = (height, height, height) * scale \n"\
";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"; modified parallax mapping to reduce swimming effect: \n"\
"mul r3, r1_bx2.wwww, r1_bx2.zzzz ; (nh,nh,nh,nh) = (h,h,h,h) * (n.z,n.z,n.z,n.z,) \n"\
"mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
"mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"phase \n"\
" \n"\
"texld r0, r2 ; load diffuse texture with new tex coord \n"\
"texld r1, r2 ; sample normal map \n"\
"texcrd r2.xyz, t2 ; fetch light vector 1 \n"\
"texcrd r3.xyz, t3 ; fetch light vector 2 \n"\
" \n"\
"dp3_sat r5, r1_bx2, r2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\
"mul r5, r5, v0 ; luminance1 * light color 1 \n"\
" \n"\
"dp3_sat r3, r1_bx2, r3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\
"mad r3, r3, v1, r5 ; (luminance2 * light color 2) + luminance1 \n"\
" \n"\
"mul r0.xyz, r0, r3 ; total luminance * base color \n"\
"+mov r0.a, v0.a ; write original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader version 2.0
const char D3D9_PARALLAX_MAP_PSH_20[] =
";Irrlicht Engine D3D9 render path parallax mapping pixel shader \n"\
";Input: \n"\
" \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";t4: eye vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
" \n"\
"ps.2.0 \n"\
" \n"\
"dcl_2d s0 ; Declare the s0 register to be the sampler for stage 0 \n"\
"dcl t0.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\
"dcl t1.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\
"dcl_2d s1 ; Declare the s1 register to be the sampler for stage 1 \n"\
" \n"\
"dcl t2.xyz ; \n"\
"dcl t3.xyz ; \n"\
"dcl t4.xyz ; \n"\
"dcl v0.xyzw; \n"\
"dcl v1.xyzw; \n"\
" \n"\
"def c0, -1.0f, -1.0f, -1.0f, -1.0f ; for _bx2 emulation \n"\
"def c1, 2.0f, 2.0f, 2.0f, 2.0f ; for _bx2 emulation \n"\
"mov r11, c1; \n"\
" \n"\
"texld r1, t1, s1 ; sample (normal.x, normal.y, normal.z, height) \n"\
"mov r4.xyz, t4 ; fetch eye vector \n"\
"mov r0.xy, t0 ; color map \n"\
" \n"\
"; original parallax mapping: \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r1.xyz, r1, r11, c0; \n"\
" \n"\
"mul r3, r1.wwww, c6; ; r3 = (height, height, height) * scale \n"\
" \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r4.xyz, r4, r11, c0; \n"\
" \n"\
"mad r2.xy, r3, r4, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"; modified parallax mapping to avoid swimming: \n"\
";mul r3, r1_bx2.wwww, r1_bx2.zzzz ; r3 = (h,h,h,h) * (n.z, n.z, n.z, n.z,) \n"\
";mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"texld r0, r2, s0 ; load diffuse texture with new tex coord \n"\
"texld r1, r2, s1 ; sample normal map \n"\
"mov r2.xyz, t2 ; fetch light vector 1 \n"\
"mov r3.xyz, t3 ; fetch light vector 2 \n"\
" \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r1.xyz, r1, r11, c0; \n"\
"mad r2.xyz, r2, r11, c0; \n"\
"mad r3.xyz, r3, r11, c0; \n"\
" \n"\
"dp3_sat r2, r1, r2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\
"mul r2, r2, v0 ; luminance1 * light color 1 \n"\
" \n"\
"dp3_sat r3, r1, r3 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\
"mad r3, r3, v1, r2 ; (luminance2 * light color 2) + luminance1 \n"\
" \n"\
"mul r0.xyz, r0, r3 ; total luminance * base color \n"\
"mov r0.a, v0.a ; write original alpha value \n"\
"mov oC0, r0; \n"\
"\n";
CD3D9ParallaxMapRenderer::CD3D9ParallaxMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial),
CurrentScale(0.0f)
{
#ifdef _DEBUG
setDebugName("CD3D9ParallaxMapRenderer");
#endif
// set this as callback. We could have done this in
// the initialization list, but some compilers don't like it.
CallBack = this;
// basicly, this thing simply compiles these hardcoded shaders if the
// hardware is able to do them, otherwise it maps to the base material
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) ||
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
{
// this hardware is not able to do shaders. Fall back to
// base material.
outMaterialTypeNr = driver->addMaterialRenderer(this);
return;
}
// check if already compiled parallax map shaders are there.
video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID);
if (renderer)
{
// use the already compiled shaders
video::CD3D9ParallaxMapRenderer* nmr = (video::CD3D9ParallaxMapRenderer*)renderer;
VertexShader = nmr->VertexShader;
if (VertexShader)
VertexShader->AddRef();
PixelShader = nmr->PixelShader;
if (PixelShader)
PixelShader->AddRef();
outMaterialTypeNr = driver->addMaterialRenderer(this);
}
else
{
#ifdef SHADER_EXTERNAL_DEBUG
// quickly load shader from external file
io::CReadFile* file = new io::CReadFile("parallax.psh");
s32 sz = file->getSize();
char* s = new char[sz+1];
file->read(s, sz);
s[sz] = 0;
init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, s);
delete [] s;
file->drop();
#else
// compile shaders on our own
init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, D3D9_PARALLAX_MAP_PSH);
#endif // SHADER_EXTERNAL_DEBUG
}
// something failed, use base material
if (-1==outMaterialTypeNr)
driver->addMaterialRenderer(this);
}
CD3D9ParallaxMapRenderer::~CD3D9ParallaxMapRenderer()
{
if (CallBack == this)
CallBack = 0;
}
bool CD3D9ParallaxMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (vtxtype != video::EVT_TANGENTS)
{
os::Printer::log("Error: Parallax map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
return false;
}
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
void CD3D9ParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material,
const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services)
{
CD3D9ShaderMaterialRenderer::OnSetMaterial(material, lastMaterial,
resetAllRenderstates, services);
CurrentScale = material.MaterialTypeParam;
}
//! Returns the render capability of the material.
s32 CD3D9ParallaxMapRenderer::getRenderCapability() const
{
if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) &&
Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
return 0;
return 1;
}
//! Called by the engine when the vertex and/or pixel shader constants
//! for an material renderer should be set.
void CD3D9ParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();
// set transposed world matrix
services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
// set eye position
// The viewpoint is at (0., 0., 0.) in eye space.
// Turning this into a vector [0 0 0 1] and multiply it by
// the inverse of the view matrix, the resulting vector is the
// object space location of the camera.
f32 floats[4] = {0,0,0,1};
core::matrix4 minv = driver->getTransform(video::ETS_VIEW);
minv.makeInverse();
minv.multiplyWith1x4Matrix(floats);
services->setVertexShaderConstant(floats, 4, 1);
// set transposed worldViewProj matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
// here we've got to fetch the fixed function lights from the
// driver and set them as constants
const u32 cnt = driver->getDynamicLightCount();
for (u32 i=0; i<2; ++i)
{
SLight light;
if (i<cnt)
light = driver->getDynamicLight(i);
else
{
light.DiffuseColor.set(0,0,0); // make light dark
light.Radius = 1.0f;
}
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
}
// this is not really necessary in d3d9 (used a def instruction), but to be sure:
f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
services->setVertexShaderConstant(c95, 95, 1);
f32 c96[] = {-1, 1, 1, 1};
services->setVertexShaderConstant(c96, 96, 1);
// set scale factor
f32 factor = 0.02f; // default value
if (CurrentScale != 0)
factor = CurrentScale;
f32 c6[] = {factor, factor, factor, 0};
services->setPixelShaderConstant(c6, 6, 1);
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
@@ -0,0 +1,63 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
namespace irr
{
namespace video
{
//! Renderer for normal maps using parallax mapping
class CD3D9ParallaxMapRenderer :
public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack
{
public:
CD3D9ParallaxMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial);
~CD3D9ParallaxMapRenderer();
//! Called by the engine when the vertex and/or pixel shader constants for an
//! material renderer should be set.
virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData);
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype);
//! Returns the render capability of the material.
virtual s32 getRenderCapability() const;
virtual void OnSetMaterial(const SMaterial& material) { }
virtual void OnSetMaterial(const video::SMaterial& material,
const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services);
private:
f32 CurrentScale;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif
@@ -0,0 +1,541 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#define _IRR_D3D_NO_SHADER_DEBUGGING 1
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
#include "IMaterialRendererServices.h"
#include "IVideoDriver.h"
#include "os.h"
#include "irrString.h"
#ifndef _IRR_D3D_NO_SHADER_DEBUGGING
#include <stdio.h>
#endif
namespace irr
{
namespace video
{
//! Public constructor
CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData)
: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData)
{
#ifdef _DEBUG
setDebugName("CD3D9ShaderMaterialRenderer");
#endif
if (BaseMaterial)
BaseMaterial->grab();
if (CallBack)
CallBack->grab();
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram);
}
//! constructor only for use by derived classes who want to
//! create a fall back material for example.
CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial, s32 userData)
: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData)
{
#ifdef _DEBUG
setDebugName("CD3D9ShaderMaterialRenderer");
#endif
if (BaseMaterial)
BaseMaterial->grab();
if (CallBack)
CallBack->grab();
}
void CD3D9ShaderMaterialRenderer::init(s32& outMaterialTypeNr,
const c8* vertexShaderProgram, const c8* pixelShaderProgram)
{
outMaterialTypeNr = -1;
// create vertex shader
if (!createVertexShader(vertexShaderProgram))
return;
// create pixel shader
if (!createPixelShader(pixelShaderProgram))
return;
// register myself as new material
outMaterialTypeNr = Driver->addMaterialRenderer(this);
}
//! Destructor
CD3D9ShaderMaterialRenderer::~CD3D9ShaderMaterialRenderer()
{
if (CallBack)
CallBack->drop();
if (VertexShader)
VertexShader->Release();
if (PixelShader)
PixelShader->Release();
if (BaseMaterial)
BaseMaterial->drop();
}
bool CD3D9ShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
// call callback to set shader constants
if (CallBack && (VertexShader || PixelShader))
CallBack->OnSetConstants(service, UserData);
return true;
}
void CD3D9ShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services)
{
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
if (VertexShader)
{
// save old vertex shader
pID3DDevice->GetVertexShader(&OldVertexShader);
// set new vertex shader
if (FAILED(pID3DDevice->SetVertexShader(VertexShader)))
os::Printer::log("Could not set vertex shader.", ELL_WARNING);
}
// set new pixel shader
if (PixelShader)
{
if (FAILED(pID3DDevice->SetPixelShader(PixelShader)))
os::Printer::log("Could not set pixel shader.", ELL_WARNING);
}
if (BaseMaterial)
BaseMaterial->OnSetMaterial(material, material, true, services);
}
//let callback know used material
if (CallBack)
CallBack->OnSetMaterial(material);
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
}
void CD3D9ShaderMaterialRenderer::OnUnsetMaterial()
{
if (VertexShader)
pID3DDevice->SetVertexShader(OldVertexShader);
if (PixelShader)
pID3DDevice->SetPixelShader(0);
if (BaseMaterial)
BaseMaterial->OnUnsetMaterial();
}
//! Returns if the material is transparent. The scene managment needs to know this
//! for being able to sort the materials by opaque and transparent.
bool CD3D9ShaderMaterialRenderer::isTransparent() const
{
return BaseMaterial ? BaseMaterial->isTransparent() : false;
}
bool CD3D9ShaderMaterialRenderer::createPixelShader(const c8* pxsh)
{
if (!pxsh)
return true;
// compile shader
LPD3DXBUFFER code = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile shader without debug info
stubD3DXAssembleShader(pxsh, (UINT)strlen(pxsh), 0, 0, 0, &code, &errors);
#else
// compile shader and emitt some debug informations to
// make it possible to debug the shader in visual studio
static int irr_dbg_file_nr = 0;
++irr_dbg_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_shader_%d.psh", irr_dbg_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(pxsh, strlen(pxsh), 1, f);
fflush(f);
fclose(f);
stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors);
#endif
if (errors)
{
// print out compilation errors.
os::Printer::log("Pixel shader compilation failed:", ELL_ERROR);
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
if (code)
code->Release();
errors->Release();
return false;
}
if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)code->GetBufferPointer(), &PixelShader)))
{
os::Printer::log("Could not create pixel shader.", ELL_ERROR);
code->Release();
return false;
}
code->Release();
return true;
}
bool CD3D9ShaderMaterialRenderer::createVertexShader(const char* vtxsh)
{
if (!vtxsh)
return true;
// compile shader
LPD3DXBUFFER code = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile shader without debug info
stubD3DXAssembleShader(vtxsh, (UINT)strlen(vtxsh), 0, 0, 0, &code, &errors);
#else
// compile shader and emitt some debug informations to
// make it possible to debug the shader in visual studio
static int irr_dbg_file_nr = 0;
++irr_dbg_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_shader_%d.vsh", irr_dbg_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(vtxsh, strlen(vtxsh), 1, f);
fflush(f);
fclose(f);
stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors);
#endif
if (errors)
{
// print out compilation errors.
os::Printer::log("Vertex shader compilation failed:", ELL_ERROR);
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
if (code)
code->Release();
errors->Release();
return false;
}
if (!code || FAILED(pID3DDevice->CreateVertexShader((DWORD*)code->GetBufferPointer(), &VertexShader)))
{
os::Printer::log("Could not create vertex shader.", ELL_ERROR);
if (code)
code->Release();
return false;
}
code->Release();
return true;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader(LPCSTR pSrcData,
UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs)
{
// Because Irrlicht needs to be able to start up even without installed d3d dlls, it
// needs to load external d3d dlls manually. examples for the dlls are:
// SDK dll name D3DX_SDK_VERSION
// Summer 2004: no dll 22
// February 2005: d3dx9_24.dll 24
// April 2005: d3dx9_25.dll 25
// June 2005: d3dx9_26.dll 26
// August 2005: d3dx9_27.dll 27
// October 2005,
// December 2005: d3dx9_28.dll 28
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXAssembleShader(pSrcData, SrcDataLen, pDefines, pInclude,
Flags, ppShader, ppErrorMsgs);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXAssembleShader signature
typedef HRESULT (WINAPI *AssembleShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude,
DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs);
static bool LoadFailed = false;
static AssembleShaderFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibraryA(strDllName.c_str());
if (hMod)
pFn = (AssembleShaderFunction)GetProcAddress(hMod, "D3DXAssembleShader");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXAssembleShader from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, Flags, ppShader, ppErrorMsgs);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXAssembleShaderFromFileA(pSrcFile, pDefines, pInclude, Flags,
ppShader, ppErrorMsgs);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXAssembleShaderFromFileA signature
typedef HRESULT (WINAPI *AssembleShaderFromFileFunction)(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs);
static bool LoadFailed = false;
static AssembleShaderFromFileFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibraryA(strDllName.c_str());
if (hMod)
pFn = (AssembleShaderFromFileFunction)GetProcAddress(hMod, "D3DXAssembleShaderFromFileA");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXAssembleShaderFromFileA from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcFile, pDefines, pInclude, Flags, ppShader, ppErrorMsgs);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXCompileShader(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXCompileShader
typedef HRESULT (WINAPI *D3DXCompileShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable);
static bool LoadFailed = false;
static D3DXCompileShaderFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibraryA(strDllName.c_str());
if (hMod)
pFn = (D3DXCompileShaderFunction)GetProcAddress(hMod, "D3DXCompileShader");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXCompileShader from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXCompileShaderFromFileA(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXCompileShaderFromFileA
typedef HRESULT (WINAPI *D3DXCompileShaderFromFileFunction)(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable);
static bool LoadFailed = false;
static D3DXCompileShaderFromFileFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibraryA(strDllName.c_str());
if (hMod)
pFn = (D3DXCompileShaderFromFileFunction)GetProcAddress(hMod, "D3DXCompileShaderFromFileA");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXCompileShaderFromFileA from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
@@ -0,0 +1,102 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3dx9shader.h>
#include "IMaterialRenderer.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class IShaderConstantSetCallBack;
class IMaterialRenderer;
//! Class for using vertex and pixel shaders with D3D9
class CD3D9ShaderMaterialRenderer : public IMaterialRenderer
{
public:
//! Public constructor
CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData);
//! Destructor
~CD3D9ShaderMaterialRenderer();
virtual void OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services);
virtual void OnUnsetMaterial();
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype);
//! Returns if the material is transparent.
virtual bool isTransparent() const;
protected:
//! constructor only for use by derived classes who want to
//! create a fall back material for example.
CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData=0);
void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram);
bool createPixelShader(const c8* pxsh);
bool createVertexShader(const char* vtxsh);
HRESULT stubD3DXAssembleShader(LPCSTR pSrcData, UINT SrcDataLen,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude,
DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs);
HRESULT stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs);
HRESULT stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable);
HRESULT stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable);
IDirect3DDevice9* pID3DDevice;
video::IVideoDriver* Driver;
IShaderConstantSetCallBack* CallBack;
IMaterialRenderer* BaseMaterial;
IDirect3DVertexShader9* VertexShader;
IDirect3DVertexShader9* OldVertexShader;
IDirect3DPixelShader9* PixelShader;
s32 UserData;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif
@@ -0,0 +1,699 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE
#include "CD3D9Texture.h"
#include "CD3D9Driver.h"
#include "os.h"
#include <d3dx9tex.h>
#ifndef _IRR_COMPILE_WITH_DIRECT3D_8_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation in d3d 8 when
// compiling with both D3D 8 and 9.
// #define _IRR_USE_D3DXFilterTexture_
#endif // _IRR_COMPILE_WITH_DIRECT3D_8_
#ifdef _IRR_USE_D3DXFilterTexture_
#pragma comment(lib, "d3dx9.lib")
#endif
namespace irr
{
namespace video
{
//! rendertarget constructor
CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format)
: ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0),
TextureSize(size), ImageSize(size), Pitch(0), ColorFormat(ECF_UNKNOWN),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true)
{
#ifdef _DEBUG
setDebugName("CD3D9Texture");
#endif
Device=driver->getExposedVideoData().D3D9.D3DDev9;
if (Device)
Device->AddRef();
createRenderTarget(format);
}
//! constructor
CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
u32 flags, const io::path& name, void* mipmapData)
: ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0),
TextureSize(0,0), ImageSize(0,0), Pitch(0), ColorFormat(ECF_UNKNOWN),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false)
{
#ifdef _DEBUG
setDebugName("CD3D9Texture");
#endif
HasMipMaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Device=driver->getExposedVideoData().D3D9.D3DDev9;
if (Device)
Device->AddRef();
if (image)
{
if (createTexture(flags, image))
{
if (copyTexture(image))
{
regenerateMipMapLevels(mipmapData);
}
}
else
os::Printer::log("Could not create DIRECT3D9 Texture.", ELL_WARNING);
}
}
//! destructor
CD3D9Texture::~CD3D9Texture()
{
if (Texture)
Texture->Release();
if (RTTSurface)
RTTSurface->Release();
// if this texture was the last one using the depth buffer
// we can release the surface. We only use the value of the pointer
// hence it is safe to use the dropped pointer...
if (DepthSurface)
{
if (DepthSurface->drop())
Driver->removeDepthSurface(DepthSurface);
}
if (Device)
Device->Release();
}
void CD3D9Texture::createRenderTarget(const ECOLOR_FORMAT format)
{
// are texture size restrictions there ?
if(!Driver->queryFeature(EVDF_TEXTURE_NPOT))
{
if (TextureSize != ImageSize)
os::Printer::log("RenderTarget size has to be a power of two", ELL_INFORMATION);
}
TextureSize = TextureSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth);
D3DFORMAT d3dformat = Driver->getD3DColorFormat();
if(ColorFormat == ECF_UNKNOWN)
{
// get irrlicht format from backbuffer
// (This will get overwritten by the custom format if it is provided, else kept.)
ColorFormat = Driver->getColorFormat();
setPitch(d3dformat);
// Use color format if provided.
if(format != ECF_UNKNOWN)
{
ColorFormat = format;
d3dformat = Driver->getD3DFormatFromColorFormat(format);
setPitch(d3dformat); // This will likely set pitch to 0 for now.
}
}
else
{
d3dformat = Driver->getD3DFormatFromColorFormat(ColorFormat);
}
// create texture
HRESULT hr;
hr = Device->CreateTexture(
TextureSize.Width,
TextureSize.Height,
1, // mip map level count, we don't want mipmaps here
D3DUSAGE_RENDERTARGET,
d3dformat,
D3DPOOL_DEFAULT,
&Texture,
NULL);
if (FAILED(hr))
{
if (D3DERR_INVALIDCALL == hr)
os::Printer::log("Could not create render target texture", "Invalid Call");
else
if (D3DERR_OUTOFVIDEOMEMORY == hr)
os::Printer::log("Could not create render target texture", "Out of Video Memory");
else
if (E_OUTOFMEMORY == hr)
os::Printer::log("Could not create render target texture", "Out of Memory");
else
os::Printer::log("Could not create render target texture");
}
}
bool CD3D9Texture::createMipMaps(u32 level)
{
if (level==0)
return true;
if (HardwareMipMaps && Texture)
{
// generate mipmaps in hardware
Texture->GenerateMipSubLevels();
return true;
}
// manual mipmap generation
IDirect3DSurface9* upperSurface = 0;
IDirect3DSurface9* lowerSurface = 0;
// get upper level
HRESULT hr = Texture->GetSurfaceLevel(level-1, &upperSurface);
if (FAILED(hr) || !upperSurface)
{
os::Printer::log("Could not get upper surface level for mip map generation", ELL_WARNING);
return false;
}
// get lower level
hr = Texture->GetSurfaceLevel(level, &lowerSurface);
if (FAILED(hr) || !lowerSurface)
{
os::Printer::log("Could not get lower surface level for mip map generation", ELL_WARNING);
upperSurface->Release();
return false;
}
D3DSURFACE_DESC upperDesc, lowerDesc;
upperSurface->GetDesc(&upperDesc);
lowerSurface->GetDesc(&lowerDesc);
D3DLOCKED_RECT upperlr;
D3DLOCKED_RECT lowerlr;
// lock upper surface
if (FAILED(upperSurface->LockRect(&upperlr, NULL, 0)))
{
upperSurface->Release();
lowerSurface->Release();
os::Printer::log("Could not lock upper texture for mip map generation", ELL_WARNING);
return false;
}
// lock lower surface
if (FAILED(lowerSurface->LockRect(&lowerlr, NULL, 0)))
{
upperSurface->UnlockRect();
upperSurface->Release();
lowerSurface->Release();
os::Printer::log("Could not lock lower texture for mip map generation", ELL_WARNING);
return false;
}
if (upperDesc.Format != lowerDesc.Format)
{
os::Printer::log("Cannot copy mip maps with different formats.", ELL_WARNING);
}
else
{
if ((upperDesc.Format == D3DFMT_A1R5G5B5) || (upperDesc.Format == D3DFMT_R5G6B5))
copy16BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
lowerDesc.Width, lowerDesc.Height,
upperlr.Pitch, lowerlr.Pitch);
else
if (upperDesc.Format == D3DFMT_A8R8G8B8)
copy32BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
lowerDesc.Width, lowerDesc.Height,
upperlr.Pitch, lowerlr.Pitch);
else
os::Printer::log("Unsupported mipmap format, cannot copy.", ELL_WARNING);
}
bool result=true;
// unlock
if (FAILED(upperSurface->UnlockRect()))
result=false;
if (FAILED(lowerSurface->UnlockRect()))
result=false;
// release
upperSurface->Release();
lowerSurface->Release();
if (!result || (upperDesc.Width <= 3 && upperDesc.Height <= 3))
return result; // stop generating levels
// generate next level
return createMipMaps(level+1);
}
//! creates the hardware texture
bool CD3D9Texture::createTexture(u32 flags, IImage * image)
{
ImageSize = image->getDimension();
core::dimension2d<u32> optSize = ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth);
D3DFORMAT format = D3DFMT_A1R5G5B5;
switch(getTextureFormatFromFlags(flags))
{
case ETCF_ALWAYS_16_BIT:
format = D3DFMT_A1R5G5B5; break;
case ETCF_ALWAYS_32_BIT:
format = D3DFMT_A8R8G8B8; break;
case ETCF_OPTIMIZED_FOR_QUALITY:
{
switch(image->getColorFormat())
{
case ECF_R8G8B8:
case ECF_A8R8G8B8:
format = D3DFMT_A8R8G8B8; break;
case ECF_A1R5G5B5:
case ECF_R5G6B5:
format = D3DFMT_A1R5G5B5; break;
}
}
break;
case ETCF_OPTIMIZED_FOR_SPEED:
format = D3DFMT_A1R5G5B5;
break;
default:
break;
}
if (Driver->getTextureCreationFlag(video::ETCF_NO_ALPHA_CHANNEL))
{
if (format == D3DFMT_A8R8G8B8)
format = D3DFMT_R8G8B8;
else if (format == D3DFMT_A1R5G5B5)
format = D3DFMT_R5G6B5;
}
const bool mipmaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
DWORD usage = 0;
// This enables hardware mip map generation.
if (mipmaps && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
{
LPDIRECT3D9 intf = Driver->getExposedVideoData().D3D9.D3D9;
D3DDISPLAYMODE d3ddm;
intf->GetAdapterDisplayMode(Driver->Params.DisplayAdapter, &d3ddm);
if (D3D_OK==intf->CheckDeviceFormat(Driver->Params.DisplayAdapter,D3DDEVTYPE_HAL,d3ddm.Format,D3DUSAGE_AUTOGENMIPMAP,D3DRTYPE_TEXTURE,format))
{
usage = D3DUSAGE_AUTOGENMIPMAP;
HardwareMipMaps = true;
}
}
HRESULT hr = Device->CreateTexture(optSize.Width, optSize.Height,
mipmaps ? 0 : 1, // number of mipmaplevels (0 = automatic all)
usage, // usage
format, D3DPOOL_MANAGED , &Texture, NULL);
if (FAILED(hr))
{
// try brute force 16 bit
HardwareMipMaps = false;
if (format == D3DFMT_A8R8G8B8)
format = D3DFMT_A1R5G5B5;
else if (format == D3DFMT_R8G8B8)
format = D3DFMT_R5G6B5;
else
return false;
hr = Device->CreateTexture(optSize.Width, optSize.Height,
mipmaps ? 0 : 1, // number of mipmaplevels (0 = automatic all)
0, format, D3DPOOL_MANAGED, &Texture, NULL);
}
ColorFormat = Driver->getColorFormatFromD3DFormat(format);
setPitch(format);
return (SUCCEEDED(hr));
}
//! copies the image to the texture
bool CD3D9Texture::copyTexture(IImage * image)
{
if (Texture && image)
{
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
TextureSize.Width = desc.Width;
TextureSize.Height = desc.Height;
D3DLOCKED_RECT rect;
HRESULT hr = Texture->LockRect(0, &rect, 0, 0);
if (FAILED(hr))
{
os::Printer::log("Texture data not copied", "Could not LockRect D3D9 Texture.", ELL_ERROR);
return false;
}
Pitch = rect.Pitch;
image->copyToScaling(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch);
hr = Texture->UnlockRect(0);
if (FAILED(hr))
{
os::Printer::log("Texture data not copied", "Could not UnlockRect D3D9 Texture.", ELL_ERROR);
return false;
}
}
return true;
}
//! lock function
void* CD3D9Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
{
if (!Texture)
return 0;
MipLevelLocked=mipmapLevel;
HRESULT hr;
D3DLOCKED_RECT rect;
if(!IsRenderTarget)
{
hr = Texture->LockRect(mipmapLevel, &rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR);
return 0;
}
}
else
{
if (!RTTSurface)
{
// Make RTT surface large enough for all miplevels (including 0)
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
hr = Device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &RTTSurface, 0);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Offscreen surface creation failed.", ELL_ERROR);
return 0;
}
}
IDirect3DSurface9 *surface = 0;
hr = Texture->GetSurfaceLevel(mipmapLevel, &surface);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Could not get surface.", ELL_ERROR);
return 0;
}
hr = Device->GetRenderTargetData(surface, RTTSurface);
surface->Release();
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Data copy failed.", ELL_ERROR);
return 0;
}
hr = RTTSurface->LockRect(&rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0);
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR);
return 0;
}
}
return rect.pBits;
}
//! unlock function
void CD3D9Texture::unlock()
{
if (!Texture)
return;
if (!IsRenderTarget)
Texture->UnlockRect(MipLevelLocked);
else if (RTTSurface)
RTTSurface->UnlockRect();
}
//! Returns original size of the texture.
const core::dimension2d<u32>& CD3D9Texture::getOriginalSize() const
{
return ImageSize;
}
//! Returns (=size) of the texture.
const core::dimension2d<u32>& CD3D9Texture::getSize() const
{
return TextureSize;
}
//! returns driver type of texture (=the driver, who created the texture)
E_DRIVER_TYPE CD3D9Texture::getDriverType() const
{
return EDT_DIRECT3D9;
}
//! returns color format of texture
ECOLOR_FORMAT CD3D9Texture::getColorFormat() const
{
return ColorFormat;
}
//! returns pitch of texture (in bytes)
u32 CD3D9Texture::getPitch() const
{
return Pitch;
}
//! returns the DIRECT3D9 Texture
IDirect3DBaseTexture9* CD3D9Texture::getDX9Texture() const
{
return Texture;
}
//! returns if texture has mipmap levels
bool CD3D9Texture::hasMipMaps() const
{
return HasMipMaps;
}
void CD3D9Texture::copy16BitMipMap(char* src, char* tgt,
s32 width, s32 height,
s32 pitchsrc, s32 pitchtgt) const
{
for (s32 y=0; y<height; ++y)
{
for (s32 x=0; x<width; ++x)
{
u32 a=0, r=0, g=0, b=0;
for (s32 dy=0; dy<2; ++dy)
{
const s32 tgy = (y*2)+dy;
for (s32 dx=0; dx<2; ++dx)
{
const s32 tgx = (x*2)+dx;
SColor c;
if (ColorFormat == ECF_A1R5G5B5)
c = A1R5G5B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
else
c = R5G6B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
a += c.getAlpha();
r += c.getRed();
g += c.getGreen();
b += c.getBlue();
}
}
a /= 4;
r /= 4;
g /= 4;
b /= 4;
u16 c;
if (ColorFormat == ECF_A1R5G5B5)
c = RGBA16(r,g,b,a);
else
c = A8R8G8B8toR5G6B5(SColor(a,r,g,b).color);
*(u16*)(&tgt[(x*2)+(y*pitchtgt)]) = c;
}
}
}
void CD3D9Texture::copy32BitMipMap(char* src, char* tgt,
s32 width, s32 height,
s32 pitchsrc, s32 pitchtgt) const
{
for (s32 y=0; y<height; ++y)
{
for (s32 x=0; x<width; ++x)
{
u32 a=0, r=0, g=0, b=0;
SColor c;
for (s32 dy=0; dy<2; ++dy)
{
const s32 tgy = (y*2)+dy;
for (s32 dx=0; dx<2; ++dx)
{
const s32 tgx = (x*2)+dx;
c = *(u32*)(&src[(tgx*4)+(tgy*pitchsrc)]);
a += c.getAlpha();
r += c.getRed();
g += c.getGreen();
b += c.getBlue();
}
}
a /= 4;
r /= 4;
g /= 4;
b /= 4;
c.set(a, r, g, b);
*(u32*)(&tgt[(x*4)+(y*pitchtgt)]) = c.color;
}
}
}
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void CD3D9Texture::regenerateMipMapLevels(void* mipmapData)
{
if (mipmapData)
{
core::dimension2du size = TextureSize;
u32 level=0;
do
{
if (size.Width>1)
size.Width /=2;
if (size.Height>1)
size.Height /=2;
++level;
IDirect3DSurface9* mipSurface = 0;
HRESULT hr = Texture->GetSurfaceLevel(level, &mipSurface);
if (FAILED(hr) || !mipSurface)
{
os::Printer::log("Could not get mipmap level", ELL_WARNING);
return;
}
D3DSURFACE_DESC mipDesc;
mipSurface->GetDesc(&mipDesc);
D3DLOCKED_RECT miplr;
// lock mipmap surface
if (FAILED(mipSurface->LockRect(&miplr, NULL, 0)))
{
mipSurface->Release();
os::Printer::log("Could not lock texture", ELL_WARNING);
return;
}
memcpy(miplr.pBits, mipmapData, size.getArea()*getPitch()/TextureSize.Width);
mipmapData = (u8*)mipmapData+size.getArea()*getPitch()/TextureSize.Width;
// unlock
mipSurface->UnlockRect();
// release
mipSurface->Release();
} while (size.Width != 1 || size.Height != 1);
}
else if (HasMipMaps)
{
// create mip maps.
#ifdef _IRR_USE_D3DXFilterTexture_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation
HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT, D3DX_DEFAULT);
if (FAILED(hr))
#endif
createMipMaps();
}
}
//! returns if it is a render target
bool CD3D9Texture::isRenderTarget() const
{
return IsRenderTarget;
}
//! Returns pointer to the render target surface
IDirect3DSurface9* CD3D9Texture::getRenderTargetSurface()
{
if (!IsRenderTarget)
return 0;
IDirect3DSurface9 *pRTTSurface = 0;
if (Texture)
Texture->GetSurfaceLevel(0, &pRTTSurface);
if (pRTTSurface)
pRTTSurface->Release();
return pRTTSurface;
}
void CD3D9Texture::setPitch(D3DFORMAT d3dformat)
{
switch(d3dformat)
{
case D3DFMT_X1R5G5B5:
case D3DFMT_A1R5G5B5:
Pitch = TextureSize.Width * 2;
break;
case D3DFMT_A8B8G8R8:
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
Pitch = TextureSize.Width * 4;
break;
case D3DFMT_R5G6B5:
Pitch = TextureSize.Width * 2;
break;
case D3DFMT_R8G8B8:
Pitch = TextureSize.Width * 3;
break;
default:
Pitch = 0;
};
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
+132
View File
@@ -0,0 +1,132 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DIRECTX9_TEXTURE_H_INCLUDED__
#define __C_DIRECTX9_TEXTURE_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "ITexture.h"
#include "IImage.h"
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
namespace irr
{
namespace video
{
class CD3D9Driver;
// forward declaration for RTT depth buffer handling
struct SDepthSurface;
/*!
interface for a Video Driver dependent Texture.
*/
class CD3D9Texture : public ITexture
{
public:
//! constructor
CD3D9Texture(IImage* image, CD3D9Driver* driver,
u32 flags, const io::path& name, void* mipmapData=0);
//! rendertarget constructor
CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size, const io::path& name,
const ECOLOR_FORMAT format = ECF_UNKNOWN);
//! destructor
virtual ~CD3D9Texture();
//! lock function
virtual void* lock(E_TEXTURE_LOCK_MODE mode=ETLM_READ_WRITE, u32 mipmapLevel=0);
//! unlock function
virtual void unlock();
//! Returns original size of the texture.
virtual const core::dimension2d<u32>& getOriginalSize() const;
//! Returns (=size) of the texture.
virtual const core::dimension2d<u32>& getSize() const;
//! returns driver type of texture (=the driver, who created the texture)
virtual E_DRIVER_TYPE getDriverType() const;
//! returns color format of texture
virtual ECOLOR_FORMAT getColorFormat() const;
//! returns pitch of texture (in bytes)
virtual u32 getPitch() const;
//! returns the DIRECT3D9 Texture
IDirect3DBaseTexture9* getDX9Texture() const;
//! returns if texture has mipmap levels
bool hasMipMaps() const;
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! returns if it is a render target
virtual bool isRenderTarget() const;
//! Returns pointer to the render target surface
IDirect3DSurface9* getRenderTargetSurface();
u64 getTextureHandler() const { return (u64)Texture; }
private:
friend class CD3D9Driver;
void createRenderTarget(const ECOLOR_FORMAT format = ECF_UNKNOWN);
//! creates the hardware texture
bool createTexture(u32 flags, IImage * image);
//! copies the image to the texture
bool copyTexture(IImage * image);
//! Helper function for mipmap generation.
bool createMipMaps(u32 level=1);
//! Helper function for mipmap generation.
void copy16BitMipMap(char* src, char* tgt,
s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const;
//! Helper function for mipmap generation.
void copy32BitMipMap(char* src, char* tgt,
s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const;
//! set Pitch based on the d3d format
void setPitch(D3DFORMAT d3dformat);
IDirect3DDevice9* Device;
IDirect3DTexture9* Texture;
IDirect3DSurface9* RTTSurface;
CD3D9Driver* Driver;
SDepthSurface* DepthSurface;
core::dimension2d<u32> TextureSize;
core::dimension2d<u32> ImageSize;
s32 Pitch;
u32 MipLevelLocked;
ECOLOR_FORMAT ColorFormat;
bool HasMipMaps;
bool HardwareMipMaps;
bool IsRenderTarget;
};
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
#endif // __C_DIRECTX9_TEXTURE_H_INCLUDED__
@@ -0,0 +1,164 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultGUIElementFactory.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IGUIButton.h"
#include "IGUICheckBox.h"
#include "IGUIColorSelectDialog.h"
#include "IGUIComboBox.h"
#include "IGUIContextMenu.h"
#include "IGUIEditBox.h"
#include "IGUIFileOpenDialog.h"
#include "IGUIInOutFader.h"
#include "IGUIImage.h"
#include "IGUIListBox.h"
#include "IGUIMeshViewer.h"
#include "IGUIScrollBar.h"
#include "IGUISpinBox.h"
#include "IGUIStaticText.h"
#include "IGUITabControl.h"
#include "IGUITable.h"
#include "IGUIToolbar.h"
#include "IGUIWindow.h"
#include "IGUITreeView.h"
namespace irr
{
namespace gui
{
CDefaultGUIElementFactory::CDefaultGUIElementFactory(IGUIEnvironment* env)
: Environment(env)
{
#ifdef _DEBUG
setDebugName("CDefaultGUIElementFactory");
#endif
// don't grab the gui environment here to prevent cyclic references
}
//! adds an element to the env based on its type id
IGUIElement* CDefaultGUIElementFactory::addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent)
{
switch(type)
{
case EGUIET_BUTTON:
return Environment->addButton(core::rect<s32>(0,0,100,100),parent);
case EGUIET_CHECK_BOX:
return Environment->addCheckBox(false, core::rect<s32>(0,0,100,100), parent);
case EGUIET_COLOR_SELECT_DIALOG:
return Environment->addColorSelectDialog(0,true,parent);
case EGUIET_COMBO_BOX:
return Environment->addComboBox(core::rect<s32>(0,0,100,100),parent);
case EGUIET_CONTEXT_MENU:
return Environment->addContextMenu(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MENU:
return Environment->addMenu(parent);
case EGUIET_EDIT_BOX:
return Environment->addEditBox(0,core::rect<s32>(0,0,100,100),true, parent);
case EGUIET_FILE_OPEN_DIALOG:
return Environment->addFileOpenDialog(0,true,parent);
case EGUIET_IMAGE:
return Environment->addImage(0,core::position2di(0,0), true, parent);
case EGUIET_IN_OUT_FADER:
return Environment->addInOutFader(0,parent);
case EGUIET_LIST_BOX:
return Environment->addListBox(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MESH_VIEWER:
return Environment->addMeshViewer(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MODAL_SCREEN:
return Environment->addModalScreen(parent);
case EGUIET_MESSAGE_BOX:
return Environment->addMessageBox(0,0,false,0,parent);
case EGUIET_SCROLL_BAR:
return Environment->addScrollBar(false,core::rect<s32>(0,0,100,100),parent);
case EGUIET_STATIC_TEXT:
return Environment->addStaticText(L"",core::rect<s32>(0,0,100,100),false,true,parent);
case EGUIET_TAB:
return Environment->addTab(core::rect<s32>(0,0,100,100),parent);
case EGUIET_TAB_CONTROL:
return Environment->addTabControl(core::rect<s32>(0,0,100,100),parent);
case EGUIET_TABLE:
return Environment->addTable(core::rect<s32>(0,0,100,100), parent);
case EGUIET_TOOL_BAR:
return Environment->addToolBar(parent);
case EGUIET_WINDOW:
return Environment->addWindow(core::rect<s32>(0,0,100,100),false,0,parent);
case EGUIET_SPIN_BOX:
return Environment->addSpinBox(L"0.0", core::rect<s32>(0,0,100,100), true, parent);
case EGUIET_TREE_VIEW:
return Environment->addTreeView(core::rect<s32>(0,0,100,100),parent);
default:
return 0;
}
}
//! adds an element to the environment based on its type name
IGUIElement* CDefaultGUIElementFactory::addGUIElement(const c8* typeName, IGUIElement* parent)
{
return addGUIElement( getTypeFromName(typeName), parent );
}
//! Returns the amount of element types this factory is able to create.
s32 CDefaultGUIElementFactory::getCreatableGUIElementTypeCount() const
{
return EGUIET_COUNT;
}
//! Returns the type of a createable element type.
EGUI_ELEMENT_TYPE CDefaultGUIElementFactory::getCreateableGUIElementType(s32 idx) const
{
if (idx>=0 && idx<EGUIET_COUNT)
return (EGUI_ELEMENT_TYPE)idx;
return EGUIET_ELEMENT;
}
//! Returns the type name of a createable element type.
const c8* CDefaultGUIElementFactory::getCreateableGUIElementTypeName(s32 idx) const
{
if (idx>=0 && idx<EGUIET_COUNT)
return GUIElementTypeNames[idx];
return 0;
}
//! Returns the type name of a createable element type.
const c8* CDefaultGUIElementFactory::getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const
{
// for this factory, type == index
if (type>=0 && type<EGUIET_COUNT)
return GUIElementTypeNames[type];
return 0;
}
EGUI_ELEMENT_TYPE CDefaultGUIElementFactory::getTypeFromName(const c8* name) const
{
for ( u32 i=0; GUIElementTypeNames[i]; ++i)
if (!strcmp(name, GUIElementTypeNames[i]) )
return (EGUI_ELEMENT_TYPE)i;
return EGUIET_ELEMENT;
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,70 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__
#define __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIElementFactory.h"
namespace irr
{
namespace gui
{
class IGUIElement;
class IGUIEnvironment;
//! This interface makes it possible to dynamically create gui elements.
class CDefaultGUIElementFactory : public IGUIElementFactory
{
public:
CDefaultGUIElementFactory(IGUIEnvironment* env);
//! Adds an element to the gui environment based on its type id.
/** \param type: Type of the element to add.
\param parent: Parent scene node of the new element. A value of 0 adds it to the root.
\return Returns pointer to the new element or 0 if unsuccessful. */
virtual IGUIElement* addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent=0);
//! Adds a GUI element to the GUI Environment based on its type name.
/** \param typeName: Type name of the element to add. Taken from the GUIElementTypeNames c8* array.
\param parent: Parent scene node of the new element. A value of 0 adds it to the root.
\return Returns pointer to the new element or 0 if unsuccessful. */
virtual IGUIElement* addGUIElement(const c8* typeName, IGUIElement* parent=0);
//! Returns the amount of GUI element types this factory is able to create.
virtual s32 getCreatableGUIElementTypeCount() const;
//! Returns the type of a createable GUI element type based on the index.
/** \param idx: Index of the element type in this factory. The value must be equal or greater than 0
and lower than getCreatableGUIElementTypeCount(). */
virtual EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const;
//! Returns the type name of a createable GUI element type based on the index.
/** \param idx: Index of the element type in this factory. The value must be equal or greater than 0
and lower than getCreatableGUIElementTypeCount(). */
virtual const c8* getCreateableGUIElementTypeName(s32 idx) const;
//! Returns the type name of a createable GUI element based on its type.
/** \param type: Type of the GUI element.
\return: Returns the name of the type if this factory can create it, otherwise it returns 0. */
virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const;
private:
EGUI_ELEMENT_TYPE getTypeFromName(const c8* name) const;
IGUIEnvironment* Environment;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__
@@ -0,0 +1,162 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultSceneNodeAnimatorFactory.h"
#include "CSceneNodeAnimatorCameraFPS.h"
#include "CSceneNodeAnimatorCameraMaya.h"
#include "ICursorControl.h"
#include "ISceneNodeAnimatorCollisionResponse.h"
#include "ISceneManager.h"
namespace irr
{
namespace scene
{
//! Names for scene node types
const c8* const SceneNodeAnimatorTypeNames[] =
{
"flyCircle",
"flyStraight",
"followSpline",
"rotation",
"texture",
"deletion",
"collisionResponse",
"cameraFPS",
"cameraMaya",
0
};
CDefaultSceneNodeAnimatorFactory::CDefaultSceneNodeAnimatorFactory(ISceneManager* mgr, gui::ICursorControl* crs)
: Manager(mgr), CursorControl(crs)
{
#ifdef _DEBUG
setDebugName("CDefaultSceneNodeAnimatorFactory");
#endif
// don't grab the scene manager here to prevent cyclic references
if (CursorControl)
CursorControl->grab();
}
CDefaultSceneNodeAnimatorFactory::~CDefaultSceneNodeAnimatorFactory()
{
if (CursorControl)
CursorControl->drop();
}
//! creates a scene node animator based on its type id
ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target)
{
scene::ISceneNodeAnimator* anim = 0;
switch(type)
{
case ESNAT_FLY_CIRCLE:
anim = Manager->createFlyCircleAnimator(core::vector3df(0,0,0), 10);
break;
case ESNAT_FLY_STRAIGHT:
anim = Manager->createFlyStraightAnimator(core::vector3df(0,0,0), core::vector3df(100,100,100), 10000, true );
break;
case ESNAT_FOLLOW_SPLINE:
{
core::array<core::vector3df> points;
points.push_back(core::vector3df(0,0,0));
points.push_back(core::vector3df(10,5,10));
anim = Manager->createFollowSplineAnimator(0, points);
}
break;
case ESNAT_ROTATION:
anim = Manager->createRotationAnimator(core::vector3df(0.3f,0,0));
break;
case ESNAT_TEXTURE:
{
core::array<video::ITexture*> textures;
anim = Manager->createTextureAnimator(textures, 250);
}
break;
case ESNAT_DELETION:
anim = Manager->createDeleteAnimator(5000);
break;
case ESNAT_COLLISION_RESPONSE:
anim = Manager->createCollisionResponseAnimator(0, target);
break;
case ESNAT_CAMERA_FPS:
anim = new CSceneNodeAnimatorCameraFPS(CursorControl);
break;
case ESNAT_CAMERA_MAYA:
anim = new CSceneNodeAnimatorCameraMaya(CursorControl);
break;
default:
break;
}
if (anim && target)
target->addAnimator(anim);
return anim;
}
//! creates a scene node animator based on its type name
ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(const c8* typeName, ISceneNode* target)
{
return createSceneNodeAnimator( getTypeFromName(typeName), target );
}
//! returns amount of scene node animator types this factory is able to create
u32 CDefaultSceneNodeAnimatorFactory::getCreatableSceneNodeAnimatorTypeCount() const
{
return ESNAT_COUNT;
}
//! returns type of a createable scene node animator type
ESCENE_NODE_ANIMATOR_TYPE CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorType(u32 idx) const
{
if (idx<ESNAT_COUNT)
return (ESCENE_NODE_ANIMATOR_TYPE)idx;
else
return ESNAT_UNKNOWN;
}
//! returns type name of a createable scene node animator type
const c8* CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorTypeName(u32 idx) const
{
if (idx<ESNAT_COUNT)
return SceneNodeAnimatorTypeNames[idx];
else
return 0;
}
//! returns type name of a createable scene node animator type
const c8* CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const
{
// for this factory: index == type
if (type<ESNAT_COUNT)
return SceneNodeAnimatorTypeNames[type];
else
return 0;
}
ESCENE_NODE_ANIMATOR_TYPE CDefaultSceneNodeAnimatorFactory::getTypeFromName(const c8* name) const
{
for ( u32 i=0; SceneNodeAnimatorTypeNames[i]; ++i)
if (!strcmp(name, SceneNodeAnimatorTypeNames[i]) )
return (ESCENE_NODE_ANIMATOR_TYPE)i;
return ESNAT_UNKNOWN;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,75 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_SCENE_NODE_ANIMATOR_FACTORY_H_INCLUDED__
#define __C_DEFAULT_SCENE_NODE_ANIMATOR_FACTORY_H_INCLUDED__
#include "ISceneNodeAnimatorFactory.h"
namespace irr
{
namespace gui
{
class ICursorControl;
}
namespace scene
{
class ISceneNodeAnimator;
class ISceneManager;
//! Interface making it possible to dynamicly create scene nodes animators
class CDefaultSceneNodeAnimatorFactory : public ISceneNodeAnimatorFactory
{
public:
CDefaultSceneNodeAnimatorFactory(ISceneManager* mgr, gui::ICursorControl* crs);
virtual ~CDefaultSceneNodeAnimatorFactory();
//! creates a scene node animator based on its type id
/** \param type: Type of the scene node animator to add.
\param target: Target scene node of the new animator.
\return Returns pointer to the new scene node animator or null if not successful. You need to
drop this pointer after calling this, see IReferenceCounted::drop() for details. */
virtual ISceneNodeAnimator* createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target);
//! creates a scene node animator based on its type name
/** \param typeName: Type of the scene node animator to add.
\param target: Target scene node of the new animator.
\return Returns pointer to the new scene node animator or null if not successful. You need to
drop this pointer after calling this, see IReferenceCounted::drop() for details. */
virtual ISceneNodeAnimator* createSceneNodeAnimator(const char* typeName, ISceneNode* target);
//! returns amount of scene node animator types this factory is able to create
virtual u32 getCreatableSceneNodeAnimatorTypeCount() const;
//! returns type of a createable scene node animator type
/** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and
getCreatableSceneNodeTypeCount() */
virtual ESCENE_NODE_ANIMATOR_TYPE getCreateableSceneNodeAnimatorType(u32 idx) const;
//! returns type name of a createable scene node animator type
/** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and
getCreatableSceneNodeAnimatorTypeCount() */
virtual const c8* getCreateableSceneNodeAnimatorTypeName(u32 idx) const;
//! returns type name of a createable scene node animator type
/** \param type: Type of scene node animator.
\return: Returns name of scene node animator type if this factory can create the type, otherwise 0. */
virtual const c8* getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const;
private:
ESCENE_NODE_ANIMATOR_TYPE getTypeFromName(const c8* name) const;
ISceneManager* Manager;
gui::ICursorControl* CursorControl;
};
} // end namespace scene
} // end namespace irr
#endif
@@ -0,0 +1,175 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultSceneNodeFactory.h"
#include "ISceneManager.h"
#include "ITextSceneNode.h"
#include "ITerrainSceneNode.h"
#include "IDummyTransformationSceneNode.h"
#include "ICameraSceneNode.h"
#include "IBillboardSceneNode.h"
#include "IAnimatedMeshSceneNode.h"
#include "IParticleSystemSceneNode.h"
#include "ILightSceneNode.h"
#include "IMeshSceneNode.h"
namespace irr
{
namespace scene
{
CDefaultSceneNodeFactory::CDefaultSceneNodeFactory(ISceneManager* mgr)
: Manager(mgr)
{
#ifdef _DEBUG
setDebugName("CDefaultSceneNodeFactory");
#endif
// don't grab the scene manager here to prevent cyclic references
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CUBE, "cube"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SPHERE, "sphere"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TEXT, "text"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_WATER_SURFACE, "waterSurface"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TERRAIN, "terrain"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SKY_BOX, "skyBox"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SKY_DOME, "skyDome"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SHADOW_VOLUME, "shadowVolume"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_OCTREE, "octree"));
// Legacy support
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_OCTREE, "octTree"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_MESH, "mesh"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_LIGHT, "light"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_EMPTY, "empty"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_DUMMY_TRANSFORMATION, "dummyTransformation"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA, "camera"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_BILLBOARD, "billBoard"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_ANIMATED_MESH, "animatedMesh"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_PARTICLE_SYSTEM, "particleSystem"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_VOLUME_LIGHT, "volumeLight"));
// SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_MD3_SCENE_NODE, "md3"));
// legacy, for version <= 1.4.x irr files
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA_MAYA, "cameraMaya"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA_FPS, "cameraFPS"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_Q3SHADER_SCENE_NODE, "quake3Shader"));
}
//! adds a scene node to the scene graph based on its type id
ISceneNode* CDefaultSceneNodeFactory::addSceneNode(ESCENE_NODE_TYPE type, ISceneNode* parent)
{
switch(type)
{
case ESNT_CUBE:
return Manager->addCubeSceneNode(10, parent);
case ESNT_SPHERE:
return Manager->addSphereSceneNode(5, 16, parent);
case ESNT_TEXT:
return Manager->addTextSceneNode(0, L"example");
case ESNT_WATER_SURFACE:
return Manager->addWaterSurfaceSceneNode(0, 2.0f, 300.0f, 10.0f, parent);
case ESNT_TERRAIN:
return Manager->addTerrainSceneNode("", parent, -1,
core::vector3df(0.0f,0.0f,0.0f),
core::vector3df(0.0f,0.0f,0.0f),
core::vector3df(1.0f,1.0f,1.0f),
video::SColor(255,255,255,255),
4, ETPS_17, 0, true);
case ESNT_SKY_BOX:
return Manager->addSkyBoxSceneNode(0,0,0,0,0,0, parent);
case ESNT_SHADOW_VOLUME:
return 0;
case ESNT_OCTREE:
return Manager->addOctreeSceneNode((IMesh*)0, parent, -1, 128, true);
case ESNT_MESH:
return Manager->addMeshSceneNode(0, parent, -1, core::vector3df(),
core::vector3df(), core::vector3df(1,1,1), true);
case ESNT_LIGHT:
return Manager->addLightSceneNode(parent);
case ESNT_EMPTY:
return Manager->addEmptySceneNode(parent);
case ESNT_DUMMY_TRANSFORMATION:
return Manager->addDummyTransformationSceneNode(parent);
case ESNT_CAMERA:
return Manager->addCameraSceneNode(parent);
case ESNT_CAMERA_MAYA:
return Manager->addCameraSceneNodeMaya(parent);
case ESNT_CAMERA_FPS:
return Manager->addCameraSceneNodeFPS(parent);
case ESNT_BILLBOARD:
return Manager->addBillboardSceneNode(parent);
case ESNT_ANIMATED_MESH:
return Manager->addAnimatedMeshSceneNode(0, parent, -1, core::vector3df(),
core::vector3df(), core::vector3df(1,1,1), true);
case ESNT_PARTICLE_SYSTEM:
return Manager->addParticleSystemSceneNode(true, parent);
default:
break;
}
return 0;
}
//! adds a scene node to the scene graph based on its type name
ISceneNode* CDefaultSceneNodeFactory::addSceneNode(const c8* typeName, ISceneNode* parent)
{
return addSceneNode( getTypeFromName(typeName), parent );
}
//! returns amount of scene node types this factory is able to create
u32 CDefaultSceneNodeFactory::getCreatableSceneNodeTypeCount() const
{
return SupportedSceneNodeTypes.size();
}
//! returns type of a createable scene node type
ESCENE_NODE_TYPE CDefaultSceneNodeFactory::getCreateableSceneNodeType(u32 idx) const
{
if (idx<SupportedSceneNodeTypes.size())
return SupportedSceneNodeTypes[idx].Type;
else
return ESNT_UNKNOWN;
}
//! returns type name of a createable scene node type
const c8* CDefaultSceneNodeFactory::getCreateableSceneNodeTypeName(u32 idx) const
{
if (idx<SupportedSceneNodeTypes.size())
return SupportedSceneNodeTypes[idx].TypeName.c_str();
else
return 0;
}
//! returns type name of a createable scene node type
const c8* CDefaultSceneNodeFactory::getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const
{
for (u32 i=0; i<SupportedSceneNodeTypes.size(); ++i)
if (SupportedSceneNodeTypes[i].Type == type)
return SupportedSceneNodeTypes[i].TypeName.c_str();
return 0;
}
ESCENE_NODE_TYPE CDefaultSceneNodeFactory::getTypeFromName(const c8* name) const
{
for (u32 i=0; i<SupportedSceneNodeTypes.size(); ++i)
if (SupportedSceneNodeTypes[i].TypeName == name)
return SupportedSceneNodeTypes[i].Type;
return ESNT_UNKNOWN;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,80 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_SCENE_NODE_FACTORY_H_INCLUDED__
#define __C_DEFAULT_SCENE_NODE_FACTORY_H_INCLUDED__
#include "ISceneNodeFactory.h"
#include "irrArray.h"
#include "irrString.h"
namespace irr
{
namespace scene
{
class ISceneNode;
class ISceneManager;
//! Interface making it possible to dynamicly create scene nodes and animators
class CDefaultSceneNodeFactory : public ISceneNodeFactory
{
public:
CDefaultSceneNodeFactory(ISceneManager* mgr);
//! adds a scene node to the scene graph based on its type id
/** \param type: Type of the scene node to add.
\param parent: Parent scene node of the new node, can be null to add the scene node to the root.
\return Returns pointer to the new scene node or null if not successful. */
virtual ISceneNode* addSceneNode(ESCENE_NODE_TYPE type, ISceneNode* parent=0);
//! adds a scene node to the scene graph based on its type name
/** \param typeName: Type name of the scene node to add.
\param parent: Parent scene node of the new node, can be null to add the scene node to the root.
\return Returns pointer to the new scene node or null if not successful. */
virtual ISceneNode* addSceneNode(const c8* typeName, ISceneNode* parent=0);
//! returns amount of scene node types this factory is able to create
virtual u32 getCreatableSceneNodeTypeCount() const;
//! returns type name of a createable scene node type by index
/** \param idx: Index of scene node type in this factory. Must be a value between 0 and
uetCreatableSceneNodeTypeCount() */
virtual const c8* getCreateableSceneNodeTypeName(u32 idx) const;
//! returns type of a createable scene node type
/** \param idx: Index of scene node type in this factory. Must be a value between 0 and
getCreatableSceneNodeTypeCount() */
virtual ESCENE_NODE_TYPE getCreateableSceneNodeType(u32 idx) const;
//! returns type name of a createable scene node type
/** \param idx: Type of scene node.
\return: Returns name of scene node type if this factory can create the type, otherwise 0. */
virtual const c8* getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const;
private:
ESCENE_NODE_TYPE getTypeFromName(const c8* name) const;
struct SSceneNodeTypePair
{
SSceneNodeTypePair(ESCENE_NODE_TYPE type, const c8* name)
: Type(type), TypeName(name)
{}
ESCENE_NODE_TYPE Type;
core::stringc TypeName;
};
core::array<SSceneNodeTypePair> SupportedSceneNodeTypes;
ISceneManager* Manager;
};
} // end namespace scene
} // end namespace irr
#endif
@@ -0,0 +1,105 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDummyTransformationSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CDummyTransformationSceneNode::CDummyTransformationSceneNode(
ISceneNode* parent, ISceneManager* mgr, s32 id)
: IDummyTransformationSceneNode(parent, mgr, id)
{
#ifdef _DEBUG
setDebugName("CDummyTransformationSceneNode");
#endif
setAutomaticCulling(scene::EAC_OFF);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CDummyTransformationSceneNode::getBoundingBox() const
{
return Box;
}
//! Returns a reference to the current relative transformation matrix.
//! This is the matrix, this scene node uses instead of scale, translation
//! and rotation.
core::matrix4& CDummyTransformationSceneNode::getRelativeTransformationMatrix()
{
return RelativeTransformationMatrix;
}
//! Returns the relative transformation of the scene node.
core::matrix4 CDummyTransformationSceneNode::getRelativeTransformation() const
{
return RelativeTransformationMatrix;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CDummyTransformationSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CDummyTransformationSceneNode* nb = new CDummyTransformationSceneNode(newParent,
newManager, ID);
nb->cloneMembers(this, newManager);
nb->RelativeTransformationMatrix = RelativeTransformationMatrix;
nb->Box = Box;
if ( newParent )
nb->drop();
return nb;
}
const core::vector3df& CDummyTransformationSceneNode::getScale() const
{
os::Printer::log("CDummyTransformationSceneNode::getScale() does not contain the relative transformation.", ELL_DEBUG);
return RelativeScale;
}
void CDummyTransformationSceneNode::setScale(const core::vector3df& scale)
{
os::Printer::log("CDummyTransformationSceneNode::setScale() does not affect the relative transformation.", ELL_DEBUG);
RelativeScale = scale;
}
const core::vector3df& CDummyTransformationSceneNode::getRotation() const
{
os::Printer::log("CDummyTransformationSceneNode::getRotation() does not contain the relative transformation.", ELL_DEBUG);
return RelativeRotation;
}
void CDummyTransformationSceneNode::setRotation(const core::vector3df& rotation)
{
os::Printer::log("CDummyTransformationSceneNode::setRotation() does not affect the relative transformation.", ELL_DEBUG);
RelativeRotation = rotation;
}
const core::vector3df& CDummyTransformationSceneNode::getPosition() const
{
os::Printer::log("CDummyTransformationSceneNode::getPosition() does not contain the relative transformation.", ELL_DEBUG);
return RelativeTranslation;
}
void CDummyTransformationSceneNode::setPosition(const core::vector3df& newpos)
{
os::Printer::log("CDummyTransformationSceneNode::setPosition() does not affect the relative transformation.", ELL_DEBUG);
RelativeTranslation = newpos;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,62 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__
#define __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__
#include "IDummyTransformationSceneNode.h"
namespace irr
{
namespace scene
{
class CDummyTransformationSceneNode : public IDummyTransformationSceneNode
{
public:
//! constructor
CDummyTransformationSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id);
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! Returns a reference to the current relative transformation matrix.
//! This is the matrix, this scene node uses instead of scale, translation
//! and rotation.
virtual core::matrix4& getRelativeTransformationMatrix();
//! Returns the relative transformation of the scene node.
virtual core::matrix4 getRelativeTransformation() const;
//! does nothing.
virtual void render() {}
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_DUMMY_TRANSFORMATION; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
private:
// TODO: We can add least add some warnings to find troubles faster until we have
// fixed bug id 2318691.
virtual const core::vector3df& getScale() const;
virtual void setScale(const core::vector3df& scale);
virtual const core::vector3df& getRotation() const;
virtual void setRotation(const core::vector3df& rotation);
virtual const core::vector3df& getPosition() const;
virtual void setPosition(const core::vector3df& newpos);
core::matrix4 RelativeTransformationMatrix;
core::aabbox3d<f32> Box;
};
} // end namespace scene
} // end namespace irr
#endif
@@ -0,0 +1,70 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CEmptySceneNode.h"
#include "ISceneManager.h"
namespace irr
{
namespace scene
{
//! constructor
CEmptySceneNode::CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id)
: ISceneNode(parent, mgr, id)
{
#ifdef _DEBUG
setDebugName("CEmptySceneNode");
#endif
setAutomaticCulling(scene::EAC_OFF);
}
//! pre render event
void CEmptySceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CEmptySceneNode::render()
{
// do nothing
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CEmptySceneNode::getBoundingBox() const
{
return Box;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CEmptySceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CEmptySceneNode* nb = new CEmptySceneNode(newParent,
newManager, ID);
nb->cloneMembers(this, newManager);
nb->Box = Box;
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr
@@ -0,0 +1,46 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_EMPTY_SCENE_NODE_H_INCLUDED__
#define __C_EMPTY_SCENE_NODE_H_INCLUDED__
#include "ISceneNode.h"
namespace irr
{
namespace scene
{
class CEmptySceneNode : public ISceneNode
{
public:
//! constructor
CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id);
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! This method is called just before the rendering process of the whole scene.
virtual void OnRegisterSceneNode();
//! does nothing.
virtual void render();
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_EMPTY; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
private:
core::aabbox3d<f32> Box;
};
} // end namespace scene
} // end namespace irr
#endif
@@ -0,0 +1,76 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CFPSCounter.h"
#include "irrMath.h"
namespace irr
{
namespace video
{
CFPSCounter::CFPSCounter()
: FPS(60), Primitive(0), StartTime(0), FramesCounted(0),
PrimitivesCounted(0), PrimitiveAverage(0), PrimitiveTotal(0)
{
}
//! returns current fps
s32 CFPSCounter::getFPS() const
{
return FPS;
}
//! returns current primitive count
u32 CFPSCounter::getPrimitive() const
{
return Primitive;
}
//! returns average primitive count of last period
u32 CFPSCounter::getPrimitiveAverage() const
{
return PrimitiveAverage;
}
//! returns accumulated primitive count since start
u32 CFPSCounter::getPrimitiveTotal() const
{
return PrimitiveTotal;
}
//! to be called every frame
void CFPSCounter::registerFrame(u32 now, u32 primitivesDrawn)
{
++FramesCounted;
PrimitiveTotal += primitivesDrawn;
PrimitivesCounted += primitivesDrawn;
Primitive = primitivesDrawn;
const u32 milliseconds = now - StartTime;
if (milliseconds >= 1500 )
{
const f32 invMilli = core::reciprocal ( (f32) milliseconds );
FPS = core::ceil32 ( ( 1000 * FramesCounted ) * invMilli );
PrimitiveAverage = core::ceil32 ( ( 1000 * PrimitivesCounted ) * invMilli );
FramesCounted = 0;
PrimitivesCounted = 0;
StartTime = now;
}
}
} // end namespace video
} // end namespace irr
@@ -0,0 +1,54 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FPSCOUNTER_H_INCLUDED__
#define __C_FPSCOUNTER_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace video
{
class CFPSCounter
{
public:
CFPSCounter();
//! returns current fps
s32 getFPS() const;
//! returns primitive count
u32 getPrimitive() const;
//! returns average primitive count of last period
u32 getPrimitiveAverage() const;
//! returns accumulated primitive count since start
u32 getPrimitiveTotal() const;
//! to be called every frame
void registerFrame(u32 now, u32 primitive);
private:
s32 FPS;
u32 Primitive;
u32 StartTime;
u32 FramesCounted;
u32 PrimitivesCounted;
u32 PrimitiveAverage;
u32 PrimitiveTotal;
};
} // end namespace video
} // end namespace irr
#endif
+165
View File
@@ -0,0 +1,165 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CFileList.h"
#include "IrrCompileConfig.h"
#include "irrArray.h"
#include "coreutil.h"
#include "os.h"
namespace irr
{
namespace io
{
static const io::path emptyFileListEntry;
CFileList::CFileList(const io::path& path, bool ignoreCase, bool ignorePaths)
: IgnorePaths(ignorePaths), IgnoreCase(ignoreCase), Path(path)
{
#ifdef _DEBUG
setDebugName("CFileList");
#endif
Path.replace('\\', '/');
}
CFileList::~CFileList()
{
Files.clear();
}
u32 CFileList::getFileCount() const
{
return Files.size();
}
void CFileList::sort()
{
Files.sort();
}
const io::path& CFileList::getFileName(u32 index) const
{
if (index >= Files.size())
return emptyFileListEntry;
return Files[index].Name;
}
//! Gets the full name of a file in the list, path included, based on an index.
const io::path& CFileList::getFullFileName(u32 index) const
{
if (index >= Files.size())
return emptyFileListEntry;
return Files[index].FullName;
}
//! adds a file or folder
u32 CFileList::addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id)
{
SFileListEntry entry;
entry.ID = id ? id : Files.size();
entry.Offset = offset;
entry.Size = size;
entry.Name = fullPath;
entry.Name.replace('\\', '/');
entry.IsDirectory = isDirectory;
// remove trailing slash
if (entry.Name.lastChar() == '/')
{
entry.IsDirectory = true;
entry.Name[entry.Name.size()-1] = 0;
entry.Name.validate();
}
if (IgnoreCase)
entry.Name.make_lower();
entry.FullName = entry.Name;
core::deletePathFromFilename(entry.Name);
if (IgnorePaths)
entry.FullName = entry.Name;
//os::Printer::log(Path.c_str(), entry.FullName);
Files.push_back(entry);
return Files.size() - 1;
}
//! Returns the ID of a file in the file list, based on an index.
u32 CFileList::getID(u32 index) const
{
return index < Files.size() ? Files[index].ID : 0;
}
bool CFileList::isDirectory(u32 index) const
{
bool ret = false;
if (index < Files.size())
ret = Files[index].IsDirectory;
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ret;
}
//! Returns the size of a file
u32 CFileList::getFileSize(u32 index) const
{
return index < Files.size() ? Files[index].Size : 0;
}
//! Returns the size of a file
u32 CFileList::getFileOffset(u32 index) const
{
return index < Files.size() ? Files[index].Offset : 0;
}
//! Searches for a file or folder within the list, returns the index
s32 CFileList::findFile(const io::path& filename, bool isDirectory = false) const
{
SFileListEntry entry;
// we only need FullName to be set for the search
entry.FullName = filename;
entry.IsDirectory = isDirectory;
// exchange
entry.FullName.replace('\\', '/');
// remove trailing slash
if (entry.FullName.lastChar() == '/')
{
entry.IsDirectory = true;
entry.FullName[entry.FullName.size()-1] = 0;
entry.FullName.validate();
}
if (IgnoreCase)
entry.FullName.make_lower();
if (IgnorePaths)
core::deletePathFromFilename(entry.FullName);
return Files.binary_search(entry);
}
//! Returns the base path of the file list
const io::path& CFileList::getPath() const
{
return Path;
}
} // end namespace irr
} // end namespace io
+138
View File
@@ -0,0 +1,138 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FILE_LIST_H_INCLUDED__
#define __C_FILE_LIST_H_INCLUDED__
#include "IFileList.h"
#include "irrString.h"
#include "irrArray.h"
namespace irr
{
namespace io
{
//! An entry in a list of files, can be a folder or a file.
struct SFileListEntry
{
//! The name of the file
/** If this is a file or folder in the virtual filesystem and the archive
was created with the ignoreCase flag then the file name will be lower case. */
io::path Name;
//! The name of the file including the path
/** If this is a file or folder in the virtual filesystem and the archive was
created with the ignoreDirs flag then it will be the same as Name. */
io::path FullName;
//! The size of the file in bytes
u32 Size;
//! The ID of the file in an archive
/** This is used to link the FileList entry to extra info held about this
file in an archive, which can hold things like data offset and CRC. */
u32 ID;
//! FileOffset inside an archive
u32 Offset;
//! True if this is a folder, false if not.
bool IsDirectory;
//! The == operator is provided so that CFileList can slowly search the list!
bool operator ==(const struct SFileListEntry& other) const
{
if (IsDirectory != other.IsDirectory)
return false;
return FullName.equals_ignore_case(other.FullName);
}
//! The < operator is provided so that CFileList can sort and quickly search the list.
bool operator <(const struct SFileListEntry& other) const
{
if (IsDirectory != other.IsDirectory)
return IsDirectory;
return FullName.lower_ignore_case(other.FullName);
}
};
//! Implementation of a file list
class CFileList : public IFileList
{
public:
// CFileList methods
//! Constructor
/** \param path The path of this file archive */
CFileList(const io::path& path, bool ignoreCase, bool ignorePaths);
//! Destructor
virtual ~CFileList();
//! Add as a file or folder to the list
/** \param fullPath The file name including path, up to the root of the file list.
\param isDirectory True if this is a directory rather than a file.
\param offset The offset where the file is stored in an archive
\param size The size of the file in bytes.
\param id The ID of the file in the archive which owns it */
virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0);
//! Sorts the file list. You should call this after adding any items to the file list
virtual void sort();
//! Returns the amount of files in the filelist.
virtual u32 getFileCount() const;
//! Gets the name of a file in the list, based on an index.
virtual const io::path& getFileName(u32 index) const;
//! Gets the full name of a file in the list, path included, based on an index.
virtual const io::path& getFullFileName(u32 index) const;
//! Returns the ID of a file in the file list, based on an index.
virtual u32 getID(u32 index) const;
//! Returns true if the file is a directory
virtual bool isDirectory(u32 index) const;
//! Returns the size of a file
virtual u32 getFileSize(u32 index) const;
//! Returns the offest of a file
virtual u32 getFileOffset(u32 index) const;
//! Searches for a file or folder within the list, returns the index
virtual s32 findFile(const io::path& filename, bool isFolder) const;
//! Returns the base path of the file list
virtual const io::path& getPath() const;
protected:
//! Ignore paths when adding or searching for files
bool IgnorePaths;
//! Ignore case when adding or searching for files
bool IgnoreCase;
//! Path to the file list
io::path Path;
//! List of files
core::array<SFileListEntry> Files;
};
} // end namespace irr
} // end namespace io
#endif
File diff suppressed because it is too large Load Diff
+186
View File
@@ -0,0 +1,186 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FILE_SYSTEM_H_INCLUDED__
#define __C_FILE_SYSTEM_H_INCLUDED__
#include "IFileSystem.h"
#include "irrArray.h"
namespace irr
{
namespace io
{
class CZipReader;
class CPakReader;
class CMountPointReader;
/*!
FileSystem which uses normal files and one zipfile
*/
class CFileSystem : public IFileSystem
{
public:
//! constructor
CFileSystem();
//! destructor
virtual ~CFileSystem();
//! opens a file for read access
virtual IReadFile* createAndOpenFile(const io::path& filename);
//! Creates an IReadFile interface for accessing memory like a file.
virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped = false);
//! Creates an IReadFile interface for accessing files inside files
virtual IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize);
//! Creates an IWriteFile interface for accessing memory like a file.
virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped=false);
//! Opens a file for write access.
virtual IWriteFile* createAndWriteFile(const io::path& filename, bool append=false);
//! Adds an archive to the file system.
virtual bool addFileArchive(const io::path& filename,
bool ignoreCase = true, bool ignorePaths = true,
E_FILE_ARCHIVE_TYPE archiveType = EFAT_UNKNOWN,
const core::stringc& password="",
IFileArchive** retArchive = 0);
//! Adds an archive to the file system.
virtual bool addFileArchive(IReadFile* file, bool ignoreCase=true,
bool ignorePaths=true,
E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN,
const core::stringc& password="",
IFileArchive** retArchive = 0);
//! Adds an archive to the file system.
virtual bool addFileArchive(IFileArchive* archive);
//! move the hirarchy of the filesystem. moves sourceIndex relative up or down
virtual bool moveFileArchive(u32 sourceIndex, s32 relative);
//! Adds an external archive loader to the engine.
virtual void addArchiveLoader(IArchiveLoader* loader);
//! Returns the total number of archive loaders added.
virtual u32 getArchiveLoaderCount() const;
//! Gets the archive loader by index.
virtual IArchiveLoader* getArchiveLoader(u32 index) const;
//! gets the file archive count
virtual u32 getFileArchiveCount() const;
//! gets an archive
virtual IFileArchive* getFileArchive(u32 index);
virtual void removeAllFileArchives();
//! removes an archive from the file system.
virtual bool removeFileArchive(u32 index);
//! removes an archive from the file system.
virtual bool removeFileArchive(const io::path& filename);
//! Removes an archive from the file system.
virtual bool removeFileArchive(const IFileArchive* archive);
//! Returns the string of the current working directory
virtual const io::path& getWorkingDirectory();
//! Changes the current Working Directory to the string given.
//! The string is operating system dependent. Under Windows it will look
//! like this: "drive:\directory\sudirectory\"
virtual bool changeWorkingDirectoryTo(const io::path& newDirectory);
//! Converts a relative path to an absolute (unique) path, resolving symbolic links
virtual io::path getAbsolutePath(const io::path& filename) const;
//! Returns the directory a file is located in.
/** \param filename: The file to get the directory from */
virtual io::path getFileDir(const io::path& filename) const;
//! Returns the base part of a filename, i.e. the name without the directory
//! part. If no directory is prefixed, the full name is returned.
/** \param filename: The file to get the basename from */
virtual io::path getFileBasename(const io::path& filename, bool keepExtension=true) const;
//! flatten a path and file name for example: "/you/me/../." becomes "/you"
virtual io::path& flattenFilename( io::path& directory, const io::path& root = "/" ) const;
//! Get the relative filename, relative to the given directory
virtual path getRelativeFilename(const path& filename, const path& directory) const;
virtual EFileSystemType setFileListSystem(EFileSystemType listType);
//! Creates a list of files and directories in the current working directory
//! and returns it.
virtual IFileList* createFileList();
//! Creates a list of files and directories in specified directory
//! and returns it.
virtual IFileList* createFileList(const io::path& directory);
//! Creates an empty filelist
virtual IFileList* createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths);
//! determines if a file exists and would be able to be opened.
virtual bool existFile(const io::path& filename) const;
//! Determines if a file exists and could be opened (thread-safe, ignore file archives), this function returns false for directory
virtual bool existFileOnly(const path& filename) const;
//! Creates a XML Reader from a file.
virtual IXMLReader* createXMLReader(const io::path& filename);
//! Creates a XML Reader from a file.
virtual IXMLReader* createXMLReader(IReadFile* file);
//! Creates a XML Reader from a file.
virtual IXMLReaderUTF8* createXMLReaderUTF8(const io::path& filename);
//! Creates a XML Reader from a file.
virtual IXMLReaderUTF8* createXMLReaderUTF8(IReadFile* file);
//! Creates a XML Writer from a file.
virtual IXMLWriter* createXMLWriter(const io::path& filename);
//! Creates a XML Writer from a file.
virtual IXMLWriter* createXMLWriter(IWriteFile* file);
//! Creates a new empty collection of attributes, usable for serialization and more.
virtual IAttributes* createEmptyAttributes(video::IVideoDriver* driver);
virtual std::unique_lock<std::recursive_mutex> acquireFileArchivesMutex() const;
private:
// don't expose, needs refactoring
bool changeArchivePassword(const path& filename,
const core::stringc& password,
IFileArchive** archive = 0);
//! Currently used FileSystemType
EFileSystemType FileSystemType;
//! WorkingDirectory for Native and Virtual filesystems
io::path WorkingDirectory [2];
//! currently attached ArchiveLoaders
core::array<IArchiveLoader*> ArchiveLoader;
//! currently attached Archives
core::array<IFileArchive*> FileArchives;
mutable std::recursive_mutex m_file_archives_mutex;
};
} // end namespace irr
} // end namespace io
#endif
+539
View File
@@ -0,0 +1,539 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIButton.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip)
: IGUIButton(environment, parent, id, rectangle),
SpriteBank(0), OverrideFont(0), Image(0), PressedImage(0),
ClickTime(0), HoverTime(0), FocusTime(0),
IsPushButton(false), Pressed(false),
UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
{
#ifdef _DEBUG
setDebugName("CGUIButton");
#endif
setNotClipped(noclip);
// Initialize the sprites.
for (u32 i=0; i<EGBS_COUNT; ++i)
ButtonSprites[i].Index = -1;
// This element can be tabbed.
setTabStop(true);
setTabOrder(-1);
}
//! destructor
CGUIButton::~CGUIButton()
{
if (OverrideFont)
OverrideFont->drop();
if (Image)
Image->drop();
if (PressedImage)
PressedImage->drop();
if (SpriteBank)
SpriteBank->drop();
}
//! Sets if the images should be scaled to fit the button
void CGUIButton::setScaleImage(bool scaleImage)
{
ScaleImage = scaleImage;
}
//! Returns whether the button scale the used images
bool CGUIButton::isScalingImage() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ScaleImage;
}
//! Sets if the button should use the skin to draw its border
void CGUIButton::setDrawBorder(bool border)
{
DrawBorder = border;
}
void CGUIButton::setSpriteBank(IGUISpriteBank* sprites)
{
if (sprites)
sprites->grab();
if (SpriteBank)
SpriteBank->drop();
SpriteBank = sprites;
}
void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop)
{
if (SpriteBank)
{
ButtonSprites[(u32)state].Index = index;
ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop;
}
else
{
ButtonSprites[(u32)state].Index = -1;
}
}
//! called if an event happened.
bool CGUIButton::OnEvent(const SEvent& event)
{
if (!isEnabled())
return IGUIElement::OnEvent(event);
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE))
{
if (!IsPushButton)
setPressed(true);
else
setPressed(!Pressed);
return true;
}
if (Pressed && !IsPushButton && event.KeyInput.PressedDown &&
event.KeyInput.Key == IRR_KEY_ESCAPE)
{
setPressed(false);
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE))
{
if (!IsPushButton)
setPressed(false);
if (Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.Caller == this)
{
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (!IsPushButton)
setPressed(false);
FocusTime = os::Timer::getTime();
}
else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
FocusTime = os::Timer::getTime();
}
else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)
{
HoverTime = os::Timer::getTime();
}
}
break;
case EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
if (Environment->hasFocus(this) &&
!AbsoluteClippingRect.isPointInside(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
{
Environment->removeFocus(this);
return false;
}
if (!IsPushButton)
setPressed(true);
Environment->setFocus(this);
return true;
}
else
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
bool wasPressed = Pressed;
if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )
{
if (!IsPushButton)
setPressed(false);
return true;
}
if (!IsPushButton)
setPressed(false);
else
{
setPressed(!Pressed);
}
if ((!IsPushButton && wasPressed && Parent) ||
(IsPushButton && wasPressed != Pressed))
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
default:
break;
}
return Parent ? Parent->OnEvent(event) : false;
}
//! draws the element and its children
void CGUIButton::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
// todo: move sprite up and text down if the pressed state has a sprite
const core::position2di spritePos = AbsoluteRect.getCenter();
if (!Pressed)
{
if (DrawBorder)
skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect);
if (Image)
{
core::position2d<s32> pos = spritePos;
pos.X -= ImageRect.getWidth() / 2;
pos.Y -= ImageRect.getHeight() / 2;
skin->draw2DImage(Image,
ScaleImage ? AbsoluteRect :
core::recti(pos, ImageRect.getSize()),
ImageRect, &AbsoluteClippingRect,
0, UseAlphaChannel);
//video::IVideoDriver* driver = Environment->getVideoDriver();
//driver->draw2DImage(Image,
// ScaleImage? AbsoluteRect :
// core::recti(pos, ImageRect.getSize()),
// ImageRect, &AbsoluteClippingRect,
// 0, UseAlphaChannel);
}
}
else
{
if (DrawBorder)
skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect);
if (PressedImage)
{
core::position2d<s32> pos = spritePos;
pos.X -= PressedImageRect.getWidth() / 2;
pos.Y -= PressedImageRect.getHeight() / 2;
if (Image == PressedImage && PressedImageRect == ImageRect)
{
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
}
skin->draw2DImage(PressedImage,
ScaleImage? AbsoluteRect :
core::recti(pos, PressedImageRect.getSize()),
PressedImageRect, &AbsoluteClippingRect,
0, UseAlphaChannel);
}
}
if (false) //SpriteBank)
{
// pressed / unpressed animation
u32 state = Pressed ? (u32)EGBS_BUTTON_DOWN : (u32)EGBS_BUTTON_UP;
if (ButtonSprites[state].Index != -1)
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, ClickTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
}
// focused / unfocused animation
state = Environment->hasFocus(this) ? (u32)EGBS_BUTTON_FOCUSED : (u32)EGBS_BUTTON_NOT_FOCUSED;
if (ButtonSprites[state].Index != -1)
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, FocusTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
}
// mouse over / off animation
if (isEnabled())
{
state = Environment->getHovered() == this ? (u32)EGBS_BUTTON_MOUSE_OVER : (u32)EGBS_BUTTON_MOUSE_OFF;
if (ButtonSprites[state].Index != -1)
{
SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos,
&AbsoluteClippingRect, ButtonSprites[state].Color, HoverTime, os::Timer::getTime(),
ButtonSprites[state].Loop, true);
}
}
}
if (Text.size())
{
IGUIFont* font = getActiveFont();
core::rect<s32> rect = AbsoluteRect;
if (Pressed)
{
rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X);
rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y);
}
if (font)
font->draw(Text.c_str(), rect,
skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
true, true, &AbsoluteClippingRect);
}
IGUIElement::draw();
}
//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
void CGUIButton::setOverrideFont(IGUIFont* font)
{
if (OverrideFont == font)
return;
if (OverrideFont)
OverrideFont->drop();
OverrideFont = font;
if (OverrideFont)
OverrideFont->grab();
}
//! Gets the override font (if any)
IGUIFont * CGUIButton::getOverrideFont() const
{
return OverrideFont;
}
//! Get the font which is used right now for drawing
IGUIFont* CGUIButton::getActiveFont() const
{
if ( OverrideFont )
return OverrideFont;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getFont(EGDF_BUTTON);
return 0;
}
//! Sets an image which should be displayed on the button when it is in normal state.
void CGUIButton::setImage(video::ITexture* image)
{
if (image)
image->grab();
if (Image)
Image->drop();
Image = image;
if (image)
ImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getSize());
if (!PressedImage)
setPressedImage(Image);
}
//! Sets the image which should be displayed on the button when it is in its normal state.
void CGUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)
{
setImage(image);
ImageRect = pos;
}
//! Sets an image which should be displayed on the button when it is in pressed state.
void CGUIButton::setPressedImage(video::ITexture* image)
{
if (image)
image->grab();
if (PressedImage)
PressedImage->drop();
PressedImage = image;
if (image)
PressedImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getSize());
}
//! Sets the image which should be displayed on the button when it is in its pressed state.
void CGUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)
{
setPressedImage(image);
PressedImageRect = pos;
}
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button.
void CGUIButton::setIsPushButton(bool isPushButton)
{
IsPushButton = isPushButton;
}
//! Returns if the button is currently pressed
bool CGUIButton::isPressed() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Pressed;
}
//! Sets the pressed state of the button if this is a pushbutton
void CGUIButton::setPressed(bool pressed)
{
if (Pressed != pressed)
{
ClickTime = os::Timer::getTime();
Pressed = pressed;
}
}
//! Returns whether the button is a push button
bool CGUIButton::isPushButton() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return IsPushButton;
}
//! Sets if the alpha channel should be used for drawing images on the button (default is false)
void CGUIButton::setUseAlphaChannel(bool useAlphaChannel)
{
UseAlphaChannel = useAlphaChannel;
}
//! Returns if the alpha channel should be used for drawing images on the button
bool CGUIButton::isAlphaChannelUsed() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return UseAlphaChannel;
}
bool CGUIButton::isDrawingBorder() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return DrawBorder;
}
//! Writes attributes of the element.
void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIButton::serializeAttributes(out,options);
out->addBool ("PushButton", IsPushButton );
if (IsPushButton)
out->addBool("Pressed", Pressed);
out->addTexture ("Image", Image);
out->addRect ("ImageRect", ImageRect);
out->addTexture ("PressedImage", PressedImage);
out->addRect ("PressedImageRect", PressedImageRect);
out->addBool ("UseAlphaChannel", isAlphaChannelUsed());
out->addBool ("Border", isDrawingBorder());
out->addBool ("ScaleImage", isScalingImage());
// out->addString ("OverrideFont", OverrideFont);
}
//! Reads attributes of the element
void CGUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIButton::deserializeAttributes(in,options);
IsPushButton = in->getAttributeAsBool("PushButton");
Pressed = IsPushButton ? in->getAttributeAsBool("Pressed") : false;
core::rect<s32> rec = in->getAttributeAsRect("ImageRect");
if (rec.isValid())
setImage( in->getAttributeAsTexture("Image"), rec);
else
setImage( in->getAttributeAsTexture("Image") );
rec = in->getAttributeAsRect("PressedImageRect");
if (rec.isValid())
setPressedImage( in->getAttributeAsTexture("PressedImage"), rec);
else
setPressedImage( in->getAttributeAsTexture("PressedImage") );
setDrawBorder(in->getAttributeAsBool("Border"));
setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));
setScaleImage(in->getAttributeAsBool("ScaleImage"));
// setOverrideFont(in->getAttributeAsString("OverrideFont"));
updateAbsolutePosition();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+143
View File
@@ -0,0 +1,143 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_BUTTON_H_INCLUDED__
#define __C_GUI_BUTTON_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIButton.h"
#include "IGUISpriteBank.h"
#include "SColor.h"
namespace irr
{
namespace gui
{
class CGUIButton : public IGUIButton
{
public:
//! constructor
CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip=false);
//! destructor
virtual ~CGUIButton();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
virtual void setOverrideFont(IGUIFont* font=0);
//! Gets the override font (if any)
virtual IGUIFont* getOverrideFont() const;
//! Get the font which is used right now for drawing
virtual IGUIFont* getActiveFont() const;
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image=0);
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image, const core::rect<s32>& pos);
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image=0);
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos);
//! Sets the sprite bank used by the button
virtual void setSpriteBank(IGUISpriteBank* bank=0);
//! Sets the animated sprite for a specific button state
/** \param index: Number of the sprite within the sprite bank, use -1 for no sprite
\param state: State of the button to set the sprite for
\param index: The sprite number from the current sprite bank
\param color: The color of the sprite
*/
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index,
video::SColor color=video::SColor(255,255,255,255), bool loop=false);
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button.
virtual void setIsPushButton(bool isPushButton=true);
//! Checks whether the button is a push button
virtual bool isPushButton() const;
//! Sets the pressed state of the button if this is a pushbutton
virtual void setPressed(bool pressed=true);
//! Returns if the button is currently pressed
virtual bool isPressed() const;
//! Sets if the button should use the skin to draw its border
virtual void setDrawBorder(bool border=true);
//! Checks if the button face and border are being drawn
virtual bool isDrawingBorder() const;
//! Sets if the alpha channel should be used for drawing images on the button (default is false)
virtual void setUseAlphaChannel(bool useAlphaChannel=true);
//! Checks if the alpha channel should be used for drawing images on the button
virtual bool isAlphaChannelUsed() const;
//! Sets if the button should scale the button images to fit
virtual void setScaleImage(bool scaleImage=true);
//! Checks whether the button scales the used images
virtual bool isScalingImage() const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
struct ButtonSprite
{
s32 Index;
video::SColor Color;
bool Loop;
};
ButtonSprite ButtonSprites[EGBS_COUNT];
IGUISpriteBank* SpriteBank;
IGUIFont* OverrideFont;
video::ITexture* Image;
video::ITexture* PressedImage;
core::rect<s32> ImageRect;
core::rect<s32> PressedImageRect;
u32 ClickTime, HoverTime, FocusTime;
bool IsPushButton;
bool Pressed;
bool UseAlphaChannel;
bool DrawBorder;
bool ScaleImage;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_BUTTON_H_INCLUDED__
@@ -0,0 +1,208 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUICheckBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUICheckBox(environment, parent, id, rectangle), checkTime(0), Pressed(false), Checked(checked)
{
#ifdef _DEBUG
setDebugName("CGUICheckBox");
#endif
// this element can be tabbed into
setTabStop(true);
setTabOrder(-1);
}
//! called if an event happened.
bool CGUICheckBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE))
{
Pressed = true;
return true;
}
else
if (Pressed && event.KeyInput.PressedDown &&
event.KeyInput.Key == IRR_KEY_ESCAPE)
{
Pressed = false;
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE))
{
Pressed = false;
if (Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == this)
Pressed = false;
}
break;
case EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
Pressed = true;
checkTime = os::Timer::getTime();
Environment->setFocus(this);
return true;
}
else
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
bool wasPressed = Pressed;
Environment->removeFocus(this);
Pressed = false;
if (wasPressed && Parent)
{
if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y) ) )
{
Pressed = false;
return true;
}
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUICheckBox::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (skin)
{
const s32 height = skin->getSize(EGDS_CHECK_BOX_WIDTH);
core::rect<s32> checkRect(AbsoluteRect.UpperLeftCorner.X,
((AbsoluteRect.getHeight() - height) / 2) + AbsoluteRect.UpperLeftCorner.Y,
0, 0);
checkRect.LowerRightCorner.X = checkRect.UpperLeftCorner.X + height;
checkRect.LowerRightCorner.Y = checkRect.UpperLeftCorner.Y + height;
EGUI_DEFAULT_COLOR col = EGDC_GRAY_EDITABLE;
if ( isEnabled() )
col = Pressed ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE;
skin->draw3DSunkenPane(this, skin->getColor(col),
false, true, checkRect, &AbsoluteClippingRect);
if (Checked)
{
skin->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(),
checkTime, os::Timer::getTime(), false, &AbsoluteClippingRect);
}
if (Text.size())
{
checkRect = AbsoluteRect;
checkRect.UpperLeftCorner.X += height + 5;
IGUIFont* font = skin->getFont();
if (font)
{
font->draw(Text.c_str(), checkRect,
skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &AbsoluteClippingRect);
}
}
}
IGUIElement::draw();
}
//! set if box is checked
void CGUICheckBox::setChecked(bool checked)
{
Checked = checked;
}
//! returns if box is checked
bool CGUICheckBox::isChecked() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Checked;
}
//! Writes attributes of the element.
void CGUICheckBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUICheckBox::serializeAttributes(out,options);
out->addBool("Checked", Checked);
}
//! Reads attributes of the element
void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
Checked = in->getAttributeAsBool ("Checked");
IGUICheckBox::deserializeAttributes(in,options);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,55 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_CHECKBOX_H_INCLUDED__
#define __C_GUI_CHECKBOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUICheckBox.h"
namespace irr
{
namespace gui
{
class CGUICheckBox : public IGUICheckBox
{
public:
//! constructor
CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! set if box is checked
virtual void setChecked(bool checked);
//! returns if box is checked
virtual bool isChecked() const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
u32 checkTime;
bool Pressed;
bool Checked;
};
} // end namespace gui
} // end namespace irr
#endif // __C_GUI_CHECKBOX_H_INCLUDED__
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,483 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIColorSelectDialog.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIStaticText.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "IFileList.h"
#include "os.h"
#include "fast_atof.h"
namespace irr
{
namespace gui
{
const s32 CSD_WIDTH = 350;
const s32 CSD_HEIGHT = 300;
namespace
{
struct subElementPredefines
{
const wchar_t *pre;
const wchar_t *init;
const wchar_t *post;
int x, y;
int range_down ,range_up;
};
static const subElementPredefines Template [] =
{
{ L"A:", L"0", 0,50,165, 0, 255 },
{ L"R:", L"0", 0,20,205, 0, 255 },
{ L"G:", L"0", 0,20,230, 0, 255 },
{ L"B:", L"0", 0,20,255, 0, 255 },
{ L"H:", L"0", L"°",80,205, 0, 360 },
{ L"S:", L"0", L"%",80,230, 0, 100 },
{ L"L:", L"0", L"%",80,255, 0, 100 },
};
}
//! constructor
CGUIColorSelectDialog::CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id)
: IGUIColorSelectDialog(environment, parent, id,
core::rect<s32>((parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2,
(parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2,
(parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2+CSD_WIDTH,
(parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2+CSD_HEIGHT)),
Dragging(false)
{
#ifdef _DEBUG
IGUIElement::setDebugName("CGUIColorSelectDialog");
#endif
Text = title;
IGUISkin* skin = Environment->getSkin();
const s32 buttonw = environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH);
const s32 posx = RelativeRect.getWidth() - buttonw - 4;
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw),
this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close");
if (skin && skin->getSpriteBank())
{
CloseButton->setSpriteBank(skin->getSpriteBank());
CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL));
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL));
}
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CloseButton->grab();
OKButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK");
OKButton->setSubElement(true);
OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
OKButton->grab();
CancelButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel");
CancelButton->setSubElement(true);
CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CancelButton->grab();
video::IVideoDriver* driver = Environment->getVideoDriver();
ColorRing.Texture = driver->getTexture ( "#colorring" );
if ( 0 == ColorRing.Texture )
{
buildColorRing(core::dimension2d<u32>(128, 128), 1,
Environment->getSkin()->getColor(EGDC_3D_SHADOW));
}
core::rect<s32> r(20,20, 0,0);
ColorRing.Control = Environment->addImage(ColorRing.Texture, r.UpperLeftCorner, true, this);
ColorRing.Control->setSubElement(true);
ColorRing.Control->grab();
for ( u32 i = 0; i != sizeof (Template) / sizeof ( subElementPredefines ); ++i )
{
if ( Template[i].pre )
{
r.UpperLeftCorner.X = Template[i].x;
r.UpperLeftCorner.Y = Template[i].y;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 15;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
IGUIElement *t = Environment->addStaticText(Template[i].pre, r, false, false, this);
t->setSubElement(true);
}
if ( Template[i].post )
{
r.UpperLeftCorner.X = Template[i].x + 56;
r.UpperLeftCorner.Y = Template[i].y;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 15;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
IGUIElement *t = Environment->addStaticText( Template[i].post, r, false, false, this);
t->setSubElement(true);
}
r.UpperLeftCorner.X = Template[i].x + 15;
r.UpperLeftCorner.Y = Template[i].y-2;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 40;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
gui::IGUISpinBox* spin = Environment->addSpinBox( Template[i].init, r, true, this);
spin->setSubElement(true);
spin->setDecimalPlaces(0);
spin->setRange((f32)Template[i].range_down, (f32)Template[i].range_up);
spin->grab();
Battery.push_back(spin);
}
bringToFront(CancelButton);
bringToFront(OKButton);
}
//! destructor
CGUIColorSelectDialog::~CGUIColorSelectDialog()
{
if (CloseButton)
CloseButton->drop();
if (OKButton)
OKButton->drop();
if (CancelButton)
CancelButton->drop();
for (u32 i = 0; i != Battery.size(); ++i)
Battery[i]->drop();
if (ColorRing.Control)
ColorRing.Control->drop();
}
//! renders a antialiased, colored ring
void CGUIColorSelectDialog::buildColorRing( const core::dimension2d<u32> & dim, s32 supersample, const video::SColor& borderColor )
{
const core::dimension2d<u32> d(dim.Width * supersample, dim.Height * supersample);
video::IVideoDriver* driver = Environment->getVideoDriver();
video::IImage *RawTexture = driver->createImage(video::ECF_A8R8G8B8, d);
RawTexture->fill ( 0x00808080 );
const s32 radiusOut = ( d.Width / 2 ) - 4;
const s32 fullR2 = radiusOut * radiusOut;
video::SColorf rgb(0,0,0);
video::SColorHSL hsl;
hsl.Luminance = 50;
hsl.Saturation = 100;
core::position2d<s32> p;
for ( p.Y = -radiusOut; p.Y <= radiusOut; p.Y += 1 )
{
s32 y2 = p.Y * p.Y;
for (p.X = -radiusOut; p.X <= radiusOut; p.X += 1)
{
s32 r2 = y2 + ( p.X * p.X );
// test point in circle
s32 testa = r2 - fullR2;
if ( testa < 0 )
{
// dotproduct u ( x,y ) * v ( 1, 0 ) = cosinus(a)
const f32 r = sqrtf((f32) r2);
// normalize, dotproduct = xnorm
const f32 xn = r == 0.f ? 0.f : -p.X * core::reciprocal(r);
hsl.Hue = acosf(xn)*core::RADTODEG;
if ( p.Y > 0 )
hsl.Hue = 360 - hsl.Hue;
hsl.Hue -= 90;
const f32 rTest = r / radiusOut;
#if 0
if (rTest < 0.33f)
{
// luminance from 0 to 50
hsl.Luminance = 50*(rTest/0.33);
hsl.Saturation = 0.f;
hsl.toRGB(rgb);
}
else
if ( rTest < 0.66f )
{
// saturation from 0 to 100
hsl.Saturation = 100*(( rTest - 0.33f ) / 0.33f);
hsl.Luminance = 50;
hsl.toRGB(rgb);
}
else
{
// luminance from 50 to 100
hsl.Luminance = 100*(0.5f + ( ( rTest - 0.66f ) / .66f ));
hsl.Saturation = 100;
hsl.toRGB(rgb);
}
// borders should be slightly transparent
if ( rTest >= 0.95f )
rgb.a = (1.f-rTest)*20;
else
rgb.a=1.f;
#else
if ( rTest > 0.5f )
{
hsl.Saturation = 100;
hsl.Luminance = 50;
hsl.toRGB(rgb);
}
// borders should be slightly transparent
if ( rTest < 0.5f )
rgb.a = 0;
else if ( rTest >= 0.95f )
rgb.a = (1.f-rTest)*20;
else if ( rTest <= 0.55f )
rgb.a = (rTest-0.5f)*20;
else
rgb.a=1.f;
#endif
RawTexture->setPixel(4+p.X+radiusOut, 4+p.Y+radiusOut, rgb.toSColor());
}
}
}
RawTexture->unlock ();
if ( supersample > 1 )
{
video::IImage * filter = driver->createImage(video::ECF_A8R8G8B8, dim );
RawTexture->copyToScalingBoxFilter(filter);
RawTexture->drop();
RawTexture = filter;
}
bool generateMipLevels = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
driver->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, false);
ColorRing.Texture = driver->addTexture ( "#colorring", RawTexture);
RawTexture->drop();
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, generateMipLevels);
}
//! called if an event happened.
bool CGUIColorSelectDialog::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_SPINBOX_CHANGED:
{
for ( u32 i = 0; i!= Battery.size (); ++i )
{
if ( event.GUIEvent.Caller == Battery[i] )
{
if (i<4)
{
video::SColor rgb((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(),
(u32)Battery[2]->getValue(), (u32)Battery[3]->getValue());
video::SColorHSL hsl;
video::SColorf rgb2(rgb);
hsl.fromRGB(rgb2);
Battery[4]->setValue(hsl.Hue);
Battery[5]->setValue(hsl.Saturation);
Battery[6]->setValue(hsl.Luminance);
}
else
{
video::SColorHSL hsl(Battery[4]->getValue(), Battery[5]->getValue(),
Battery[6]->getValue());
video::SColorf rgb2;
hsl.toRGB(rgb2);
video::SColor rgb = rgb2.toSColor();
Battery[1]->setValue((f32)rgb.getRed());
Battery[2]->setValue((f32)rgb.getGreen());
Battery[3]->setValue((f32)rgb.getBlue());
}
}
}
return true;
}
case EGET_ELEMENT_FOCUS_LOST:
Dragging = false;
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == CloseButton ||
event.GUIEvent.Caller == CancelButton)
{
sendCancelEvent();
remove();
return true;
}
else
if (event.GUIEvent.Caller == OKButton)
{
sendSelectedEvent();
remove();
return true;
}
break;
case EGET_LISTBOX_CHANGED:
case EGET_LISTBOX_SELECTED_AGAIN:
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = true;
Environment->setFocus(this);
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
Environment->removeFocus(this);
return true;
case EMIE_MOUSE_MOVED:
if (Dragging)
{
// gui window should not be dragged outside its parent
if (Parent)
if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1)
return true;
move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
return true;
}
default:
break;
}
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUIColorSelectDialog::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
core::rect<s32> rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect);
if (Text.size())
{
rect.UpperLeftCorner.X += 2;
rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;
IGUIFont* font = skin->getFont(EGDF_WINDOW);
if (font)
font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true,
&AbsoluteClippingRect);
}
IGUIElement::draw();
// draw color selector after the window elements
core::vector2di pos(ColorRing.Control->getAbsolutePosition().UpperLeftCorner);
pos.X += ColorRing.Texture->getOriginalSize().Width/2;
pos.Y += ColorRing.Texture->getOriginalSize().Height/2;
#if 0
const f32 h = Battery[4]->getValue();
const f32 s = Battery[5]->getValue();
const f32 l = Battery[6]->getValue();
const f32 factor = 58.f*(((s==0)&&(l<50))?(l*0.33f/50):(
(s<100)?((.33f+(s*0.33f/100))):((0.66f+(l-50)*0.33f/50))));
#else
const f32 factor = 44;
#endif
pos.X += core::round32(sinf(Battery[4]->getValue()*core::DEGTORAD)*factor);
pos.Y -= core::round32(cosf(Battery[4]->getValue()*core::DEGTORAD)*factor);
Environment->getVideoDriver()->draw2DPolygon(pos, 4, 0xffffffff, 4);
}
video::SColor CGUIColorSelectDialog::getColor()
{
return video::SColor((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(),
(u32)Battery[2]->getValue(), (u32)Battery[3]->getValue());
}
video::SColorHSL CGUIColorSelectDialog::getColorHSL()
{
return video::SColorHSL(Battery[4]->getValue(), Battery[5]->getValue(),
Battery[6]->getValue());
}
//! sends the event that the file has been selected.
void CGUIColorSelectDialog::sendSelectedEvent()
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_SELECTED;
Parent->OnEvent(event);
}
//! sends the event that the file choose process has been canceld
void CGUIColorSelectDialog::sendCancelEvent()
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
Parent->OnEvent(event);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,74 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__
#define __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIColorSelectDialog.h"
#include "IGUIButton.h"
#include "IGUISpinBox.h"
#include "IGUIImage.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class CGUIColorSelectDialog : public IGUIColorSelectDialog
{
public:
//! constructor
CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id);
//! destructor
virtual ~CGUIColorSelectDialog();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
virtual video::SColor getColor();
virtual video::SColorHSL getColorHSL();
private:
//! sends the event that the file has been selected.
void sendSelectedEvent();
//! sends the event that the file choose process has been canceld
void sendCancelEvent();
core::position2d<s32> DragStart;
bool Dragging;
IGUIButton* CloseButton;
IGUIButton* OKButton;
IGUIButton* CancelButton;
core::array<IGUISpinBox*> Battery;
struct SColorCircle
{
IGUIImage * Control;
video::ITexture * Texture;
};
SColorCircle ColorRing;
void buildColorRing( const core::dimension2d<u32> & dim, s32 supersample, const video::SColor& borderColor );
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__
@@ -0,0 +1,525 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIComboBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IGUIFont.h"
#include "IGUIButton.h"
#include "CGUIListBox.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle)
: IGUIComboBox(environment, parent, id, rectangle),
ListButton(0), SelectedText(0), ListBox(0), LastFocus(0),
Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false)
{
#ifdef _DEBUG
setDebugName("CGUIComboBox");
#endif
IGUISkin* skin = Environment->getSkin();
s32 width = 15;
if (skin)
width = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
core::rect<s32> r;
r.UpperLeftCorner.X = rectangle.getWidth() - width - 2;
r.LowerRightCorner.X = rectangle.getWidth() - 2;
r.UpperLeftCorner.Y = 2;
r.LowerRightCorner.Y = rectangle.getHeight() - 2;
ListButton = Environment->addButton(r, this, -1, L"");
if (skin && skin->getSpriteBank())
{
ListButton->setSpriteBank(skin->getSpriteBank());
ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
}
ListButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
ListButton->setSubElement(true);
ListButton->setTabStop(false);
r.UpperLeftCorner.X = 2;
r.UpperLeftCorner.Y = 2;
r.LowerRightCorner.X = RelativeRect.getWidth() - (ListButton->getAbsolutePosition().getWidth() + 2);
r.LowerRightCorner.Y = RelativeRect.getHeight() - 2;
SelectedText = Environment->addStaticText(L"", r, false, false, this, -1, false);
SelectedText->setSubElement(true);
SelectedText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
SelectedText->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_CENTER);
if (skin)
SelectedText->setOverrideColor(skin->getColor(EGDC_BUTTON_TEXT));
SelectedText->enableOverrideColor(true);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
}
void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
{
HAlign = horizontal;
VAlign = vertical;
SelectedText->setTextAlignment(horizontal, vertical);
}
//! Set the maximal number of rows for the selection listbox
void CGUIComboBox::setMaxSelectionRows(u32 max)
{
MaxSelectionRows = max;
// force recalculation of open listbox
if (ListBox)
{
openCloseMenu();
openCloseMenu();
}
}
//! Get the maximimal number of rows for the selection listbox
u32 CGUIComboBox::getMaxSelectionRows() const
{
return MaxSelectionRows;
}
//! Returns amount of items in box
u32 CGUIComboBox::getItemCount() const
{
return Items.size();
}
//! returns string of an item. the idx may be a value from 0 to itemCount-1
const wchar_t* CGUIComboBox::getItem(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Name.c_str();
}
//! returns string of an item. the idx may be a value from 0 to itemCount-1
u32 CGUIComboBox::getItemData(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Data;
}
//! Returns index based on item data
s32 CGUIComboBox::getIndexForItemData(u32 data ) const
{
for ( u32 i = 0; i < Items.size (); ++i )
{
if ( Items[i].Data == data )
return i;
}
return -1;
}
//! Removes an item from the combo box.
void CGUIComboBox::removeItem(u32 idx)
{
if (idx >= Items.size())
return;
if (Selected == (s32)idx)
setSelected(-1);
Items.erase(idx);
}
//! Returns caption of this element.
const wchar_t* CGUIComboBox::getText() const
{
return getItem(Selected);
}
//! adds an item and returns the index of it
u32 CGUIComboBox::addItem(const wchar_t* text, u32 data)
{
Items.push_back( SComboData ( text, data ) );
if (Selected == -1)
setSelected(0);
return Items.size() - 1;
}
//! deletes all items in the combo box
void CGUIComboBox::clear()
{
Items.clear();
setSelected(-1);
}
//! returns id of selected item. returns -1 if no item is selected.
s32 CGUIComboBox::getSelected() const
{
return Selected;
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUIComboBox::setSelected(s32 idx)
{
if (idx < -1 || idx >= (s32)Items.size())
return;
Selected = idx;
if (Selected == -1)
SelectedText->setText(L"");
else
SelectedText->setText(Items[Selected].Name.c_str());
}
//! called if an event happened.
bool CGUIComboBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (ListBox && event.KeyInput.PressedDown &&
event.KeyInput.Key == IRR_KEY_ESCAPE)
{
// hide list box
openCloseMenu();
return true;
}
else
if (event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE)
{
if (!event.KeyInput.PressedDown)
{
openCloseMenu();
}
ListButton->setPressed(ListBox == 0);
return true;
}
else
if (event.KeyInput.PressedDown)
{
s32 oldSelected = Selected;
bool absorb = true;
switch (event.KeyInput.Key)
{
case IRR_KEY_DOWN:
setSelected(Selected+1);
break;
case IRR_KEY_UP:
setSelected(Selected-1);
break;
case IRR_KEY_HOME:
case IRR_KEY_PRIOR:
setSelected(0);
break;
case IRR_KEY_END:
case IRR_KEY_NEXT:
setSelected((s32)Items.size()-1);
break;
default:
absorb = false;
}
if (Selected <0)
setSelected(0);
if (Selected >= (s32)Items.size())
setSelected((s32)Items.size() -1);
if (Selected != oldSelected)
{
sendSelectionChangedEvent();
return true;
}
if (absorb)
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
if (ListBox &&
(Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) &&
event.GUIEvent.Element != this &&
!isMyChild(event.GUIEvent.Element) &&
!ListBox->isMyChild(event.GUIEvent.Element))
{
openCloseMenu();
}
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == ListButton)
{
openCloseMenu();
return true;
}
break;
case EGET_LISTBOX_SELECTED_AGAIN:
case EGET_LISTBOX_CHANGED:
if (event.GUIEvent.Caller == ListBox)
{
setSelected(ListBox->getSelected());
if (Selected <0 || Selected >= (s32)Items.size())
setSelected(-1);
openCloseMenu();
sendSelectionChangedEvent();
}
return true;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
// send to list box
if (ListBox && ListBox->isPointInside(p) && ListBox->OnEvent(event))
return true;
return true;
}
case EMIE_LMOUSE_LEFT_UP:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
// send to list box
if (!(ListBox &&
ListBox->getAbsolutePosition().isPointInside(p) &&
ListBox->OnEvent(event)))
{
openCloseMenu();
}
return true;
}
case EMIE_MOUSE_WHEEL:
{
s32 oldSelected = Selected;
setSelected( Selected + ((event.MouseInput.Wheel < 0) ? 1 : -1));
if (Selected <0)
setSelected(0);
if (Selected >= (s32)Items.size())
setSelected((s32)Items.size() -1);
if (Selected != oldSelected)
{
sendSelectionChangedEvent();
return true;
}
}
default:
break;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUIComboBox::sendSelectionChangedEvent()
{
if (Parent)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_COMBO_BOX_CHANGED;
Parent->OnEvent(event);
}
}
//! draws the element and its children
void CGUIComboBox::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
IGUIElement *currentFocus = Environment->getFocus();
if (currentFocus != LastFocus)
{
HasFocus = currentFocus == this || isMyChild(currentFocus);
LastFocus = currentFocus;
}
// set colors each time as skin-colors can be changed
SelectedText->setBackgroundColor(skin->getColor(EGDC_HIGH_LIGHT));
if(isEnabled())
{
SelectedText->setDrawBackground(HasFocus);
SelectedText->setOverrideColor(skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT));
}
else
{
SelectedText->setDrawBackground(false);
SelectedText->setOverrideColor(skin->getColor(EGDC_GRAY_TEXT));
}
ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
core::rect<s32> frameRect(AbsoluteRect);
// draw the border
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT),
true, true, frameRect, &AbsoluteClippingRect);
// draw children
IGUIElement::draw();
}
void CGUIComboBox::openCloseMenu()
{
if (ListBox)
{
// close list box
Environment->setFocus(this);
ListBox->remove();
ListBox = 0;
}
else
{
if (Parent)
Parent->bringToFront(this);
IGUISkin* skin = Environment->getSkin();
u32 h = Items.size();
if (h > getMaxSelectionRows())
h = getMaxSelectionRows();
if (h == 0)
h = 1;
IGUIFont* font = skin->getFont();
if (font)
h *= (font->getDimension(L"A").Height + 4);
// open list box
core::rect<s32> r(0, AbsoluteRect.getHeight(),
AbsoluteRect.getWidth(), AbsoluteRect.getHeight() + h);
ListBox = new CGUIListBox(Environment, this, -1, r, false, true, true);
ListBox->setSubElement(true);
ListBox->setNotClipped(true);
ListBox->drop();
// ensure that list box is always completely visible
if (ListBox->getAbsolutePosition().LowerRightCorner.Y > Environment->getRootGUIElement()->getAbsolutePosition().getHeight())
ListBox->setRelativePosition( core::rect<s32>(0, -ListBox->getAbsolutePosition().getHeight(), AbsoluteRect.getWidth(), 0) );
for (s32 i=0; i<(s32)Items.size(); ++i)
ListBox->addItem(Items[i].Name.c_str());
ListBox->setSelected(Selected);
// set focus
Environment->setFocus(ListBox);
}
}
//! Writes attributes of the element.
void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIComboBox::serializeAttributes(out,options);
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
out->addInt("MaxSelectionRows", (s32)MaxSelectionRows );
out->addInt ("Selected", Selected );
out->addInt ("ItemCount", Items.size());
for (u32 i=0; i < Items.size(); ++i)
{
core::stringc s = "Item";
s += i;
s += "Text";
out->addString(s.c_str(), Items[i].Name.c_str());
}
}
//! Reads attributes of the element
void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIComboBox::deserializeAttributes(in,options);
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
setMaxSelectionRows( (u32)(in->getAttributeAsInt("MaxSelectionRows")) );
// clear the list
clear();
// get item count
u32 c = in->getAttributeAsInt("ItemCount");
// add items
for (u32 i=0; i < c; ++i)
{
core::stringc s = "Item";
s += i;
s += "Text";
addItem(in->getAttributeAsStringW(s.c_str()).c_str(), 0);
}
setSelected(in->getAttributeAsInt("Selected"));
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+117
View File
@@ -0,0 +1,117 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_COMBO_BOX_H_INCLUDED__
#define __C_GUI_COMBO_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIComboBox.h"
#include "IGUIStaticText.h"
#include "irrString.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class IGUIButton;
class IGUIListBox;
//! Single line edit box for editing simple text.
class CGUIComboBox : public IGUIComboBox
{
public:
//! constructor
CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle);
//! Returns amount of items in box
virtual u32 getItemCount() const;
//! returns string of an item. the idx may be a value from 0 to itemCount-1
virtual const wchar_t* getItem(u32 idx) const;
//! Returns item data of an item. the idx may be a value from 0 to itemCount-1
virtual u32 getItemData(u32 idx) const;
//! Returns index based on item data
virtual s32 getIndexForItemData( u32 data ) const;
//! adds an item and returns the index of it
virtual u32 addItem(const wchar_t* text, u32 data);
//! Removes an item from the combo box.
virtual void removeItem(u32 id);
//! deletes all items in the combo box
virtual void clear();
//! returns the text of the currently selected item
virtual const wchar_t* getText() const;
//! returns id of selected item. returns -1 if no item is selected.
virtual s32 getSelected() const;
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelected(s32 idx);
//! sets the text alignment of the text part
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
//! Set the maximal number of rows for the selection listbox
virtual void setMaxSelectionRows(u32 max);
//! Get the maximimal number of rows for the selection listbox
virtual u32 getMaxSelectionRows() const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
void openCloseMenu();
void sendSelectionChangedEvent();
IGUIButton* ListButton;
IGUIStaticText* SelectedText;
IGUIListBox* ListBox;
IGUIElement *LastFocus;
struct SComboData
{
SComboData ( const wchar_t * text, u32 data )
: Name (text), Data ( data ) {}
core::stringw Name;
u32 Data;
};
core::array< SComboData > Items;
s32 Selected;
EGUI_ALIGNMENT HAlign, VAlign;
u32 MaxSelectionRows;
bool HasFocus;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_COMBO_BOX_H_INCLUDED__
@@ -0,0 +1,867 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIContextMenu.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment,
IGUIElement* parent, s32 id,
core::rect<s32> rectangle, bool getFocus, bool allowFocus)
: IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0),
CloseHandling(ECMC_REMOVE), HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus)
{
#ifdef _DEBUG
setDebugName("CGUIContextMenu");
#endif
Pos = rectangle.UpperLeftCorner;
recalculateSize();
if (getFocus)
Environment->setFocus(this);
setNotClipped(true);
}
//! destructor
CGUIContextMenu::~CGUIContextMenu()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->drop();
if (LastFont)
LastFont->drop();
}
//! set behavior when menus are closed
void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose)
{
CloseHandling = onClose;
}
//! get current behavior when the menue will be closed
ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const
{
return CloseHandling;
}
//! Returns amount of menu items
u32 CGUIContextMenu::getItemCount() const
{
return Items.size();
}
//! Adds a menu item.
u32 CGUIContextMenu::addItem(const wchar_t* text, s32 commandId, bool enabled, bool hasSubMenu, bool checked, bool autoChecking)
{
return insertItem(Items.size(), text, commandId, enabled, hasSubMenu, checked, autoChecking);
}
//! Insert a menu item at specified position.
u32 CGUIContextMenu::insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
bool hasSubMenu, bool checked, bool autoChecking)
{
SItem s;
s.Enabled = enabled;
s.Checked = checked;
s.AutoChecking = autoChecking;
s.Text = text;
s.IsSeparator = (text == 0);
s.SubMenu = 0;
s.CommandId = commandId;
if (hasSubMenu)
{
s.SubMenu = new CGUIContextMenu(Environment, this, commandId,
core::rect<s32>(0,0,100,100), false, false);
s.SubMenu->setVisible(false);
}
u32 result = idx;
if ( idx < Items.size() )
{
Items.insert(s, idx);
}
else
{
Items.push_back(s);
result = Items.size() - 1;
}
recalculateSize();
return result;
}
s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) const
{
for ( u32 i=idxStartSearch; i<Items.size(); ++i )
{
if ( Items[i].CommandId == commandId )
{
return (s32)i;
}
}
return -1;
}
//! Adds a sub menu from an element that already exists.
void CGUIContextMenu::setSubMenu(u32 index, CGUIContextMenu* menu)
{
if (index >= Items.size())
return;
if (menu)
menu->grab();
if (Items[index].SubMenu)
Items[index].SubMenu->drop();
Items[index].SubMenu = menu;
menu->setVisible(false);
if (Items[index].SubMenu)
{
menu->AllowFocus = false;
if ( Environment->getFocus() == menu )
{
Environment->setFocus( this );
}
}
recalculateSize();
}
//! Adds a separator item to the menu
void CGUIContextMenu::addSeparator()
{
addItem(0, -1, true, false, false, false);
}
//! Returns text of the menu item.
const wchar_t* CGUIContextMenu::getItemText(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Text.c_str();
}
//! Sets text of the menu item.
void CGUIContextMenu::setItemText(u32 idx, const wchar_t* text)
{
if (idx >= Items.size())
return;
Items[idx].Text = text;
recalculateSize();
}
//! should the element change the checked status on clicking
void CGUIContextMenu::setItemAutoChecking(u32 idx, bool autoChecking)
{
if ( idx >= Items.size())
return;
Items[idx].AutoChecking = autoChecking;
}
//! does the element change the checked status on clicking
bool CGUIContextMenu::getItemAutoChecking(u32 idx) const
{
if (idx >= Items.size())
return false;
return Items[idx].AutoChecking;
}
//! Returns if a menu item is enabled
bool CGUIContextMenu::isItemEnabled(u32 idx) const
{
if (idx >= Items.size())
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Items[idx].Enabled;
}
//! Returns if a menu item is checked
bool CGUIContextMenu::isItemChecked(u32 idx) const
{
if (idx >= Items.size())
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Items[idx].Checked;
}
//! Sets if the menu item should be enabled.
void CGUIContextMenu::setItemEnabled(u32 idx, bool enabled)
{
if (idx >= Items.size())
return;
Items[idx].Enabled = enabled;
}
//! Sets if the menu item should be checked.
void CGUIContextMenu::setItemChecked(u32 idx, bool checked )
{
if (idx >= Items.size())
return;
Items[idx].Checked = checked;
}
//! Removes a menu item
void CGUIContextMenu::removeItem(u32 idx)
{
if (idx >= Items.size())
return;
if (Items[idx].SubMenu)
{
Items[idx].SubMenu->drop();
Items[idx].SubMenu = 0;
}
Items.erase(idx);
recalculateSize();
}
//! Removes all menu items
void CGUIContextMenu::removeAllItems()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->drop();
Items.clear();
recalculateSize();
}
//! called if an event happened.
bool CGUIContextMenu::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus)
{
// set event parent of submenus
IGUIElement * p = EventParent ? EventParent : Parent;
setEventParent(p);
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
if ( !p->OnEvent(event) )
{
if ( CloseHandling & ECMC_HIDE )
{
setVisible(false);
}
if ( CloseHandling & ECMC_REMOVE )
{
remove();
}
}
return false;
}
break;
case EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller == this && !AllowFocus)
{
return true;
}
break;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_LEFT_UP:
{
// menu might be removed if it loses focus in sendClick, so grab a reference
grab();
const u32 t = sendClick(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
if ((t==0 || t==1) && Environment->hasFocus(this))
Environment->removeFocus(this);
drop();
}
return true;
case EMIE_LMOUSE_PRESSED_DOWN:
return true;
case EMIE_MOUSE_MOVED:
if (Environment->hasFocus(this))
highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
return true;
default:
break;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! Sets the visible state of this element.
void CGUIContextMenu::setVisible(bool visible)
{
HighLighted = -1;
ChangeTime = os::Timer::getTime();
for (u32 j=0; j<Items.size(); ++j)
if (Items[j].SubMenu)
Items[j].SubMenu->setVisible(false);
IGUIElement::setVisible(visible);
}
//! sends a click Returns:
//! 0 if click went outside of the element,
//! 1 if a valid button was clicked,
//! 2 if a nonclickable element was clicked
u32 CGUIContextMenu::sendClick(const core::position2d<s32>& p)
{
u32 t = 0;
// get number of open submenu
s32 openmenu = -1;
s32 j;
for (j=0; j<(s32)Items.size(); ++j)
if (Items[j].SubMenu && Items[j].SubMenu->isVisible())
{
openmenu = j;
break;
}
// delegate click operation to submenu
if (openmenu != -1)
{
t = Items[j].SubMenu->sendClick(p);
if (t != 0)
return t; // clicked something
}
// check click on myself
if (isPointInside(p) &&
(u32)HighLighted < Items.size())
{
if (!Items[HighLighted].Enabled ||
Items[HighLighted].IsSeparator ||
Items[HighLighted].SubMenu)
return 2;
if ( Items[HighLighted].AutoChecking )
{
Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true;
}
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED;
if (EventParent)
EventParent->OnEvent(event);
else if (Parent)
Parent->OnEvent(event);
return 1;
}
return 0;
}
//! returns true, if an element was highligted
bool CGUIContextMenu::highlight(const core::position2d<s32>& p, bool canOpenSubMenu)
{
if (!isEnabled())
{
return false;
}
// get number of open submenu
s32 openmenu = -1;
s32 i;
for (i=0; i<(s32)Items.size(); ++i)
if (Items[i].Enabled && Items[i].SubMenu && Items[i].SubMenu->isVisible())
{
openmenu = i;
break;
}
// delegate highlight operation to submenu
if (openmenu != -1)
{
if (Items[openmenu].Enabled && Items[openmenu].SubMenu->highlight(p, canOpenSubMenu))
{
HighLighted = openmenu;
ChangeTime = os::Timer::getTime();
return true;
}
}
// highlight myself
for (i=0; i<(s32)Items.size(); ++i)
{
if (Items[i].Enabled && getHRect(Items[i], AbsoluteRect).isPointInside(p))
{
HighLighted = i;
ChangeTime = os::Timer::getTime();
// make submenus visible/invisible
for (s32 j=0; j<(s32)Items.size(); ++j)
if (Items[j].SubMenu)
{
if ( j == i && canOpenSubMenu && Items[j].Enabled )
Items[j].SubMenu->setVisible(true);
else if ( j != i )
Items[j].SubMenu->setVisible(false);
}
return true;
}
}
HighLighted = openmenu;
return false;
}
//! returns the item highlight-area
core::rect<s32> CGUIContextMenu::getHRect(const SItem& i, const core::rect<s32>& absolute) const
{
core::rect<s32> r = absolute;
r.UpperLeftCorner.Y += i.PosY;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
return r;
}
//! Gets drawing rect of Item
core::rect<s32> CGUIContextMenu::getRect(const SItem& i, const core::rect<s32>& absolute) const
{
core::rect<s32> r = absolute;
r.UpperLeftCorner.Y += i.PosY;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
r.UpperLeftCorner.X += 20;
return r;
}
//! draws the element and its children
void CGUIContextMenu::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
IGUIFont* font = skin->getFont(EGDF_MENU);
if (font != LastFont)
{
if (LastFont)
LastFont->drop();
LastFont = font;
if (LastFont)
LastFont->grab();
recalculateSize();
}
core::rect<s32> rect = AbsoluteRect;
core::rect<s32>* clip = 0;
// draw frame
skin->draw3DMenuPane(this, AbsoluteRect, clip);
// loop through all menu items
rect = AbsoluteRect;
for (s32 i=0; i<(s32)Items.size(); ++i)
{
if (Items[i].IsSeparator)
{
// draw separator
rect = AbsoluteRect;
rect.UpperLeftCorner.Y += Items[i].PosY + 3;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
rect.UpperLeftCorner.X += 5;
rect.LowerRightCorner.X -= 5;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip);
rect.LowerRightCorner.Y += 1;
rect.UpperLeftCorner.Y += 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
}
else
{
rect = getRect(Items[i], AbsoluteRect);
// draw highlighted
if (i == HighLighted && Items[i].Enabled)
{
core::rect<s32> r = AbsoluteRect;
r.LowerRightCorner.Y = rect.LowerRightCorner.Y;
r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y;
r.LowerRightCorner.X -= 5;
r.UpperLeftCorner.X += 5;
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip);
}
// draw text
EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT;
if (i == HighLighted)
c = EGDC_HIGH_LIGHT_TEXT;
if (!Items[i].Enabled)
c = EGDC_GRAY_TEXT;
if (font)
font->draw(Items[i].Text.c_str(), rect,
skin->getColor(c), false, true, clip);
// draw submenu symbol
//IGUISpriteBank* sprites = skin->getSpriteBank();
//if (Items[i].SubMenu && sprites)
//{
// core::rect<s32> r = rect;
// r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
//
// sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
// r.getCenter(), clip, skin->getColor(c),
// (i == HighLighted) ? ChangeTime : 0,
// (i == HighLighted) ? os::Timer::getTime() : 0,
// (i == HighLighted), true);
//}
// draw checked symbol
//if (Items[i].Checked && sprites)
//{
// core::rect<s32> r = rect;
// r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
// r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
// sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
// r.getCenter(), clip, skin->getColor(c),
// (i == HighLighted) ? ChangeTime : 0,
// (i == HighLighted) ? os::Timer::getTime() : 0,
// (i == HighLighted), true);
//}
}
}
IGUIElement::draw();
}
void CGUIContextMenu::recalculateSize()
{
IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU);
if (!font)
return;
core::rect<s32> rect;
rect.UpperLeftCorner = RelativeRect.UpperLeftCorner;
u32 width = 100;
u32 height = 3;
u32 i;
for (i=0; i<Items.size(); ++i)
{
if (Items[i].IsSeparator)
{
Items[i].Dim.Width = 100;
Items[i].Dim.Height = 10;
}
else
{
Items[i].Dim = font->getDimension(Items[i].Text.c_str());
Items[i].Dim.Width += 40;
if (Items[i].Dim.Width > width)
width = Items[i].Dim.Width;
}
Items[i].PosY = height;
height += Items[i].Dim.Height;
}
height += 5;
if (height < 10)
height = 10;
rect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + width;
rect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + height;
setRelativePosition(rect);
// recalculate submenus
for (i=0; i<Items.size(); ++i)
{
if (Items[i].SubMenu)
{
// move submenu
const s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth();
const s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight();
core::rect<s32> subRect(width-5, Items[i].PosY, width+w-5, Items[i].PosY+h);
// if it would be drawn beyond the right border, then add it to the left side
gui::IGUIElement * root = Environment->getRootGUIElement();
if ( root )
{
core::rect<s32> rectRoot( root->getAbsolutePosition() );
if ( getAbsolutePosition().UpperLeftCorner.X+subRect.LowerRightCorner.X > rectRoot.LowerRightCorner.X )
{
subRect.UpperLeftCorner.X = -w;
subRect.LowerRightCorner.X = 0;
}
}
Items[i].SubMenu->setRelativePosition(subRect);
}
}
}
//! Returns the selected item in the menu
s32 CGUIContextMenu::getSelectedItem() const
{
return HighLighted;
}
//! \return Returns a pointer to the submenu of an item.
IGUIContextMenu* CGUIContextMenu::getSubMenu(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].SubMenu;
}
//! Returns command id of a menu item
s32 CGUIContextMenu::getItemCommandId(u32 idx) const
{
if (idx >= Items.size())
return -1;
return Items[idx].CommandId;
}
//! Sets the command id of a menu item
void CGUIContextMenu::setItemCommandId(u32 idx, s32 id)
{
if (idx >= Items.size())
return;
Items[idx].CommandId = id;
}
//! Writes attributes of the element.
void CGUIContextMenu::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIElement::serializeAttributes(out,options);
out->addPosition2d("Position", Pos);
if (Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU )
{
const IGUIContextMenu* const ptr = (const IGUIContextMenu*)Parent;
// find the position of this item in its parent's list
u32 i;
// VC6 needs the cast for this
for (i=0; (i<ptr->getItemCount()) && (ptr->getSubMenu(i) != (const IGUIContextMenu*)this); ++i)
; // do nothing
out->addInt("ParentItem", i);
}
out->addInt("CloseHandling", (s32)CloseHandling);
// write out the item list
out->addInt("ItemCount", Items.size());
core::stringc tmp;
for (u32 i=0; i < Items.size(); ++i)
{
tmp = "IsSeparator"; tmp += i;
out->addBool(tmp.c_str(), Items[i].IsSeparator);
if (!Items[i].IsSeparator)
{
tmp = "Text"; tmp += i;
out->addString(tmp.c_str(), Items[i].Text.c_str());
tmp = "CommandID"; tmp += i;
out->addInt(tmp.c_str(), Items[i].CommandId);
tmp = "Enabled"; tmp += i;
out->addBool(tmp.c_str(), Items[i].Enabled);
tmp = "Checked"; tmp += i;
out->addBool(tmp.c_str(), Items[i].Checked);
tmp = "AutoChecking"; tmp += i;
out->addBool(tmp.c_str(), Items[i].AutoChecking);
}
}
}
//! Reads attributes of the element
void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIElement::deserializeAttributes(in,options);
Pos = in->getAttributeAsPosition2d("Position");
// link to this item's parent
if (Parent && ( Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) )
((CGUIContextMenu*)Parent)->setSubMenu(in->getAttributeAsInt("ParentItem"),this);
CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling");
removeAllItems();
// read the item list
const s32 count = in->getAttributeAsInt("ItemCount");
for (s32 i=0; i<count; ++i)
{
core::stringc tmp;
core::stringw txt;
s32 commandid=-1;
bool enabled=true;
bool checked=false;
bool autochecking=false;
tmp = "IsSeparator"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) )
addSeparator();
else
{
tmp = "Text"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
txt = in->getAttributeAsStringW(tmp.c_str());
tmp = "CommandID"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
commandid = in->getAttributeAsInt(tmp.c_str());
tmp = "Enabled"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
enabled = in->getAttributeAsBool(tmp.c_str());
tmp = "Checked"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
checked = in->getAttributeAsBool(tmp.c_str());
tmp = "AutoChecking"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
autochecking = in->getAttributeAsBool(tmp.c_str());
addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking);
}
}
recalculateSize();
}
// because sometimes the element has no parent at click time
void CGUIContextMenu::setEventParent(IGUIElement *parent)
{
EventParent = parent;
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->setEventParent(parent);
}
bool CGUIContextMenu::hasOpenSubMenu() const
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu && Items[i].SubMenu->isVisible())
return true;
return false;
}
void CGUIContextMenu::closeAllSubMenus()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->setVisible(false);
//HighLighted = -1;
}
} // end namespace
} // end namespace
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,174 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_CONTEXT_MENU_H_INCLUDED__
#define __C_GUI_CONTEXT_MENU_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIContextMenu.h"
#include "irrString.h"
#include "irrArray.h"
#include "IGUIFont.h"
namespace irr
{
namespace gui
{
//! GUI Context menu interface.
class CGUIContextMenu : public IGUIContextMenu
{
public:
//! constructor
CGUIContextMenu(IGUIEnvironment* environment,
IGUIElement* parent, s32 id, core::rect<s32> rectangle,
bool getFocus = true, bool allowFocus = true);
//! destructor
virtual ~CGUIContextMenu();
//! set behavior when menus are closed
virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose);
//! get current behavior when the menue will be closed
virtual ECONTEXT_MENU_CLOSE getCloseHandling() const;
//! Returns amount of menu items
virtual u32 getItemCount() const;
//! Adds a menu item.
virtual u32 addItem(const wchar_t* text, s32 commandid,
bool enabled, bool hasSubMenu, bool checked, bool autoChecking);
//! Insert a menu item at specified position.
virtual u32 insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
bool hasSubMenu, bool checked, bool autoChecking);
//! Find a item which has the given CommandId starting from given index
virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch) const;
//! Adds a separator item to the menu
virtual void addSeparator();
//! Returns text of the menu item.
virtual const wchar_t* getItemText(u32 idx) const;
//! Sets text of the menu item.
virtual void setItemText(u32 idx, const wchar_t* text);
//! Returns if a menu item is enabled
virtual bool isItemEnabled(u32 idx) const;
//! Sets if the menu item should be enabled.
virtual void setItemEnabled(u32 idx, bool enabled);
//! Returns if a menu item is checked
virtual bool isItemChecked(u32 idx) const;
//! Sets if the menu item should be checked.
virtual void setItemChecked(u32 idx, bool enabled);
//! Removes a menu item
virtual void removeItem(u32 idx);
//! Removes all menu items
virtual void removeAllItems();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Returns the selected item in the menu
virtual s32 getSelectedItem() const;
//! Returns a pointer to the submenu of an item.
//! \return Pointer to the submenu of an item.
virtual IGUIContextMenu* getSubMenu(u32 idx) const;
//! Sets the visible state of this element.
virtual void setVisible(bool visible);
//! should the element change the checked status on clicking
virtual void setItemAutoChecking(u32 idx, bool autoChecking);
//! does the element change the checked status on clicking
virtual bool getItemAutoChecking(u32 idx) const;
//! Returns command id of a menu item
virtual s32 getItemCommandId(u32 idx) const;
//! Sets the command id of a menu item
virtual void setItemCommandId(u32 idx, s32 id);
//! Adds a sub menu from an element that already exists.
virtual void setSubMenu(u32 index, CGUIContextMenu* menu);
//! When an eventparent is set it receives events instead of the usual parent element
virtual void setEventParent(IGUIElement *parent);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
protected:
void closeAllSubMenus();
bool hasOpenSubMenu() const;
struct SItem
{
core::stringw Text;
bool IsSeparator;
bool Enabled;
bool Checked;
bool AutoChecking;
core::dimension2d<u32> Dim;
s32 PosY;
CGUIContextMenu* SubMenu;
s32 CommandId;
};
virtual void recalculateSize();
//! returns true, if an element was highlighted
virtual bool highlight(const core::position2d<s32>& p, bool canOpenSubMenu);
//! sends a click Returns:
//! 0 if click went outside of the element,
//! 1 if a valid button was clicked,
//! 2 if a nonclickable element was clicked
virtual u32 sendClick(const core::position2d<s32>& p);
//! returns the item highlight-area
virtual core::rect<s32> getHRect(const SItem& i, const core::rect<s32>& absolute) const;
//! Gets drawing rect of Item
virtual core::rect<s32> getRect(const SItem& i, const core::rect<s32>& absolute) const;
core::array<SItem> Items;
core::position2d<s32> Pos;
IGUIElement* EventParent;
IGUIFont *LastFont;
ECONTEXT_MENU_CLOSE CloseHandling;
s32 HighLighted;
u32 ChangeTime;
bool AllowFocus;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_CONTEXT_MENU_H_INCLUDED__
File diff suppressed because it is too large Load Diff
+188
View File
@@ -0,0 +1,188 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_EDIT_BOX_H_INCLUDED__
#define __C_GUI_EDIT_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEditBox.h"
#include "irrArray.h"
#include "IOSOperator.h"
namespace irr
{
namespace gui
{
class CGUIEditBox : public IGUIEditBox
{
public:
//! constructor
CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle);
//! destructor
virtual ~CGUIEditBox();
//! Sets another skin independent font.
virtual void setOverrideFont(IGUIFont* font=0);
//! Gets the override font (if any)
/** \return The override font (may be 0) */
virtual IGUIFont* getOverrideFont() const;
//! Get the font which is used right now for drawing
/** Currently this is the override font when one is set and the
font of the active skin otherwise */
virtual IGUIFont* getActiveFont() const;
//! Sets another color for the text.
virtual void setOverrideColor(video::SColor color);
//! Gets the override color
virtual video::SColor getOverrideColor() const;
//! Sets if the text should use the overide color or the
//! color in the gui skin.
virtual void enableOverrideColor(bool enable);
//! Checks if an override color is enabled
/** \return true if the override color is enabled, false otherwise */
virtual bool isOverrideColorEnabled(void) const;
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
//! Turns the border on or off
virtual void setDrawBorder(bool border);
//! Enables or disables word wrap for using the edit box as multiline text editor.
virtual void setWordWrap(bool enable);
//! Checks if word wrap is enabled
//! \return true if word wrap is enabled, false otherwise
virtual bool isWordWrapEnabled() const;
//! Enables or disables newlines.
/** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired,
instead a newline character will be inserted. */
virtual void setMultiLine(bool enable);
//! Checks if multi line editing is enabled
//! \return true if mult-line is enabled, false otherwise
virtual bool isMultiLineEnabled() const;
//! Enables or disables automatic scrolling with cursor position
//! \param enable: If set to true, the text will move around with the cursor position
virtual void setAutoScroll(bool enable);
//! Checks to see if automatic scrolling is enabled
//! \return true if automatic scrolling is enabled, false if not
virtual bool isAutoScrollEnabled() const;
//! Gets the size area of the text in the edit box
//! \return Returns the size in pixels of the text
virtual core::dimension2du getTextDimension();
//! Sets text justification
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Sets the new caption of this element.
virtual void setText(const core::stringw& text);
//! Sets the maximum amount of characters which may be entered in the box.
//! \param max: Maximum amount of characters. If 0, the character amount is
//! infinity.
virtual void setMax(u32 max);
//! Returns maximum amount of characters, previously set by setMax();
virtual u32 getMax() const;
//! Sets whether the edit box is a password box. Setting this to true will
/** disable MultiLine, WordWrap and the ability to copy with ctrl+c or ctrl+x
\param passwordBox: true to enable password, false to disable
\param passwordChar: the character that is displayed instead of letters */
virtual void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*');
//! Returns true if the edit box is currently a password box.
virtual bool isPasswordBox() const;
//! Updates the absolute position, splits text if required
virtual void updateAbsolutePosition();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
virtual void setComposingText(const std::u32string& ct) {}
virtual void clearComposingText() {}
virtual const core::position2di& getICPos() const
{
static core::position2di unused;
return unused;
}
protected:
//! Breaks the single text line.
void breakText();
//! sets the area of the given line
void setTextRect(s32 line);
//! returns the line number that the cursor is on
s32 getLineFromPos(s32 pos);
//! adds a letter to the edit box
void inputChar(wchar_t c);
//! calculates the current scroll position
void calculateScrollPos();
//! calculated the FrameRect
void calculateFrameRect();
//! send some gui event to parent
void sendGuiEvent(EGUI_EVENT_TYPE type);
//! set text markers
void setTextMarkers(s32 begin, s32 end);
bool processKey(const SEvent& event);
bool processMouse(const SEvent& event);
s32 getCursorPos(s32 x, s32 y);
bool MouseMarking;
bool Border;
bool Background;
bool OverrideColorEnabled;
s32 MarkBegin;
s32 MarkEnd;
video::SColor OverrideColor;
gui::IGUIFont *OverrideFont, *LastBreakFont;
IOSOperator* Operator;
u32 BlinkStartTime;
s32 CursorPos;
s32 HScrollPos, VScrollPos; // scroll position in characters
u32 Max;
bool WordWrap, MultiLine, AutoScroll, PasswordBox;
wchar_t PasswordChar;
EGUI_ALIGNMENT HAlign, VAlign;
core::array< core::stringw > BrokenText;
core::array< s32 > BrokenTextPositions;
core::rect<s32> CurrentTextRect, FrameRect; // temporary values
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_EDIT_BOX_H_INCLUDED__
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,322 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_ENVIRONMENT_H_INCLUDED__
#define __C_GUI_ENVIRONMENT_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IGUIElement.h"
#include "irrArray.h"
#include "IFileSystem.h"
#include "IOSOperator.h"
namespace irr
{
namespace io
{
class IXMLWriter;
}
namespace gui
{
class CGUIEnvironment : public IGUIEnvironment, public IGUIElement
{
public:
//! constructor
CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op);
//! destructor
virtual ~CGUIEnvironment();
//! draws all gui elements
virtual void drawAll();
//! returns the current video driver
virtual video::IVideoDriver* getVideoDriver() const;
//! returns pointer to the filesystem
virtual io::IFileSystem* getFileSystem() const;
//! returns a pointer to the OS operator
virtual IOSOperator* getOSOperator() const;
//! posts an input event to the environment
virtual bool postEventFromUser(const SEvent& event);
//! This sets a new event receiver for gui events. Usually you do not have to
//! use this method, it is used by the internal engine.
virtual void setUserEventReceiver(IEventReceiver* evr);
//! removes all elements from the environment
virtual void clear();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! returns the current gui skin
virtual IGUISkin* getSkin() const;
//! Sets a new GUI Skin
virtual void setSkin(IGUISkin* skin);
//! Creates a new GUI Skin based on a template.
/** \return Returns a pointer to the created skin.
If you no longer need the skin, you should call IGUISkin::drop().
See IReferenceCounted::drop() for more information. */
virtual IGUISkin* createSkin(EGUI_SKIN_TYPE type);
//! Creates the image list from the given texture.
virtual IGUIImageList* createImageList( video::ITexture* texture,
core::dimension2d<s32> imageSize, bool useAlphaChannel );
//! returns the font
virtual IGUIFont* getFont(const io::path& filename);
//! add an externally loaded font
virtual IGUIFont* addFont(const io::path& name, IGUIFont* font);
//! remove loaded font
virtual void removeFont(IGUIFont* font);
//! returns default font
virtual IGUIFont* getBuiltInFont() const;
//! returns the sprite bank
virtual IGUISpriteBank* getSpriteBank(const io::path& filename);
//! returns the sprite bank
virtual IGUISpriteBank* addEmptySpriteBank(const io::path& name);
//! adds an button. The returned pointer must not be dropped.
virtual IGUIButton* addButton(const core::rect<s32>& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext = 0);
//! adds a window. The returned pointer must not be dropped.
virtual IGUIWindow* addWindow(const core::rect<s32>& rectangle, bool modal = false,
const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1);
//! adds a modal screen. The returned pointer must not be dropped.
virtual IGUIElement* addModalScreen(IGUIElement* parent);
//! Adds a message box.
virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0,
bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0);
//! adds a scrollbar. The returned pointer must not be dropped.
virtual IGUIScrollBar* addScrollBar(bool horizontal, const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1);
//! Adds an image element.
virtual IGUIImage* addImage(video::ITexture* image, core::position2d<s32> pos,
bool useAlphaChannel=true, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0);
//! adds an image. The returned pointer must not be dropped.
virtual IGUIImage* addImage(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0, bool useAlphaChannel=true);
//! adds a checkbox
virtual IGUICheckBox* addCheckBox(bool checked, const core::rect<s32>& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0);
//! adds a list box
virtual IGUIListBox* addListBox(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1, bool drawBackground=false);
//! adds a tree view
virtual IGUITreeView* addTreeView(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1, bool drawBackground=false,
bool scrollBarVertical = true, bool scrollBarHorizontal = false);
//! adds an mesh viewer. The returned pointer must not be dropped.
virtual IGUIMeshViewer* addMeshViewer(const core::rect<s32>& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0);
//! Adds a file open dialog.
virtual IGUIFileOpenDialog* addFileOpenDialog(const wchar_t* title = 0,
bool modal=true, IGUIElement* parent=0, s32 id=-1,
bool restoreCWD=false, io::path::char_type* startDir=0);
//! Adds a color select dialog.
virtual IGUIColorSelectDialog* addColorSelectDialog(const wchar_t* title = 0, bool modal=true, IGUIElement* parent=0, s32 id=-1);
//! adds a static text. The returned pointer must not be dropped.
virtual IGUIStaticText* addStaticText(const core::stringw& text, const core::rect<s32>& rectangle,
bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1, bool drawBackground = false);
//! Adds an edit box. The returned pointer must not be dropped.
virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect<s32>& rectangle,
bool border=false, IGUIElement* parent=0, s32 id=-1);
//! Adds a spin box to the environment
virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect<s32>& rectangle,
bool border=false,IGUIElement* parent=0, s32 id=-1);
//! Adds a tab control to the environment.
virtual IGUITabControl* addTabControl(const core::rect<s32>& rectangle,
IGUIElement* parent=0, bool fillbackground=false, bool border=true, s32 id=-1);
//! Adds tab to the environment.
virtual IGUITab* addTab(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1);
//! Adds a context menu to the environment.
virtual IGUIContextMenu* addContextMenu(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1);
//! Adds a menu to the environment.
virtual IGUIContextMenu* addMenu(IGUIElement* parent=0, s32 id=-1);
//! Adds a toolbar to the environment. It is like a menu is always placed on top
//! in its parent, and contains buttons.
virtual IGUIToolBar* addToolBar(IGUIElement* parent=0, s32 id=-1);
//! Adds a combo box to the environment.
virtual IGUIComboBox* addComboBox(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1);
//! Adds a table element.
virtual IGUITable* addTable(const core::rect<s32>& rectangle,
IGUIElement* parent=0, s32 id=-1, bool drawBackground=false);
//! sets the focus to an element
virtual bool setFocus(IGUIElement* element);
//! removes the focus from an element
virtual bool removeFocus(IGUIElement* element);
//! Returns if the element has focus
virtual bool hasFocus(IGUIElement* element) const;
//! Returns the element with the focus
virtual IGUIElement* getFocus() const;
//! Returns the element last known to be under the mouse
virtual IGUIElement* getHovered() const;
//! Adds an element for fading in or out.
virtual IGUIInOutFader* addInOutFader(const core::rect<s32>* rectangle=0, IGUIElement* parent=0, s32 id=-1);
//! Returns the root gui element.
virtual IGUIElement* getRootGUIElement();
virtual void OnPostRender( u32 time );
//! Returns the default element factory which can create all built in elements
virtual IGUIElementFactory* getDefaultGUIElementFactory() const;
//! Adds an element factory to the gui environment.
/** Use this to extend the gui environment with new element types which it should be
able to create automaticly, for example when loading data from xml files. */
virtual void registerGUIElementFactory(IGUIElementFactory* factoryToAdd);
//! Returns amount of registered scene node factories.
virtual u32 getRegisteredGUIElementFactoryCount() const;
//! Returns a scene node factory by index
virtual IGUIElementFactory* getGUIElementFactory(u32 index) const;
//! Adds a GUI Element by its name
virtual IGUIElement* addGUIElement(const c8* elementName, IGUIElement* parent=0);
//! Saves the current gui into a file.
/** \param filename: Name of the file.
\param start: The element to start saving from.
if not specified, the root element will be used */
virtual bool saveGUI( const io::path& filename, IGUIElement* start=0);
//! Saves the current gui into a file.
/** \param file: The file to save the GUI to.
\param start: The element to start saving from.
if not specified, the root element will be used */
virtual bool saveGUI(io::IWriteFile* file, IGUIElement* start=0);
//! Loads the gui. Note that the current gui is not cleared before.
/** \param filename: Name of the file.
\param parent: The parent of all loaded GUI elements,
if not specified, the root element will be used */
virtual bool loadGUI(const io::path& filename, IGUIElement* parent=0);
//! Loads the gui. Note that the current gui is not cleared before.
/** \param file: IReadFile to load the GUI from
\param parent: The parent of all loaded GUI elements,
if not specified, the root element will be used */
virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0);
//! Writes attributes of the environment
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the environment.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! writes an element
virtual void writeGUIElement(io::IXMLWriter* writer, IGUIElement* node);
//! reads an element
virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node);
virtual void removeHovered(IGUIElement* element);
private:
IGUIElement* getNextElement(bool reverse=false, bool group=false);
void updateHoveredElement(core::position2d<s32> mousePos);
struct SFont
{
io::SNamedPath NamedPath;
IGUIFont* Font;
bool operator < (const SFont& other) const
{
return (NamedPath < other.NamedPath);
}
};
struct SSpriteBank
{
io::SNamedPath NamedPath;
IGUISpriteBank* Bank;
bool operator < (const SSpriteBank& other) const
{
return (NamedPath < other.NamedPath);
}
};
struct SToolTip
{
IGUIStaticText* Element;
u32 LastTime;
u32 EnterTime;
u32 LaunchTime;
u32 RelaunchTime;
};
SToolTip ToolTip;
core::array<IGUIElementFactory*> GUIElementFactoryList;
core::array<SFont> Fonts;
core::array<SSpriteBank> Banks;
video::IVideoDriver* Driver;
IGUIElement* Hovered;
IGUIElement* HoveredNoSubelement; // subelements replaced by their parent, so you only have 'real' elements here
IGUIElement* Focus;
core::position2d<s32> LastHoveredMousePos;
IGUISkin* CurrentSkin;
io::IFileSystem* FileSystem;
IEventReceiver* UserReceiver;
IOSOperator* Operator;
static const io::path DefaultFontName;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_ENVIRONMENT_H_INCLUDED__
@@ -0,0 +1,446 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIFileOpenDialog.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include <locale.h>
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIStaticText.h"
#include "IGUIFont.h"
#include "IGUIFontBitmap.h"
#include "IFileList.h"
#include "os.h"
namespace irr
{
namespace gui
{
const s32 FOD_WIDTH = 350;
const s32 FOD_HEIGHT = 250;
//! constructor
CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title,
IGUIEnvironment* environment, IGUIElement* parent, s32 id,
bool restoreCWD, io::path::char_type* startDir)
: IGUIFileOpenDialog(environment, parent, id,
core::rect<s32>((parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2,
(parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2,
(parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2+FOD_WIDTH,
(parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2+FOD_HEIGHT)),
FileNameText(0), FileList(0), Dragging(false)
{
#ifdef _DEBUG
IGUIElement::setDebugName("CGUIFileOpenDialog");
#endif
Text = title;
FileSystem = Environment?Environment->getFileSystem():0;
if (FileSystem)
{
FileSystem->grab();
if (restoreCWD)
RestoreDirectory = FileSystem->getWorkingDirectory();
if (startDir)
{
StartDirectory = startDir;
FileSystem->changeWorkingDirectoryTo(startDir);
}
}
else
return;
IGUISpriteBank* sprites = 0;
video::SColor color(255,255,255,255);
IGUISkin* skin = Environment->getSkin();
if (skin)
{
sprites = skin->getSpriteBank();
color = skin->getColor(EGDC_WINDOW_SYMBOL);
}
const s32 buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
const s32 posx = RelativeRect.getWidth() - buttonw - 4;
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close");
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
if (sprites)
{
CloseButton->setSpriteBank(sprites);
CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), color);
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), color);
}
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CloseButton->grab();
OKButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK");
OKButton->setSubElement(true);
OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
OKButton->grab();
CancelButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel");
CancelButton->setSubElement(true);
CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CancelButton->grab();
FileBox = Environment->addListBox(core::rect<s32>(10, 55, RelativeRect.getWidth()-90, 230), this, -1, true);
FileBox->setSubElement(true);
FileBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
FileBox->grab();
FileNameText = Environment->addEditBox(0, core::rect<s32>(10, 30, RelativeRect.getWidth()-90, 50), true, this);
FileNameText->setSubElement(true);
FileNameText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
FileNameText->grab();
setTabGroup(true);
fillListBox();
}
//! destructor
CGUIFileOpenDialog::~CGUIFileOpenDialog()
{
if (CloseButton)
CloseButton->drop();
if (OKButton)
OKButton->drop();
if (CancelButton)
CancelButton->drop();
if (FileBox)
FileBox->drop();
if (FileNameText)
FileNameText->drop();
if (FileSystem)
{
// revert to original CWD if path was set in constructor
if (RestoreDirectory.size())
FileSystem->changeWorkingDirectoryTo(RestoreDirectory);
FileSystem->drop();
}
if (FileList)
FileList->drop();
}
//! returns the filename of the selected file. Returns NULL, if no file was selected.
const wchar_t* CGUIFileOpenDialog::getFileName() const
{
return FileName.c_str();
}
//! Returns the directory of the selected file. Returns NULL, if no directory was selected.
const io::path& CGUIFileOpenDialog::getDirectoryName()
{
FileSystem->flattenFilename ( FileDirectory );
return FileDirectory;
}
//! called if an event happened.
bool CGUIFileOpenDialog::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
Dragging = false;
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == CloseButton ||
event.GUIEvent.Caller == CancelButton)
{
sendCancelEvent();
remove();
return true;
}
else
if (event.GUIEvent.Caller == OKButton )
{
if ( FileDirectory != L"" )
{
sendSelectedEvent( EGET_DIRECTORY_SELECTED );
}
if ( FileName != L"" )
{
sendSelectedEvent( EGET_FILE_SELECTED );
remove();
return true;
}
}
break;
case EGET_LISTBOX_CHANGED:
{
s32 selected = FileBox->getSelected();
if (FileList && FileSystem)
{
if (FileList->isDirectory(selected))
{
FileName = L"";
FileDirectory = FileList->getFullFileName(selected);
}
else
{
FileDirectory = L"";
FileName = FileList->getFullFileName(selected);
}
return true;
}
}
break;
case EGET_LISTBOX_SELECTED_AGAIN:
{
const s32 selected = FileBox->getSelected();
if (FileList && FileSystem)
{
if (FileList->isDirectory(selected))
{
FileDirectory = FileList->getFullFileName(selected);
FileSystem->changeWorkingDirectoryTo(FileList->getFileName(selected));
fillListBox();
FileName = "";
}
else
{
FileName = FileList->getFullFileName(selected);
}
return true;
}
}
break;
case EGET_EDITBOX_ENTER:
if (event.GUIEvent.Caller == FileNameText)
{
io::path dir( FileNameText->getText () );
if ( FileSystem->changeWorkingDirectoryTo( dir ) )
{
fillListBox();
FileName = L"";
}
return true;
}
break;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
return FileBox->OnEvent(event);
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = true;
Environment->setFocus(this);
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
return true;
case EMIE_MOUSE_MOVED:
if ( !event.MouseInput.isLeftPressed () )
Dragging = false;
if (Dragging)
{
// gui window should not be dragged outside its parent
if (Parent)
if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1)
return true;
move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
return true;
}
break;
default:
break;
}
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUIFileOpenDialog::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
core::rect<s32> rect = AbsoluteRect;
rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER),
rect, &AbsoluteClippingRect);
if (Text.size())
{
rect.UpperLeftCorner.X += 2;
rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;
IGUIFont* font = skin->getFont(EGDF_WINDOW);
if (font)
font->draw(Text.c_str(), rect,
skin->getColor(EGDC_ACTIVE_CAPTION),
false, true, &AbsoluteClippingRect);
}
IGUIElement::draw();
}
//! Writes attributes of the element.
/* Not sure if this will really work out properly. Saving paths can be
rather problematic. */
void CGUIFileOpenDialog::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IGUIFileOpenDialog::serializeAttributes(out,options);
out->addString("StartDirectory", StartDirectory.c_str());
out->addBool("RestoreDirectory", (RestoreDirectory.size()!=0));
}
//! Reads attributes of the element
/* Note that thiese paths changes will happen at arbitrary places upon
load of the gui description. This may be undesired. */
void CGUIFileOpenDialog::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
StartDirectory = in->getAttributeAsString("StartDirectory");
const bool restore = in->getAttributeAsBool("RestoreDirectory");
if (restore)
RestoreDirectory = FileSystem->getWorkingDirectory();
else
RestoreDirectory = "";
if (StartDirectory.size())
FileSystem->changeWorkingDirectoryTo(StartDirectory);
IGUIFileOpenDialog::deserializeAttributes(in,options);
}
//! fills the listbox with files.
void CGUIFileOpenDialog::fillListBox()
{
IGUISkin *skin = Environment->getSkin();
if (!FileSystem || !FileBox || !skin)
return;
if (FileList)
FileList->drop();
FileBox->clear();
FileList = FileSystem->createFileList();
core::stringw s;
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
setlocale(LC_ALL,"");
#endif
if (FileList)
{
for (u32 i=0; i < FileList->getFileCount(); ++i)
{
#ifndef _IRR_WCHAR_FILESYSTEM
const c8 *cs = (const c8 *)FileList->getFileName(i).c_str();
wchar_t *ws = new wchar_t[strlen(cs) + 1];
int len = mbstowcs(ws,cs,strlen(cs));
ws[len] = 0;
s = ws;
delete [] ws;
#else
s = FileList->getFileName(i).c_str();
#endif
FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE));
}
}
if (FileNameText)
{
#ifndef _IRR_WCHAR_FILESYSTEM
const c8 *cs = (const c8 *)FileSystem->getWorkingDirectory().c_str();
wchar_t *ws = new wchar_t[strlen(cs) + 1];
int len = mbstowcs(ws,cs,strlen(cs));
ws[len] = 0;
s = ws;
delete [] ws;
#else
s = FileSystem->getWorkingDirectory();
#endif
FileDirectory = s;
FileNameText->setText(s.c_str());
}
}
//! sends the event that the file has been selected.
void CGUIFileOpenDialog::sendSelectedEvent( EGUI_EVENT_TYPE type)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = type;
Parent->OnEvent(event);
}
//! sends the event that the file choose process has been canceld
void CGUIFileOpenDialog::sendCancelEvent()
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
Parent->OnEvent(event);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,84 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__
#define __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIFileOpenDialog.h"
#include "IGUIButton.h"
#include "IGUIListBox.h"
#include "IGUIEditBox.h"
#include "IFileSystem.h"
namespace irr
{
namespace gui
{
class CGUIFileOpenDialog : public IGUIFileOpenDialog
{
public:
//! constructor
CGUIFileOpenDialog(const wchar_t* title, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, bool restoreCWD=false,
io::path::char_type* startDir=0);
//! destructor
virtual ~CGUIFileOpenDialog();
//! returns the filename of the selected file. Returns NULL, if no file was selected.
virtual const wchar_t* getFileName() const;
//! Returns the directory of the selected file. Returns NULL, if no directory was selected.
virtual const io::path& getDirectoryName();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
protected:
//! fills the listbox with files.
void fillListBox();
//! sends the event that the file has been selected.
void sendSelectedEvent( EGUI_EVENT_TYPE type );
//! sends the event that the file choose process has been canceld
void sendCancelEvent();
core::position2d<s32> DragStart;
core::stringw FileName;
io::path FileDirectory;
io::path RestoreDirectory;
io::path StartDirectory;
IGUIButton* CloseButton;
IGUIButton* OKButton;
IGUIButton* CancelButton;
IGUIListBox* FileBox;
IGUIEditBox* FileNameText;
IGUIElement* EventParent;
io::IFileSystem* FileSystem;
io::IFileList* FileList;
bool Dragging;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__
+589
View File
@@ -0,0 +1,589 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIFont.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "os.h"
#include "IGUIEnvironment.h"
#include "IXMLReader.h"
#include "IReadFile.h"
#include "IVideoDriver.h"
#include "IGUISpriteBank.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path& filename)
: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
{
#ifdef _DEBUG
setDebugName("CGUIFont");
#endif
if (Environment)
{
// don't grab environment, to avoid circular references
Driver = Environment->getVideoDriver();
SpriteBank = Environment->getSpriteBank(filename);
if (!SpriteBank) // could be default-font which has no file
SpriteBank = Environment->addEmptySpriteBank(filename);
if (SpriteBank)
SpriteBank->grab();
}
if (Driver)
Driver->grab();
setInvisibleCharacters ( L" " );
}
//! destructor
CGUIFont::~CGUIFont()
{
if (Driver)
Driver->drop();
if (SpriteBank)
{
SpriteBank->drop();
// TODO: spritebank still exists in gui-environment and should be removed here when it's
// reference-count is 1. Just can't do that from here at the moment.
// But spritebank would not be able to drop textures anyway because those are in texture-cache
// where they can't be removed unless materials start reference-couting 'em.
}
}
//! loads a font file from xml
bool CGUIFont::load(io::IXMLReader* xml)
{
if (!SpriteBank)
return false;
SpriteBank->clear();
while (xml->read())
{
if (io::EXN_ELEMENT == xml->getNodeType())
{
if (core::stringw(L"Texture") == xml->getNodeName())
{
// add a texture
core::stringc fn = xml->getAttributeValue(L"filename");
u32 i = (u32)xml->getAttributeValueAsInt(L"index");
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
while (i+1 > SpriteBank->getTextureCount())
SpriteBank->addTexture(0);
// disable mipmaps+filtering
bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
// load texture
SpriteBank->setTexture(i, Driver->getTexture(fn));
// set previous mip-map+filter state
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap);
// couldn't load texture, abort.
if (!SpriteBank->getTexture(i))
{
os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR);
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
else
{
// colorkey texture rather than alpha channel?
if (alpha == core::stringw("false"))
Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0));
}
}
else if (core::stringw(L"c") == xml->getNodeName())
{
// adding a character to this font
SFontArea a;
SGUISpriteFrame f;
SGUISprite s;
core::rect<s32> rectangle;
a.underhang = xml->getAttributeValueAsInt(L"u");
a.overhang = xml->getAttributeValueAsInt(L"o");
a.spriteno = SpriteBank->getSprites().size();
s32 texno = xml->getAttributeValueAsInt(L"i");
// parse rectangle
core::stringc rectstr = xml->getAttributeValue(L"r");
wchar_t ch = xml->getAttributeValue(L"c")[0];
const c8 *c = rectstr.c_str();
s32 val;
val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.UpperLeftCorner.X = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.UpperLeftCorner.Y = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.LowerRightCorner.X = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.LowerRightCorner.Y = val;
CharacterMap.insert(ch,Areas.size());
// make frame
f.rectNumber = SpriteBank->getPositions().size();
f.textureNumber = texno;
// add frame to sprite
s.Frames.push_back(f);
s.frameTime = 0;
// add rectangle to sprite bank
SpriteBank->getPositions().push_back(rectangle);
a.width = rectangle.getWidth();
// add sprite to sprite bank
SpriteBank->getSprites().push_back(s);
// add character to font
Areas.push_back(a);
}
}
}
// set bad character
WrongCharacter = getAreaFromCharacter(L' ');
setMaxHeight();
return true;
}
void CGUIFont::setMaxHeight()
{
if ( !SpriteBank )
return;
MaxHeight = 0;
s32 t;
core::array< core::rect<s32> >& p = SpriteBank->getPositions();
for (u32 i=0; i<p.size(); ++i)
{
t = p[i].getHeight();
if (t>MaxHeight)
MaxHeight = t;
}
}
//! loads a font file, native file needed, for texture parsing
bool CGUIFont::load(io::IReadFile* file)
{
if (!Driver)
return false;
return loadTexture(Driver->createImageFromFile(file),
file->getFileName());
}
//! loads a font file, native file needed, for texture parsing
bool CGUIFont::load(const io::path& filename)
{
if (!Driver)
return false;
return loadTexture(Driver->createImageFromFile( filename ),
filename);
}
//! load & prepare font from ITexture
bool CGUIFont::loadTexture(video::IImage* image, const io::path& name)
{
if (!image || !SpriteBank)
return false;
s32 lowerRightPositions = 0;
video::IImage* tmpImage=image;
bool deleteTmpImage=false;
switch(image->getColorFormat())
{
case video::ECF_R5G6B5:
tmpImage = Driver->createImage(video::ECF_A1R5G5B5,image->getDimension());
image->copyTo(tmpImage);
deleteTmpImage=true;
break;
case video::ECF_A1R5G5B5:
case video::ECF_A8R8G8B8:
break;
case video::ECF_R8G8B8:
tmpImage = Driver->createImage(video::ECF_A8R8G8B8,image->getDimension());
image->copyTo(tmpImage);
deleteTmpImage=true;
break;
default:
os::Printer::log("Unknown texture format provided for CGUIFont::loadTexture", ELL_ERROR);
return false;
}
readPositions(tmpImage, lowerRightPositions);
WrongCharacter = getAreaFromCharacter(L' ');
// output warnings
if (!lowerRightPositions || !SpriteBank->getSprites().size())
os::Printer::log("Either no upper or lower corner pixels in the font file. If this font was made using the new font tool, please load the XML file instead. If not, the font may be corrupted.", ELL_ERROR);
else
if (lowerRightPositions != (s32)SpriteBank->getPositions().size())
os::Printer::log("The amount of upper corner pixels and the lower corner pixels is not equal, font file may be corrupted.", ELL_ERROR);
bool ret = ( !SpriteBank->getSprites().empty() && lowerRightPositions );
if ( ret )
{
bool flag[2];
flag[0] = Driver->getTextureCreationFlag ( video::ETCF_ALLOW_NON_POWER_2 );
flag[1] = Driver->getTextureCreationFlag ( video::ETCF_CREATE_MIP_MAPS );
Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, true);
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false );
SpriteBank->addTexture(Driver->addTexture(name, tmpImage));
Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, flag[0] );
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flag[1] );
}
if (deleteTmpImage)
tmpImage->drop();
image->drop();
setMaxHeight();
return ret;
}
void CGUIFont::readPositions(video::IImage* image, s32& lowerRightPositions)
{
if (!SpriteBank )
return;
const core::dimension2d<u32> size = image->getDimension();
video::SColor colorTopLeft = image->getPixel(0,0);
colorTopLeft.setAlpha(255);
image->setPixel(0,0,colorTopLeft);
video::SColor colorLowerRight = image->getPixel(1,0);
video::SColor colorBackGround = image->getPixel(2,0);
video::SColor colorBackGroundTransparent = 0;
image->setPixel(1,0,colorBackGround);
// start parsing
core::position2d<s32> pos(0,0);
for (pos.Y=0; pos.Y<(s32)size.Height; ++pos.Y)
{
for (pos.X=0; pos.X<(s32)size.Width; ++pos.X)
{
const video::SColor c = image->getPixel(pos.X, pos.Y);
if (c == colorTopLeft)
{
image->setPixel(pos.X, pos.Y, colorBackGroundTransparent);
SpriteBank->getPositions().push_back(core::rect<s32>(pos, pos));
}
else
if (c == colorLowerRight)
{
// too many lower right points
if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions)
{
lowerRightPositions = 0;
return;
}
image->setPixel(pos.X, pos.Y, colorBackGroundTransparent);
SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos;
// add frame to sprite bank
SGUISpriteFrame f;
f.rectNumber = lowerRightPositions;
f.textureNumber = 0;
SGUISprite s;
s.Frames.push_back(f);
s.frameTime = 0;
SpriteBank->getSprites().push_back(s);
// add character to font
SFontArea a;
a.overhang = 0;
a.underhang = 0;
a.spriteno = lowerRightPositions;
a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth();
Areas.push_back(a);
// map letter to character
wchar_t ch = (wchar_t)(lowerRightPositions + 32);
CharacterMap.set(ch, lowerRightPositions);
++lowerRightPositions;
}
else
if (c == colorBackGround)
image->setPixel(pos.X, pos.Y, colorBackGroundTransparent);
}
}
}
//! set an Pixel Offset on Drawing ( scale position on width )
void CGUIFont::setKerningWidth(s32 kerning)
{
GlobalKerningWidth = kerning;
}
//! set an Pixel Offset on Drawing ( scale position on width )
s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const
{
s32 ret = GlobalKerningWidth;
if (thisLetter)
{
ret += Areas[getAreaFromCharacter(*thisLetter)].overhang;
if (previousLetter)
{
ret += Areas[getAreaFromCharacter(*previousLetter)].underhang;
}
}
return ret;
}
//! set an Pixel Offset on Drawing ( scale position on height )
void CGUIFont::setKerningHeight(s32 kerning)
{
GlobalKerningHeight = kerning;
}
//! set an Pixel Offset on Drawing ( scale position on height )
s32 CGUIFont::getKerningHeight () const
{
return GlobalKerningHeight;
}
//! returns the sprite number from a given character
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
{
return Areas[getAreaFromCharacter(*c)].spriteno;
}
s32 CGUIFont::getAreaFromCharacter(const wchar_t c) const
{
core::map<wchar_t, s32>::Node* n = CharacterMap.find(c);
if (n)
return n->getValue();
else
return WrongCharacter;
}
void CGUIFont::setInvisibleCharacters( const wchar_t *s )
{
Invisible = s;
}
//! returns the dimension of text
core::dimension2d<u32> CGUIFont::getDimension(const wchar_t* text) const
{
core::dimension2d<u32> dim(0, 0);
core::dimension2d<u32> thisLine(0, MaxHeight);
for (const wchar_t* p = text; *p; ++p)
{
bool lineBreak=false;
if (*p == L'\r') // Mac or Windows breaks
{
lineBreak = true;
if (p[1] == L'\n') // Windows breaks
++p;
}
else if (*p == L'\n') // Unix breaks
{
lineBreak = true;
}
if (lineBreak)
{
dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width)
dim.Width = thisLine.Width;
thisLine.Width = 0;
continue;
}
const SFontArea &area = Areas[getAreaFromCharacter(*p)];
thisLine.Width += area.underhang;
thisLine.Width += area.width + area.overhang + GlobalKerningWidth;
}
dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width)
dim.Width = thisLine.Width;
return dim;
}
//! draws some text and clips it to the specified rectangle if wanted
void CGUIFont::draw(const core::stringw& text, const core::rect<s32>& position,
video::SColor color,
bool hcenter, bool vcenter, const core::rect<s32>* clip
)
{
if (!Driver || !SpriteBank)
return;
core::dimension2d<s32> textDimension; // NOTE: don't make this u32 or the >> later on can fail when the dimension width is < position width
core::position2d<s32> offset = position.UpperLeftCorner;
if (hcenter || vcenter || clip)
textDimension = getDimension(text.c_str());
if (hcenter)
offset.X += (position.getWidth() - textDimension.Width) >> 1;
if (vcenter)
offset.Y += (position.getHeight() - textDimension.Height) >> 1;
if (clip)
{
core::rect<s32> clippedRect(offset, textDimension);
clippedRect.clipAgainst(*clip);
if (!clippedRect.isValid())
return;
}
core::array<u32> indices(text.size());
core::array<core::position2di> offsets(text.size());
for(u32 i = 0;i < text.size();i++)
{
wchar_t c = text[i];
bool lineBreak=false;
if ( c == L'\r') // Mac or Windows breaks
{
lineBreak = true;
if ( text[i + 1] == L'\n') // Windows breaks
c = text[++i];
}
else if ( c == L'\n') // Unix breaks
{
lineBreak = true;
}
if (lineBreak)
{
offset.Y += MaxHeight;
offset.X = position.UpperLeftCorner.X;
if ( hcenter )
{
offset.X += (position.getWidth() - textDimension.Width) >> 1;
}
continue;
}
SFontArea& area = Areas[getAreaFromCharacter(c)];
offset.X += area.underhang;
if ( Invisible.findFirst ( c ) < 0 )
{
indices.push_back(area.spriteno);
offsets.push_back(offset);
}
offset.X += area.width + area.overhang + GlobalKerningWidth;
}
SpriteBank->draw2DSpriteBatch(indices, offsets, clip, color);
}
//! Calculates the index of the character in the text which is on a specific position.
s32 CGUIFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
{
s32 x = 0;
s32 idx = 0;
while (text[idx])
{
const SFontArea& a = Areas[getAreaFromCharacter(text[idx])];
x += a.width + a.overhang + a.underhang + GlobalKerningWidth;
if (x >= pixel_x)
return idx;
++idx;
}
return -1;
}
IGUISpriteBank* CGUIFont::getSpriteBank() const
{
return SpriteBank;
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+137
View File
@@ -0,0 +1,137 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_FONT_H_INCLUDED__
#define __C_GUI_FONT_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIFontBitmap.h"
#include "irrString.h"
#include "irrMap.h"
#include "IXMLReader.h"
#include "IReadFile.h"
#include "irrArray.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class IImage;
}
namespace gui
{
class IGUIEnvironment;
class CGUIFont : public IGUIFontBitmap
{
public:
//! constructor
CGUIFont(IGUIEnvironment* env, const io::path& filename);
//! destructor
virtual ~CGUIFont();
//! loads a font from a texture file
bool load(const io::path& filename);
//! loads a font from a texture file
bool load(io::IReadFile* file);
//! loads a font from an XML file
bool load(io::IXMLReader* xml);
//! draws an text and clips it to the specified rectangle if wanted
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
video::SColor color, bool hcenter=false,
bool vcenter=false, const core::rect<s32>* clip=0);
virtual void drawQuick(const core::stringw& text, const core::rect<s32>& position,
video::SColor color, bool hcenter=false,
bool vcenter=false, const core::rect<s32>* clip=0)
{
draw(text, position, color, hcenter, vcenter, clip);
}
virtual void draw(const std::vector<GlyphLayout>& gls, const core::rect<s32>& position,
video::SColor color, bool hcenter=false,
bool vcenter=false, const core::rect<s32>* clip=0) {}
virtual void initGlyphLayouts(const core::stringw& text,
std::vector<GlyphLayout>& gls, u32 shape_flag = 0) {}
//! returns the dimension of a text
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const;
//! Calculates the index of the character in the text which is on a specific position.
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const;
//! Returns the type of this font
virtual EGUI_FONT_TYPE getType() const { return EGFT_BITMAP; }
//! set an Pixel Offset on Drawing ( scale position on width )
virtual void setKerningWidth (s32 kerning);
virtual void setKerningHeight (s32 kerning);
virtual s32 getHeightPerLine() const { return (s32)getDimension(L"A").Height + getKerningHeight(); }
//! set an Pixel Offset on Drawing ( scale position on width )
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const;
virtual s32 getKerningHeight() const;
//! gets the sprite bank
virtual IGUISpriteBank* getSpriteBank() const;
//! returns the sprite number from a given character
virtual u32 getSpriteNoFromChar(const wchar_t *c) const;
virtual void setInvisibleCharacters( const wchar_t *s );
virtual void setScale(f32 scale) {}
virtual f32 getInverseShaping() const { return 1.0f; }
virtual f32 getScale() const { return 1.0f; }
private:
struct SFontArea
{
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
s32 underhang;
s32 overhang;
s32 width;
u32 spriteno;
};
//! load & prepare font from ITexture
bool loadTexture(video::IImage * image, const io::path& name);
void readPositions(video::IImage* texture, s32& lowerRightPositions);
s32 getAreaFromCharacter (const wchar_t c) const;
void setMaxHeight();
core::array<SFontArea> Areas;
core::map<wchar_t, s32> CharacterMap;
video::IVideoDriver* Driver;
IGUISpriteBank* SpriteBank;
IGUIEnvironment* Environment;
u32 WrongCharacter;
s32 MaxHeight;
s32 GlobalKerningWidth, GlobalKerningHeight;
core::stringw Invisible;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_FONT_H_INCLUDED__
+163
View File
@@ -0,0 +1,163 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIImage.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIImage::CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUIImage(environment, parent, id, rectangle), Texture(0), Color(255,255,255,255),
UseAlphaChannel(false), ScaleImage(false)
{
#ifdef _DEBUG
setDebugName("CGUIImage");
#endif
}
//! destructor
CGUIImage::~CGUIImage()
{
if (Texture)
Texture->drop();
}
//! sets an image
void CGUIImage::setImage(video::ITexture* image)
{
if (image == Texture)
return;
if (Texture)
Texture->drop();
Texture = image;
if (Texture)
Texture->grab();
}
//! Gets the image texture
video::ITexture* CGUIImage::getImage() const
{
return Texture;
}
//! sets the color of the image
void CGUIImage::setColor(video::SColor color)
{
Color = color;
}
//! Gets the color of the image
video::SColor CGUIImage::getColor() const
{
return Color;
}
//! draws the element and its children
void CGUIImage::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (Texture)
{
//if (ScaleImage)
//{
const video::SColor Colors[] = {Color,Color,Color,Color};
skin->draw2DImage(Texture, AbsoluteRect,
core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(Texture->getOriginalSize())),
&AbsoluteClippingRect, Colors, UseAlphaChannel);
//}
//else
//{
// Environment->getVideoDriver()->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner,
// core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(Texture->getOriginalSize())),
// &AbsoluteClippingRect, Color, UseAlphaChannel);
//}
}
else
{
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), AbsoluteRect, &AbsoluteClippingRect);
}
IGUIElement::draw();
}
//! sets if the image should use its alpha channel to draw itself
void CGUIImage::setUseAlphaChannel(bool use)
{
UseAlphaChannel = use;
}
//! sets if the image should use its alpha channel to draw itself
void CGUIImage::setScaleImage(bool scale)
{
ScaleImage = scale;
}
//! Returns true if the image is scaled to fit, false if not
bool CGUIImage::isImageScaled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ScaleImage;
}
//! Returns true if the image is using the alpha channel, false if not
bool CGUIImage::isAlphaChannelUsed() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return UseAlphaChannel;
}
//! Writes attributes of the element.
void CGUIImage::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIImage::serializeAttributes(out,options);
out->addTexture ("Texture", Texture);
out->addBool ("UseAlphaChannel", UseAlphaChannel);
out->addColor ("Color", Color);
out->addBool ("ScaleImage", ScaleImage);
}
//! Reads attributes of the element
void CGUIImage::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIImage::deserializeAttributes(in,options);
setImage(in->getAttributeAsTexture("Texture"));
setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));
setColor(in->getAttributeAsColor("Color"));
setScaleImage(in->getAttributeAsBool("ScaleImage"));
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+75
View File
@@ -0,0 +1,75 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_IMAGE_H_INCLUDED__
#define __C_GUI_IMAGE_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIImage.h"
namespace irr
{
namespace gui
{
class CGUIImage : public IGUIImage
{
public:
//! constructor
CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! destructor
virtual ~CGUIImage();
//! sets an image
virtual void setImage(video::ITexture* image);
//! Gets the image texture
virtual video::ITexture* getImage() const;
//! sets the color of the image
virtual void setColor(video::SColor color);
//! sets if the image should scale to fit the element
virtual void setScaleImage(bool scale);
//! draws the element and its children
virtual void draw();
//! sets if the image should use its alpha channel to draw itself
virtual void setUseAlphaChannel(bool use);
//! Gets the color of the image
virtual video::SColor getColor() const;
//! Returns true if the image is scaled to fit, false if not
virtual bool isImageScaled() const;
//! Returns true if the image is using the alpha channel, false if not
virtual bool isAlphaChannelUsed() const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
video::ITexture* Texture;
video::SColor Color;
bool UseAlphaChannel;
bool ScaleImage;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_IMAGE_H_INCLUDED__
@@ -0,0 +1,93 @@
// This file is part of the "Irrlicht Engine".
// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de
// modified by Thomas Alten
#include "CGUIImageList.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIImageList::CGUIImageList( video::IVideoDriver* driver )
: Driver( driver ),
Texture( 0 ),
ImageCount( 0 ),
ImageSize( 0, 0 ),
ImagesPerRow( 0 ),
UseAlphaChannel( false )
{
#ifdef _DEBUG
setDebugName( "CGUIImageList" );
#endif
if( Driver )
{
Driver->grab();
}
}
//! destructor
CGUIImageList::~CGUIImageList()
{
if( Driver )
{
Driver->drop();
}
if( Texture )
{
Texture->drop();
}
}
//! Creates the image list from texture.
bool CGUIImageList::createImageList(video::ITexture* texture,
core::dimension2d<s32> imageSize,
bool useAlphaChannel)
{
if( !texture )
{
return false;
}
Texture = texture;
Texture->grab();
ImageSize = imageSize;
ImagesPerRow = Texture->getSize().Width / ImageSize.Width;
ImageCount = ImagesPerRow * Texture->getSize().Height / ImageSize.Height;
UseAlphaChannel = useAlphaChannel;
return true;
}
//! Draws an image and clips it to the specified rectangle if wanted
void CGUIImageList::draw( s32 index, const core::position2d<s32>& destPos,
const core::rect<s32>* clip /*= 0*/ )
{
core::rect<s32> sourceRect;
if( !Driver || index < 0 || index >= ImageCount )
{
return;
}
sourceRect.UpperLeftCorner.X = ( index % ImagesPerRow ) * ImageSize.Width;
sourceRect.UpperLeftCorner.Y = ( index / ImagesPerRow ) * ImageSize.Height;
sourceRect.LowerRightCorner.X = sourceRect.UpperLeftCorner.X + ImageSize.Width;
sourceRect.LowerRightCorner.Y = sourceRect.UpperLeftCorner.Y + ImageSize.Height;
Driver->draw2DImage( Texture, destPos, sourceRect, clip,
video::SColor( 255, 255, 255, 255 ), UseAlphaChannel );
}
} // end namespace gui
} // end namespace irr
@@ -0,0 +1,68 @@
// This file is part of the "Irrlicht Engine".
// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de
#ifndef __C_GUI_IMAGE_LIST_H_INCLUDED__
#define __C_GUI_IMAGE_LIST_H_INCLUDED__
#include "IGUIImageList.h"
#include "IVideoDriver.h"
namespace irr
{
namespace gui
{
class CGUIImageList : public IGUIImageList
{
public:
//! constructor
CGUIImageList( video::IVideoDriver* Driver );
//! destructor
virtual ~CGUIImageList();
//! Creates the image list from texture.
//! \param texture: The texture to use
//! \param imageSize: Size of a single image
//! \param useAlphaChannel: true if the alpha channel from the texture should be used
//! \return
//! true if the image list was created
bool createImageList(
video::ITexture* texture,
core::dimension2d<s32> imageSize,
bool useAlphaChannel );
//! Draws an image and clips it to the specified rectangle if wanted
//! \param index: Index of the image
//! \param destPos: Position of the image to draw
//! \param clip: Optional pointer to a rectalgle against which the text will be clipped.
//! If the pointer is null, no clipping will be done.
virtual void draw( s32 index, const core::position2d<s32>& destPos,
const core::rect<s32>* clip = 0 );
//! Returns the count of Images in the list.
//! \return Returns the count of Images in the list.
virtual s32 getImageCount() const
{ return ImageCount; }
//! Returns the size of the images in the list.
//! \return Returns the size of the images in the list.
virtual core::dimension2d<s32> getImageSize() const
{ return ImageSize; }
private:
video::IVideoDriver* Driver;
video::ITexture* Texture;
s32 ImageCount;
core::dimension2d<s32> ImageSize;
s32 ImagesPerRow;
bool UseAlphaChannel;
};
} // end namespace gui
} // end namespace irr
#endif
@@ -0,0 +1,179 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIInOutFader.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIInOutFader::CGUIInOutFader(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUIInOutFader(environment, parent, id, rectangle)
{
#ifdef _DEBUG
setDebugName("CGUIInOutFader");
#endif
Action = EFA_NOTHING;
StartTime = 0;
EndTime = 0;
setColor(video::SColor(0,0,0,0));
}
//! draws the element and its children
void CGUIInOutFader::draw()
{
if (!IsVisible || !Action)
return;
u32 now = os::Timer::getTime();
if (now > EndTime && Action == EFA_FADE_IN)
{
Action = EFA_NOTHING;
return;
}
video::IVideoDriver* driver = Environment->getVideoDriver();
if (driver)
{
f32 d;
if (now > EndTime)
d = 0.0f;
else
d = (EndTime - now) / (f32)(EndTime - StartTime);
video::SColor newCol = FullColor.getInterpolated(TransColor, d);
driver->draw2DRectangle(newCol, AbsoluteRect, &AbsoluteClippingRect);
}
IGUIElement::draw();
}
//! Gets the color to fade out to or to fade in from.
video::SColor CGUIInOutFader::getColor() const
{
return Color[1];
}
//! Sets the color to fade out to or to fade in from.
void CGUIInOutFader::setColor(video::SColor color)
{
video::SColor s = color;
video::SColor d = color;
s.setAlpha ( 255 );
d.setAlpha ( 0 );
setColor ( s,d );
/*
Color[0] = color;
FullColor = Color[0];
TransColor = Color[0];
if (Action == EFA_FADE_OUT)
{
FullColor.setAlpha(0);
TransColor.setAlpha(255);
}
else
if (Action == EFA_FADE_IN)
{
FullColor.setAlpha(255);
TransColor.setAlpha(0);
}
*/
}
void CGUIInOutFader::setColor(video::SColor source, video::SColor dest)
{
Color[0] = source;
Color[1] = dest;
if (Action == EFA_FADE_OUT)
{
FullColor = Color[1];
TransColor = Color[0];
}
else
if (Action == EFA_FADE_IN)
{
FullColor = Color[0];
TransColor = Color[1];
}
}
//! Returns if the fade in or out process is done.
bool CGUIInOutFader::isReady() const
{
u32 now = os::Timer::getTime();
bool ret = (now > EndTime);
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ret;
}
//! Starts the fade in process.
void CGUIInOutFader::fadeIn(u32 time)
{
StartTime = os::Timer::getTime();
EndTime = StartTime + time;
Action = EFA_FADE_IN;
setColor(Color[0],Color[1]);
}
//! Starts the fade out process.
void CGUIInOutFader::fadeOut(u32 time)
{
StartTime = os::Timer::getTime();
EndTime = StartTime + time;
Action = EFA_FADE_OUT;
setColor(Color[0],Color[1]);
}
//! Writes attributes of the element.
void CGUIInOutFader::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIInOutFader::serializeAttributes(out,options);
out->addColor ("FullColor", FullColor);
out->addColor ("TransColor", TransColor);
}
//! Reads attributes of the element
void CGUIInOutFader::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIInOutFader::deserializeAttributes(in,options);
FullColor = in->getAttributeAsColor("FullColor");
TransColor = in->getAttributeAsColor("TransColor");
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,75 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_IN_OUT_FADER_H_INCLUDED__
#define __C_GUI_IN_OUT_FADER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIInOutFader.h"
namespace irr
{
namespace gui
{
class CGUIInOutFader : public IGUIInOutFader
{
public:
//! constructor
CGUIInOutFader(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle);
//! draws the element and its children
virtual void draw();
//! Gets the color to fade out to or to fade in from.
virtual video::SColor getColor() const;
//! Sets the color to fade out to or to fade in from.
virtual void setColor(video::SColor color );
virtual void setColor(video::SColor source, video::SColor dest);
//! Starts the fade in process.
virtual void fadeIn(u32 time);
//! Starts the fade out process.
virtual void fadeOut(u32 time);
//! Returns if the fade in or out process is done.
virtual bool isReady() const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
enum EFadeAction
{
EFA_NOTHING = 0,
EFA_FADE_IN,
EFA_FADE_OUT
};
u32 StartTime;
u32 EndTime;
EFadeAction Action;
video::SColor Color[2];
video::SColor FullColor;
video::SColor TransColor;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_IN_OUT_FADER_H_INCLUDED__
@@ -0,0 +1,914 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIListBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "CGUIListBox.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "CGUIScrollBar.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool clip,
bool drawBack, bool moveOverSelect)
: IGUIListBox(environment, parent, id, rectangle), Selected(-1),
ItemHeight(0),ItemHeightOverride(0),
TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0),
ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack),
MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true)
{
#ifdef _DEBUG
setDebugName("CGUIListBox");
#endif
IGUISkin* skin = Environment->getSkin();
const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE);
ScrollBar = new CGUIScrollBar(false, Environment, this, -1,
core::rect<s32>(RelativeRect.getWidth() - s, 0, RelativeRect.getWidth(), RelativeRect.getHeight()),
!clip);
ScrollBar->setSubElement(true);
ScrollBar->setTabStop(false);
ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
ScrollBar->setVisible(false);
ScrollBar->setPos(0);
setNotClipped(!clip);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
updateAbsolutePosition();
}
//! destructor
CGUIListBox::~CGUIListBox()
{
if (ScrollBar)
ScrollBar->drop();
if (Font)
Font->drop();
if (IconBank)
IconBank->drop();
}
//! returns amount of list items
u32 CGUIListBox::getItemCount() const
{
return Items.size();
}
//! returns string of a list item. the may be a value from 0 to itemCount-1
const wchar_t* CGUIListBox::getListItem(u32 id) const
{
if (id>=Items.size())
return 0;
return Items[id].text.c_str();
}
//! Returns the icon of an item
s32 CGUIListBox::getIcon(u32 id) const
{
if (id>=Items.size())
return -1;
return Items[id].icon;
}
//! adds a list item, returns id of item
u32 CGUIListBox::addItem(const wchar_t* text)
{
return addItem(text, -1);
}
//! adds a list item, returns id of item
void CGUIListBox::removeItem(u32 id)
{
if (id >= Items.size())
return;
if ((u32)Selected==id)
{
Selected = -1;
}
else if ((u32)Selected > id)
{
Selected -= 1;
selectTime = os::Timer::getTime();
}
Items.erase(id);
recalculateItemHeight();
}
s32 CGUIListBox::getItemAt(s32 xpos, s32 ypos) const
{
if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X
|| ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y
)
return -1;
if ( ItemHeight == 0 )
return -1;
s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight;
if ( item < 0 || item >= (s32)Items.size())
return -1;
return item;
}
//! clears the list
void CGUIListBox::clear()
{
Items.clear();
ItemsIconWidth = 0;
Selected = -1;
if (ScrollBar)
ScrollBar->setPos(0);
recalculateItemHeight();
}
void CGUIListBox::recalculateItemHeight()
{
IGUISkin* skin = Environment->getSkin();
if (Font != skin->getFont())
{
if (Font)
Font->drop();
Font = skin->getFont();
if ( 0 == ItemHeightOverride )
ItemHeight = 0;
if (Font)
{
if ( 0 == ItemHeightOverride )
ItemHeight = Font->getDimension(L"A").Height + 4;
Font->grab();
}
}
TotalItemHeight = ItemHeight * Items.size();
ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) );
s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1;
ScrollBar->setSmallStep ( minItemHeight );
ScrollBar->setLargeStep ( 2*minItemHeight );
if ( TotalItemHeight <= AbsoluteRect.getHeight() )
ScrollBar->setVisible(false);
else
ScrollBar->setVisible(true);
}
//! returns id of selected item. returns -1 if no item is selected.
s32 CGUIListBox::getSelected() const
{
return Selected;
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUIListBox::setSelected(s32 id)
{
if ((u32)id>=Items.size())
Selected = -1;
else
Selected = id;
selectTime = os::Timer::getTime();
recalculateScrollPos();
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUIListBox::setSelected(const wchar_t *item)
{
s32 index = -1;
if ( item )
{
for ( index = 0; index < (s32) Items.size(); ++index )
{
if ( Items[index].text == item )
break;
}
}
setSelected ( index );
}
//! called if an event happened.
bool CGUIListBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == IRR_KEY_DOWN ||
event.KeyInput.Key == IRR_KEY_UP ||
event.KeyInput.Key == IRR_KEY_HOME ||
event.KeyInput.Key == IRR_KEY_END ||
event.KeyInput.Key == IRR_KEY_NEXT ||
event.KeyInput.Key == IRR_KEY_PRIOR))
{
s32 oldSelected = Selected;
switch (event.KeyInput.Key)
{
case IRR_KEY_DOWN:
Selected += 1;
break;
case IRR_KEY_UP:
Selected -= 1;
break;
case IRR_KEY_HOME:
Selected = 0;
break;
case IRR_KEY_END:
Selected = (s32)Items.size()-1;
break;
case IRR_KEY_NEXT:
Selected += AbsoluteRect.getHeight() / ItemHeight;
break;
case IRR_KEY_PRIOR:
Selected -= AbsoluteRect.getHeight() / ItemHeight;
break;
default:
break;
}
if (Selected >= (s32)Items.size())
Selected = Items.size() - 1;
else
if (Selected<0)
Selected = 0;
recalculateScrollPos();
// post the news
if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
Parent->OnEvent(e);
}
return true;
}
else
if (!event.KeyInput.PressedDown &&
(event.KeyInput.Key == IRR_KEY_RETURN ||
event.KeyInput.Key == IRR_KEY_SPACE))
{
if (Parent)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN;
Parent->OnEvent(e);
}
return true;
}
else if (event.KeyInput.PressedDown && event.KeyInput.Char)
{
// change selection based on text as it is typed.
u32 now = os::Timer::getTime();
if (now - LastKeyTime < 500)
{
// add to key buffer if it isn't a key repeat
if (!(KeyBuffer.size() == 1 && KeyBuffer[0] == event.KeyInput.Char))
{
KeyBuffer += L" ";
KeyBuffer[KeyBuffer.size()-1] = event.KeyInput.Char;
}
}
else
{
KeyBuffer = L" ";
KeyBuffer[0] = event.KeyInput.Char;
}
LastKeyTime = now;
// find the selected item, starting at the current selection
s32 start = Selected;
// dont change selection if the key buffer matches the current item
if (Selected > -1 && KeyBuffer.size() > 1)
{
if (Items[Selected].text.size() >= KeyBuffer.size() &&
KeyBuffer.equals_ignore_case(Items[Selected].text.subString(0,KeyBuffer.size())))
return true;
}
s32 current;
for (current = start+1; current < (s32)Items.size(); ++current)
{
if (Items[current].text.size() >= KeyBuffer.size())
{
if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size())))
{
if (Parent && Selected != current && !Selecting && !MoveOverSelect)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
Parent->OnEvent(e);
}
setSelected(current);
return true;
}
}
}
for (current = 0; current <= start; ++current)
{
if (Items[current].text.size() >= KeyBuffer.size())
{
if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size())))
{
if (Parent && Selected != current && !Selecting && !MoveOverSelect)
{
Selected = current;
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
Parent->OnEvent(e);
}
setSelected(current);
return true;
}
}
}
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_SCROLL_BAR_CHANGED:
if (event.GUIEvent.Caller == ScrollBar)
return true;
break;
case gui::EGET_ELEMENT_FOCUS_LOST:
{
if (event.GUIEvent.Caller == this)
Selecting = false;
}
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2);
return true;
case EMIE_LMOUSE_PRESSED_DOWN:
{
Selecting = true;
return true;
}
case EMIE_LMOUSE_LEFT_UP:
{
Selecting = false;
if (isPointInside(p))
selectNew(event.MouseInput.Y);
return true;
}
case EMIE_MOUSE_MOVED:
if (Selecting || MoveOverSelect)
{
if (isPointInside(p))
{
selectNew(event.MouseInput.Y, true);
return true;
}
}
default:
break;
}
}
break;
case EET_LOG_TEXT_EVENT:
case EET_USER_EVENT:
case EET_JOYSTICK_INPUT_EVENT:
case EEVENT_TYPE::EGUIET_FORCE_32_BIT:
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUIListBox::selectNew(s32 ypos, bool onlyHover)
{
u32 now = os::Timer::getTime();
s32 oldSelected = Selected;
Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos);
if (Selected<0 && !Items.empty())
Selected = 0;
recalculateScrollPos();
gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED;
selectTime = now;
// post the news
if (Parent && !onlyHover)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = eventType;
Parent->OnEvent(event);
}
}
//! Update the position and size of the listbox, and update the scrollbar
void CGUIListBox::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
recalculateItemHeight();
}
//! draws the element and its children
void CGUIListBox::draw()
{
if (!IsVisible)
return;
recalculateItemHeight(); // if the font changed
IGUISkin* skin = Environment->getSkin();
core::rect<s32>* clipRect = 0;
// draw background
core::rect<s32> frameRect(AbsoluteRect);
// draw items
core::rect<s32> clientClip(AbsoluteRect);
clientClip.UpperLeftCorner.Y += 1;
clientClip.UpperLeftCorner.X += 1;
if (ScrollBar->isVisible())
clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
clientClip.LowerRightCorner.Y -= 1;
clientClip.clipAgainst(AbsoluteClippingRect);
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true,
DrawBack, frameRect, &clientClip);
if (clipRect)
clientClip.clipAgainst(*clipRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.X += 1;
if (ScrollBar->isVisible())
frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight;
frameRect.UpperLeftCorner.Y -= ScrollBar->getPos();
frameRect.LowerRightCorner.Y -= ScrollBar->getPos();
bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar));
for (s32 i=0; i<(s32)Items.size(); ++i)
{
if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y &&
frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
{
if (i == Selected && hl)
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip);
core::rect<s32> textRect = frameRect;
textRect.UpperLeftCorner.X += 3;
if (Font)
{
if (IconBank && (Items[i].icon > -1))
{
core::position2di iconPos = textRect.UpperLeftCorner;
iconPos.Y += textRect.getHeight() / 2;
iconPos.X += ItemsIconWidth/2;
if ( i==Selected && hl )
{
IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip,
hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ?
getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT),
selectTime, os::Timer::getTime(), false, true);
}
else
{
IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip,
hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON),
0 , (i==Selected) ? os::Timer::getTime() : 0, false, true);
}
}
textRect.UpperLeftCorner.X += ItemsIconWidth+3;
if ( i==Selected && hl )
{
Font->draw(Items[i].text.c_str(), textRect,
hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ?
getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT),
false, true, &clientClip);
}
else
{
Font->draw(Items[i].text.c_str(), textRect,
hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT),
false, true, &clientClip);
}
textRect.UpperLeftCorner.X -= ItemsIconWidth+3;
}
}
frameRect.UpperLeftCorner.Y += ItemHeight;
frameRect.LowerRightCorner.Y += ItemHeight;
}
IGUIElement::draw();
}
//! adds an list item with an icon
u32 CGUIListBox::addItem(const wchar_t* text, s32 icon)
{
ListItem i;
i.text = text;
i.icon = icon;
Items.push_back(i);
recalculateItemHeight();
recalculateItemWidth(icon);
return Items.size() - 1;
}
void CGUIListBox::setSpriteBank(IGUISpriteBank* bank)
{
if ( bank == IconBank )
return;
if (IconBank)
IconBank->drop();
IconBank = bank;
if (IconBank)
IconBank->grab();
}
void CGUIListBox::recalculateScrollPos()
{
if (!AutoScroll)
return;
const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos();
if (selPos < 0)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos);
}
else
if (selPos > AbsoluteRect.getHeight() - ItemHeight)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight);
}
}
void CGUIListBox::setAutoScrollEnabled(bool scroll)
{
AutoScroll = scroll;
}
bool CGUIListBox::isAutoScrollEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return AutoScroll;
}
bool CGUIListBox::getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) const
{
switch ( colorType )
{
case EGUI_LBC_TEXT:
useColorLabel = "UseColText";
colorLabel = "ColText";
break;
case EGUI_LBC_TEXT_HIGHLIGHT:
useColorLabel = "UseColTextHl";
colorLabel = "ColTextHl";
break;
case EGUI_LBC_ICON:
useColorLabel = "UseColIcon";
colorLabel = "ColIcon";
break;
case EGUI_LBC_ICON_HIGHLIGHT:
useColorLabel = "UseColIconHl";
colorLabel = "ColIconHl";
break;
default:
return false;
}
return true;
}
//! Writes attributes of the element.
void CGUIListBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIListBox::serializeAttributes(out,options);
// todo: out->addString ("IconBank", IconBank->getName?);
out->addBool ("DrawBack", DrawBack);
out->addBool ("MoveOverSelect", MoveOverSelect);
out->addBool ("AutoScroll", AutoScroll);
out->addInt("ItemCount", Items.size());
for (u32 i=0;i<Items.size(); ++i)
{
core::stringc label("text");
label += i;
out->addString(label.c_str(), Items[i].text.c_str() );
for ( s32 c=0; c < (s32)EGUI_LBC_COUNT; ++c )
{
core::stringc useColorLabel, colorLabel;
if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) )
return;
label = useColorLabel; label += i;
if ( Items[i].OverrideColors[c].Use )
{
out->addBool(label.c_str(), true );
label = colorLabel; label += i;
out->addColor(label.c_str(), Items[i].OverrideColors[c].Color);
}
else
{
out->addBool(label.c_str(), false );
}
}
}
}
//! Reads attributes of the element
void CGUIListBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
clear();
DrawBack = in->getAttributeAsBool("DrawBack");
MoveOverSelect = in->getAttributeAsBool("MoveOverSelect");
AutoScroll = in->getAttributeAsBool("AutoScroll");
IGUIListBox::deserializeAttributes(in,options);
const s32 count = in->getAttributeAsInt("ItemCount");
for (s32 i=0; i<count; ++i)
{
core::stringc label("text");
ListItem item;
label += i;
item.text = in->getAttributeAsStringW(label.c_str());
addItem(item.text.c_str(), item.icon);
for ( u32 c=0; c < EGUI_LBC_COUNT; ++c )
{
core::stringc useColorLabel, colorLabel;
if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) )
return;
label = useColorLabel; label += i;
Items[i].OverrideColors[c].Use = in->getAttributeAsBool(label.c_str());
if ( Items[i].OverrideColors[c].Use )
{
label = colorLabel; label += i;
Items[i].OverrideColors[c].Color = in->getAttributeAsColor(label.c_str());
}
}
}
}
void CGUIListBox::recalculateItemWidth(s32 icon)
{
if (IconBank && icon > -1 &&
IconBank->getSprites().size() > (u32)icon &&
IconBank->getSprites()[(u32)icon].Frames.size())
{
u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber;
if (IconBank->getPositions().size() > rno)
{
const s32 w = IconBank->getPositions()[rno].getWidth();
if (w > ItemsIconWidth)
ItemsIconWidth = w;
}
}
}
void CGUIListBox::setItem(u32 index, const wchar_t* text, s32 icon)
{
if ( index >= Items.size() )
return;
Items[index].text = text;
Items[index].icon = icon;
recalculateItemHeight();
recalculateItemWidth(icon);
}
//! Insert the item at the given index
//! Return the index on success or -1 on failure.
s32 CGUIListBox::insertItem(u32 index, const wchar_t* text, s32 icon)
{
ListItem i;
i.text = text;
i.icon = icon;
Items.insert(i, index);
recalculateItemHeight();
recalculateItemWidth(icon);
return index;
}
void CGUIListBox::swapItems(u32 index1, u32 index2)
{
if ( index1 >= Items.size() || index2 >= Items.size() )
return;
ListItem dummmy = Items[index1];
Items[index1] = Items[index2];
Items[index2] = dummmy;
}
void CGUIListBox::setItemOverrideColor(u32 index, video::SColor color)
{
for ( u32 c=0; c < EGUI_LBC_COUNT; ++c )
{
Items[index].OverrideColors[c].Use = true;
Items[index].OverrideColors[c].Color = color;
}
}
void CGUIListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color)
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return;
Items[index].OverrideColors[colorType].Use = true;
Items[index].OverrideColors[colorType].Color = color;
}
void CGUIListBox::clearItemOverrideColor(u32 index)
{
for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c )
{
Items[index].OverrideColors[c].Use = false;
}
}
void CGUIListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType)
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return;
Items[index].OverrideColors[colorType].Use = false;
}
bool CGUIListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return false;
return Items[index].OverrideColors[colorType].Use;
}
video::SColor CGUIListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
{
if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return video::SColor();
return Items[index].OverrideColors[colorType].Color;
}
video::SColor CGUIListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const
{
IGUISkin* skin = Environment->getSkin();
if ( !skin )
return video::SColor();
switch ( colorType )
{
case EGUI_LBC_TEXT:
return skin->getColor(EGDC_BUTTON_TEXT);
case EGUI_LBC_TEXT_HIGHLIGHT:
return skin->getColor(EGDC_HIGH_LIGHT_TEXT);
case EGUI_LBC_ICON:
return skin->getColor(EGDC_ICON);
case EGUI_LBC_ICON_HIGHLIGHT:
return skin->getColor(EGDC_ICON_HIGH_LIGHT);
default:
return video::SColor();
}
}
//! set global itemHeight
void CGUIListBox::setItemHeight( s32 height )
{
ItemHeight = height;
ItemHeightOverride = 1;
}
//! Sets whether to draw the background
void CGUIListBox::setDrawBackground(bool draw)
{
DrawBack = draw;
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+190
View File
@@ -0,0 +1,190 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_LIST_BOX_H_INCLUDED__
#define __C_GUI_LIST_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIListBox.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class IGUIFont;
class IGUIScrollBar;
class CGUIListBox : public IGUIListBox
{
public:
//! constructor
CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool clip=true,
bool drawBack=false, bool moveOverSelect=false);
//! destructor
virtual ~CGUIListBox();
//! returns amount of list items
virtual u32 getItemCount() const;
//! returns string of a list item. the id may be a value from 0 to itemCount-1
virtual const wchar_t* getListItem(u32 id) const;
//! adds an list item, returns id of item
virtual u32 addItem(const wchar_t* text);
//! clears the list
virtual void clear();
//! returns id of selected item. returns -1 if no item is selected.
virtual s32 getSelected() const;
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelected(s32 id);
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelected(const wchar_t *item);
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! adds an list item with an icon
//! \param text Text of list entry
//! \param icon Sprite index of the Icon within the current sprite bank. Set it to -1 if you want no icon
//! \return
//! returns the id of the new created item
virtual u32 addItem(const wchar_t* text, s32 icon);
//! Returns the icon of an item
virtual s32 getIcon(u32 id) const;
//! removes an item from the list
virtual void removeItem(u32 id);
//! get the the id of the item at the given absolute coordinates
virtual s32 getItemAt(s32 xpos, s32 ypos) const;
//! Sets the sprite bank which should be used to draw list icons. This font is set to the sprite bank of
//! the built-in-font by default. A sprite can be displayed in front of every list item.
//! An icon is an index within the icon sprite bank. Several default icons are available in the
//! skin through getIcon
virtual void setSpriteBank(IGUISpriteBank* bank);
//! set whether the listbox should scroll to newly selected items
virtual void setAutoScrollEnabled(bool scroll);
//! returns true if automatic scrolling is enabled, false if not.
virtual bool isAutoScrollEnabled() const;
//! Update the position and size of the listbox, and update the scrollbar
virtual void updateAbsolutePosition();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
//! set all item colors at given index to color
virtual void setItemOverrideColor(u32 index, video::SColor color);
//! set all item colors of specified type at given index to color
virtual void setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color);
//! clear all item colors at index
virtual void clearItemOverrideColor(u32 index);
//! clear item color at index for given colortype
virtual void clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType);
//! has the item at index its color overwritten?
virtual bool hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const;
//! return the overwrite color at given item index.
virtual video::SColor getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const;
//! return the default color which is used for the given colorType
virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const;
//! set the item at the given index
virtual void setItem(u32 index, const wchar_t* text, s32 icon);
//! Insert the item at the given index
//! Return the index on success or -1 on failure.
virtual s32 insertItem(u32 index, const wchar_t* text, s32 icon);
//! Swap the items at the given indices
virtual void swapItems(u32 index1, u32 index2);
//! set global itemHeight
virtual void setItemHeight( s32 height );
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
private:
struct ListItem
{
ListItem() : icon(-1)
{}
core::stringw text;
s32 icon;
// A multicolor extension
struct ListItemOverrideColor
{
ListItemOverrideColor() : Use(false) {}
bool Use;
video::SColor Color;
};
ListItemOverrideColor OverrideColors[EGUI_LBC_COUNT];
};
void recalculateItemHeight();
void selectNew(s32 ypos, bool onlyHover=false);
void recalculateScrollPos();
// extracted that function to avoid copy&paste code
void recalculateItemWidth(s32 icon);
// get labels used for serialization
bool getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) const;
core::array< ListItem > Items;
s32 Selected;
s32 ItemHeight;
s32 ItemHeightOverride;
s32 TotalItemHeight;
s32 ItemsIconWidth;
gui::IGUIFont* Font;
gui::IGUISpriteBank* IconBank;
gui::IGUIScrollBar* ScrollBar;
u32 selectTime;
u32 LastKeyTime;
core::stringw KeyBuffer;
bool Selecting;
bool DrawBack;
bool MoveOverSelect;
bool AutoScroll;
bool HighlightWhenNotFocused;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
+294
View File
@@ -0,0 +1,294 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIMenu.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "IGUIWindow.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIMenu::CGUIMenu(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle)
: CGUIContextMenu(environment, parent, id, rectangle, false, true)
{
#ifdef _DEBUG
setDebugName("CGUIMenu");
#endif
Type = EGUIET_MENU;
setNotClipped(false);
recalculateSize();
}
//! draws the element and its children
void CGUIMenu::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
IGUIFont* font = skin->getFont(EGDF_MENU);
if (font != LastFont)
{
if (LastFont)
LastFont->drop();
LastFont = font;
if (LastFont)
LastFont->grab();
recalculateSize();
}
core::rect<s32> rect = AbsoluteRect;
// draw frame
skin->draw3DToolBar(this, rect, &AbsoluteClippingRect);
// loop through all menu items
rect = AbsoluteRect;
for (s32 i=0; i<(s32)Items.size(); ++i)
{
if (!Items[i].IsSeparator)
{
rect = getRect(Items[i], AbsoluteRect);
// draw highlighted
if (i == HighLighted && Items[i].Enabled)
{
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_DARK_SHADOW),
true, true, rect, &AbsoluteClippingRect);
}
// draw text
EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT;
if (i == HighLighted)
c = EGDC_HIGH_LIGHT_TEXT;
if (!Items[i].Enabled)
c = EGDC_GRAY_TEXT;
if (font)
font->draw(Items[i].Text.c_str(), rect,
skin->getColor(c), true, true, &AbsoluteClippingRect);
}
}
IGUIElement::draw();
}
//! called if an event happened.
bool CGUIMenu::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element))
{
closeAllSubMenus();
HighLighted = -1;
}
break;
case gui::EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller == this && Parent)
{
Parent->bringToFront(this);
}
break;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
{
if (!Environment->hasFocus(this))
{
Environment->setFocus(this);
}
if (Parent)
Parent->bringToFront(this);
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
bool shouldCloseSubMenu = hasOpenSubMenu();
if (!AbsoluteClippingRect.isPointInside(p))
{
shouldCloseSubMenu = false;
}
highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
if ( shouldCloseSubMenu )
{
Environment->removeFocus(this);
}
return true;
}
case EMIE_LMOUSE_LEFT_UP:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
if (!AbsoluteClippingRect.isPointInside(p))
{
s32 t = sendClick(p);
if ((t==0 || t==1) && Environment->hasFocus(this))
Environment->removeFocus(this);
}
return true;
}
case EMIE_MOUSE_MOVED:
if (Environment->hasFocus(this) && HighLighted >= 0)
{
s32 oldHighLighted = HighLighted;
highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
if ( HighLighted < 0 )
HighLighted = oldHighLighted; // keep last hightlight active when moving outside the area
}
return true;
default:
break;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUIMenu::recalculateSize()
{
core::rect<s32> clientRect; // client rect of parent
if ( Parent && Parent->hasType(EGUIET_WINDOW) )
{
clientRect = static_cast<IGUIWindow*>(Parent)->getClientRect();
}
else if ( Parent )
{
clientRect = core::rect<s32>(0,0, Parent->getAbsolutePosition().getWidth(),
Parent->getAbsolutePosition().getHeight());
}
else
{
clientRect = RelativeRect;
}
IGUISkin* skin = Environment->getSkin();
IGUIFont* font = skin->getFont(EGDF_MENU);
if (!font)
{
if (Parent && skin)
RelativeRect = core::rect<s32>(clientRect.UpperLeftCorner.X, clientRect.UpperLeftCorner.Y,
clientRect.LowerRightCorner.X, clientRect.UpperLeftCorner.Y+skin->getSize(EGDS_MENU_HEIGHT));
return;
}
core::rect<s32> rect;
rect.UpperLeftCorner = clientRect.UpperLeftCorner;
s32 height = font->getDimension(L"A").Height + 5;
//if (skin && height < skin->getSize ( EGDS_MENU_HEIGHT ))
// height = skin->getSize(EGDS_MENU_HEIGHT);
s32 width = rect.UpperLeftCorner.X;
s32 i;
for (i=0; i<(s32)Items.size(); ++i)
{
if (Items[i].IsSeparator)
{
Items[i].Dim.Width = 0;
Items[i].Dim.Height = height;
}
else
{
Items[i].Dim = font->getDimension(Items[i].Text.c_str());
Items[i].Dim.Width += 20;
}
Items[i].PosY = width;
width += Items[i].Dim.Width;
}
width = clientRect.getWidth();
rect.LowerRightCorner.X = rect.UpperLeftCorner.X + width;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + height;
setRelativePosition(rect);
// recalculate submenus
for (i=0; i<(s32)Items.size(); ++i)
if (Items[i].SubMenu)
{
// move submenu
s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth();
s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight();
Items[i].SubMenu->setRelativePosition(
core::rect<s32>(Items[i].PosY, height ,
Items[i].PosY+w-5, height+h));
}
}
//! returns the item highlight-area
core::rect<s32> CGUIMenu::getHRect(const SItem& i, const core::rect<s32>& absolute) const
{
core::rect<s32> r = absolute;
r.UpperLeftCorner.X += i.PosY;
r.LowerRightCorner.X = r.UpperLeftCorner.X + i.Dim.Width;
return r;
}
//! Gets drawing rect of Item
core::rect<s32> CGUIMenu::getRect(const SItem& i, const core::rect<s32>& absolute) const
{
return getHRect(i, absolute);
}
void CGUIMenu::updateAbsolutePosition()
{
if (Parent)
DesiredRect.LowerRightCorner.X = Parent->getAbsolutePosition().getWidth();
IGUIElement::updateAbsolutePosition();
}
} // end namespace
} // end namespace
#endif // _IRR_COMPILE_WITH_GUI_
+52
View File
@@ -0,0 +1,52 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_MENU_H_INCLUDED__
#define __C_GUI_MENU_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "CGUIContextMenu.h"
namespace irr
{
namespace gui
{
//! GUI menu interface.
class CGUIMenu : public CGUIContextMenu
{
public:
//! constructor
CGUIMenu(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! draws the element and its children
virtual void draw();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! Updates the absolute position.
virtual void updateAbsolutePosition();
protected:
virtual void recalculateSize();
//! returns the item highlight-area
virtual core::rect<s32> getHRect(const SItem& i, const core::rect<s32>& absolute) const;
//! Gets drawing rect of Item
virtual core::rect<s32> getRect(const SItem& i, const core::rect<s32>& absolute) const;
};
} // end namespace gui
} // end namespace irr
#endif // __C_GUI_MENU_H_INCLUDED__
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,171 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIMeshViewer.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IAnimatedMesh.h"
#include "IMesh.h"
#include "os.h"
#include "IGUISkin.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIMeshViewer::CGUIMeshViewer(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUIMeshViewer(environment, parent, id, rectangle), Mesh(0)
{
#ifdef _DEBUG
setDebugName("CGUIMeshViewer");
#endif
}
//! destructor
CGUIMeshViewer::~CGUIMeshViewer()
{
if (Mesh)
Mesh->drop();
}
//! sets the mesh to be shown
void CGUIMeshViewer::setMesh(scene::IAnimatedMesh* mesh)
{
if (mesh)
mesh->grab();
if (Mesh)
Mesh->drop();
Mesh = mesh;
/* This might be used for proper transformation etc.
core::vector3df center(0.0f,0.0f,0.0f);
core::aabbox3d<f32> box;
box = Mesh->getMesh(0)->getBoundingBox();
center = (box.MaxEdge + box.MinEdge) / 2;
*/
}
//! Gets the displayed mesh
scene::IAnimatedMesh* CGUIMeshViewer::getMesh() const
{
return Mesh;
}
//! sets the material
void CGUIMeshViewer::setMaterial(const video::SMaterial& material)
{
Material = material;
}
//! gets the material
const video::SMaterial& CGUIMeshViewer::getMaterial() const
{
return Material;
}
//! called if an event happened.
bool CGUIMeshViewer::OnEvent(const SEvent& event)
{
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUIMeshViewer::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> viewPort = AbsoluteRect;
viewPort.LowerRightCorner.X -= 1;
viewPort.LowerRightCorner.Y -= 1;
viewPort.UpperLeftCorner.X += 1;
viewPort.UpperLeftCorner.Y += 1;
viewPort.clipAgainst(AbsoluteClippingRect);
// draw the frame
core::rect<s32> frameRect(AbsoluteRect);
frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);
// draw the mesh
if (Mesh)
{
//TODO: if outside of screen, dont draw.
// - why is the absolute clipping rect not already the screen?
core::rect<s32> oldViewPort = driver->getViewPort();
driver->setViewPort(viewPort);
core::matrix4 mat;
//CameraControl->calculateProjectionMatrix(mat);
//driver->setTransform(video::TS_PROJECTION, mat);
mat.makeIdentity();
mat.setTranslation(core::vector3df(0,0,0));
driver->setTransform(video::ETS_WORLD, mat);
//CameraControl->calculateViewMatrix(mat);
//driver->setTransform(video::TS_VIEW, mat);
driver->setMaterial(Material);
u32 frame = 0;
if(Mesh->getFrameCount())
frame = (os::Timer::getTime()/20)%Mesh->getFrameCount();
const scene::IMesh* const m = Mesh->getMesh(frame);
for (u32 i=0; i<m->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* mb = m->getMeshBuffer(i);
driver->drawVertexPrimitiveList(mb->getVertices(),
mb->getVertexCount(), mb->getIndices(),
mb->getIndexCount()/ 3, mb->getVertexType(),
scene::EPT_TRIANGLES, mb->getIndexType());
}
driver->setViewPort(oldViewPort);
}
IGUIElement::draw();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,61 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_MESH_VIEWER_H_INCLUDED__
#define __C_GUI_MESH_VIEWER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIMeshViewer.h"
#include "SMaterial.h"
namespace irr
{
namespace gui
{
class CGUIMeshViewer : public IGUIMeshViewer
{
public:
//! constructor
CGUIMeshViewer(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! destructor
virtual ~CGUIMeshViewer();
//! sets the mesh to be shown
virtual void setMesh(scene::IAnimatedMesh* mesh);
//! Gets the displayed mesh
virtual scene::IAnimatedMesh* getMesh() const;
//! sets the material
virtual void setMaterial(const video::SMaterial& material);
//! gets the material
virtual const video::SMaterial& getMaterial() const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
private:
video::SMaterial Material;
scene::IAnimatedMesh* Mesh;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_MESH_VIEWER_H_INCLUDED__
@@ -0,0 +1,463 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIMessageBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IGUIButton.h"
#include "IGUIFont.h"
#include "ITexture.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption,
const wchar_t* text, s32 flags,
IGUIElement* parent, s32 id, core::rect<s32> rectangle, video::ITexture* image)
: CGUIWindow(environment, parent, id, rectangle),
OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0),
Icon(0), IconTexture(image),
Flags(flags), MessageText(text), Pressed(false)
{
#ifdef _DEBUG
setDebugName("CGUIMessageBox");
#endif
// set element type
Type = EGUIET_MESSAGE_BOX;
// remove focus
Environment->setFocus(0);
// remove buttons
getMaximizeButton()->remove();
getMinimizeButton()->remove();
if (caption)
setText(caption);
Environment->setFocus(this);
if ( IconTexture )
IconTexture->grab();
refreshControls();
}
//! destructor
CGUIMessageBox::~CGUIMessageBox()
{
if (StaticText)
StaticText->drop();
if (OkButton)
OkButton->drop();
if (CancelButton)
CancelButton->drop();
if (YesButton)
YesButton->drop();
if (NoButton)
NoButton->drop();
if (Icon)
Icon->drop();
if ( IconTexture )
IconTexture->drop();
}
void CGUIMessageBox::setButton(IGUIButton*& button, bool isAvailable, const core::rect<s32> & btnRect, const wchar_t * text, IGUIElement*& focusMe)
{
// add/remove ok button
if (isAvailable)
{
if (!button)
{
button = Environment->addButton(btnRect, this);
button->setSubElement(true);
button->grab();
}
else
button->setRelativePosition(btnRect);
button->setText(text);
focusMe = button;
}
else if (button)
{
button->drop();
button->remove();
button =0;
}
}
void CGUIMessageBox::refreshControls()
{
// Layout can be seen as 4 boxes (a layoutmanager would be nice)
// One box at top over the whole width for title
// Two boxes with same height at the middle beside each other for icon and for text
// One box at the bottom for the buttons
const IGUISkin* skin = Environment->getSkin();
const s32 buttonHeight = skin->getSize(EGDS_BUTTON_HEIGHT);
const s32 buttonWidth = skin->getSize(EGDS_BUTTON_WIDTH);
const s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; // titlebar has no own constant
const s32 buttonDistance = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
const s32 borderWidth = skin->getSize(EGDS_MESSAGE_BOX_GAP_SPACE);
// add the static text for the message
core::rect<s32> staticRect;
staticRect.UpperLeftCorner.X = borderWidth;
staticRect.UpperLeftCorner.Y = titleHeight + borderWidth;
staticRect.LowerRightCorner.X = staticRect.UpperLeftCorner.X + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH);
staticRect.LowerRightCorner.Y = staticRect.UpperLeftCorner.Y + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT);
if (!StaticText)
{
StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this);
StaticText->setWordWrap(true);
StaticText->setSubElement(true);
StaticText->grab();
}
else
{
StaticText->setRelativePosition(staticRect);
StaticText->setText(MessageText.c_str());
}
s32 textHeight = StaticText->getTextHeight();
s32 textWidth = StaticText->getTextWidth() + 6; // +6 because the static itself needs that
const s32 iconHeight = IconTexture ? IconTexture->getOriginalSize().Height : 0;
if ( textWidth < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) )
textWidth = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) + 6;
// no neeed to check for max because it couldn't get larger due to statictextbox.
if ( textHeight < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT) )
textHeight = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT);
if ( textHeight > skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT) )
textHeight = skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT);
// content is text + icons + borders (but not titlebar)
s32 contentHeight = textHeight > iconHeight ? textHeight : iconHeight;
contentHeight += borderWidth;
s32 contentWidth = 0;
// add icon
if ( IconTexture )
{
core::position2d<s32> iconPos;
iconPos.Y = titleHeight + borderWidth;
if ( iconHeight < textHeight )
iconPos.Y += (textHeight-iconHeight) / 2;
iconPos.X = borderWidth;
if (!Icon)
{
Icon = Environment->addImage(IconTexture, iconPos, true, this);
Icon->setSubElement(true);
Icon->grab();
}
else
{
core::rect<s32> iconRect( iconPos.X, iconPos.Y, iconPos.X + IconTexture->getOriginalSize().Width, iconPos.Y + IconTexture->getOriginalSize().Height );
Icon->setRelativePosition(iconRect);
}
contentWidth += borderWidth + IconTexture->getOriginalSize().Width;
}
else if ( Icon )
{
Icon->drop();
Icon->remove();
Icon = 0;
}
// position text
core::rect<s32> textRect;
textRect.UpperLeftCorner.X = contentWidth + borderWidth;
textRect.UpperLeftCorner.Y = titleHeight + borderWidth;
if ( textHeight < iconHeight )
textRect.UpperLeftCorner.Y += (iconHeight-textHeight) / 2;
textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + textWidth;
textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + textHeight;
contentWidth += 2*borderWidth + textWidth;
StaticText->setRelativePosition( textRect );
// find out button size needs
s32 countButtons = 0;
if (Flags & EMBF_OK)
++countButtons;
if (Flags & EMBF_CANCEL)
++countButtons;
if (Flags & EMBF_YES)
++countButtons;
if (Flags & EMBF_NO)
++countButtons;
s32 buttonBoxWidth = countButtons * buttonWidth + 2 * borderWidth;
if ( countButtons > 1 )
buttonBoxWidth += (countButtons-1) * buttonDistance;
s32 buttonBoxHeight = buttonHeight + 2 * borderWidth;
// calc new message box sizes
core::rect<s32> tmp = getRelativePosition();
s32 msgBoxHeight = titleHeight + contentHeight + buttonBoxHeight;
s32 msgBoxWidth = contentWidth > buttonBoxWidth ? contentWidth : buttonBoxWidth;
// adjust message box position
tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2;
tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight;
tmp.UpperLeftCorner.X = (Parent->getAbsolutePosition().getWidth() - msgBoxWidth) / 2;
tmp.LowerRightCorner.X = tmp.UpperLeftCorner.X + msgBoxWidth;
setRelativePosition(tmp);
// add buttons
core::rect<s32> btnRect;
btnRect.UpperLeftCorner.Y = titleHeight + contentHeight + borderWidth;
btnRect.LowerRightCorner.Y = btnRect.UpperLeftCorner.Y + buttonHeight;
btnRect.UpperLeftCorner.X = borderWidth;
if ( contentWidth > buttonBoxWidth )
btnRect.UpperLeftCorner.X += (contentWidth - buttonBoxWidth) / 2; // center buttons
btnRect.LowerRightCorner.X = btnRect.UpperLeftCorner.X + buttonWidth;
IGUIElement* focusMe = 0;
setButton(OkButton, (Flags & EMBF_OK) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_OK), focusMe);
if ( Flags & EMBF_OK )
btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);
setButton(CancelButton, (Flags & EMBF_CANCEL) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_CANCEL), focusMe);
if ( Flags & EMBF_CANCEL )
btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);
setButton(YesButton, (Flags & EMBF_YES) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_YES), focusMe);
if ( Flags & EMBF_YES )
btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);
setButton(NoButton, (Flags & EMBF_NO) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_NO), focusMe);
if (Environment->hasFocus(this) && focusMe)
Environment->setFocus(focusMe);
}
//! called if an event happened.
bool CGUIMessageBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
SEvent outevent;
outevent.EventType = EET_GUI_EVENT;
outevent.GUIEvent.Caller = this;
outevent.GUIEvent.Element = 0;
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case IRR_KEY_RETURN:
if (OkButton)
{
OkButton->setPressed(true);
Pressed = true;
}
break;
case IRR_KEY_Y:
if (YesButton)
{
YesButton->setPressed(true);
Pressed = true;
}
break;
case IRR_KEY_N:
if (NoButton)
{
NoButton->setPressed(true);
Pressed = true;
}
break;
case IRR_KEY_ESCAPE:
if (Pressed)
{
// cancel press
if (OkButton) OkButton->setPressed(false);
if (YesButton) YesButton->setPressed(false);
if (NoButton) NoButton->setPressed(false);
Pressed = false;
}
else
if (CancelButton)
{
CancelButton->setPressed(true);
Pressed = true;
}
else
if (CloseButton && CloseButton->isVisible())
{
CloseButton->setPressed(true);
Pressed = true;
}
break;
default: // no other key is handled here
break;
}
}
else
if (Pressed)
{
if (OkButton && event.KeyInput.Key == IRR_KEY_RETURN)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if ((CancelButton || CloseButton) && event.KeyInput.Key == IRR_KEY_ESCAPE)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (YesButton && event.KeyInput.Key == IRR_KEY_Y)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (NoButton && event.KeyInput.Key == IRR_KEY_N)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO;
Parent->OnEvent(outevent);
remove();
return true;
}
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
if (event.GUIEvent.Caller == OkButton)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (event.GUIEvent.Caller == CancelButton ||
event.GUIEvent.Caller == CloseButton)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (event.GUIEvent.Caller == YesButton)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES;
Parent->OnEvent(outevent);
remove();
return true;
}
else
if (event.GUIEvent.Caller == NoButton)
{
setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC
Environment->setFocus(0);
outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO;
Parent->OnEvent(outevent);
remove();
return true;
}
}
break;
default:
break;
}
}
return CGUIWindow::OnEvent(event);
}
//! Writes attributes of the element.
void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
CGUIWindow::serializeAttributes(out,options);
out->addBool ("OkayButton", (Flags & EMBF_OK) != 0 );
out->addBool ("CancelButton", (Flags & EMBF_CANCEL) != 0 );
out->addBool ("YesButton", (Flags & EMBF_YES) != 0 );
out->addBool ("NoButton", (Flags & EMBF_NO) != 0 );
out->addTexture ("Texture", IconTexture);
out->addString ("MessageText", MessageText.c_str());
}
//! Reads attributes of the element
void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
Flags = 0;
Flags = in->getAttributeAsBool("OkayButton") ? EMBF_OK : 0;
Flags |= in->getAttributeAsBool("CancelButton")? EMBF_CANCEL : 0;
Flags |= in->getAttributeAsBool("YesButton") ? EMBF_YES : 0;
Flags |= in->getAttributeAsBool("NoButton") ? EMBF_NO : 0;
if ( IconTexture )
{
IconTexture->drop();
IconTexture = NULL;
}
IconTexture = in->getAttributeAsTexture("Texture");
if ( IconTexture )
IconTexture->grab();
MessageText = in->getAttributeAsStringW("MessageText").c_str();
CGUIWindow::deserializeAttributes(in,options);
refreshControls();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,64 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_MESSAGE_BOX_H_INCLUDED__
#define __C_GUI_MESSAGE_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "CGUIWindow.h"
#include "IGUIStaticText.h"
#include "IGUIImage.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class CGUIMessageBox : public CGUIWindow
{
public:
//! constructor
CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption,
const wchar_t* text, s32 flag,
IGUIElement* parent, s32 id, core::rect<s32> rectangle, video::ITexture* image=0);
//! destructor
virtual ~CGUIMessageBox();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
void refreshControls();
void setButton(IGUIButton*& button, bool isAvailable, const core::rect<s32> & btnRect, const wchar_t * text, IGUIElement*& focusMe);
IGUIButton* OkButton;
IGUIButton* CancelButton;
IGUIButton* YesButton;
IGUIButton* NoButton;
IGUIStaticText* StaticText;
IGUIImage * Icon;
video::ITexture * IconTexture;
s32 Flags;
core::stringw MessageText;
bool Pressed;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
@@ -0,0 +1,235 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIModalScreen.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "os.h"
#include "IVideoDriver.h"
#include "IGUISkin.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIModalScreen::CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* parent, s32 id)
: IGUIElement(EGUIET_MODAL_SCREEN, environment, parent, id, core::recti(0, 0, parent->getAbsolutePosition().getWidth(), parent->getAbsolutePosition().getHeight()) ),
MouseDownTime(0)
{
#ifdef _DEBUG
setDebugName("CGUIModalScreen");
#endif
setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
// this element is a tab group
setTabGroup(true);
}
bool CGUIModalScreen::canTakeFocus(IGUIElement* target) const
{
return (target && ((const IGUIElement*)target == this // this element can take it
|| isMyChild(target) // own children also
|| (target->getType() == EGUIET_MODAL_SCREEN ) // other modals also fine (is now on top or explicitely requested)
|| (target->getParent() && target->getParent()->getType() == EGUIET_MODAL_SCREEN ))) // children of other modals will do
;
}
bool CGUIModalScreen::isVisible() const
{
// any parent invisible?
IGUIElement * parentElement = getParent();
while ( parentElement )
{
if ( !parentElement->isVisible() )
return false;
parentElement = parentElement->getParent();
}
// if we have no children then the modal is probably abused as a way to block input
if ( Children.empty() )
{
return IGUIElement::isVisible();
}
// any child visible?
bool visible = false;
core::list<IGUIElement*>::ConstIterator it = Children.begin();
for (; it != Children.end(); ++it)
{
if ( (*it)->isVisible() )
{
visible = true;
break;
}
}
return visible;
}
bool CGUIModalScreen::isPointInside(const core::position2d<s32>& point) const
{
return true;
}
//! called if an event happened.
bool CGUIModalScreen::OnEvent(const SEvent& event)
{
if (!isEnabled() || !isVisible() )
return IGUIElement::OnEvent(event);
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUSED:
if ( event.GUIEvent.Caller == this && isMyChild(event.GUIEvent.Element) )
{
Environment->removeFocus(0); // can't setFocus otherwise at it still has focus here
Environment->setFocus(event.GUIEvent.Element);
MouseDownTime = os::Timer::getTime();
return true;
}
if ( !canTakeFocus(event.GUIEvent.Caller))
{
if ( !Children.empty() )
Environment->setFocus(*(Children.begin()));
else
Environment->setFocus(this);
}
IGUIElement::OnEvent(event);
return false;
case EGET_ELEMENT_FOCUS_LOST:
if ( !canTakeFocus(event.GUIEvent.Element))
{
if ( isMyChild(event.GUIEvent.Caller) )
{
if ( !Children.empty() )
Environment->setFocus(*(Children.begin()));
else
Environment->setFocus(this);
}
else
{
MouseDownTime = os::Timer::getTime();
}
return true;
}
else
{
return IGUIElement::OnEvent(event);
}
case EGET_ELEMENT_CLOSED:
// do not interfere with children being removed
return IGUIElement::OnEvent(event);
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
MouseDownTime = os::Timer::getTime();
}
default:
break;
}
IGUIElement::OnEvent(event); // anyone knows why events are passed on here? Causes p.e. problems when this is child of a CGUIWindow.
return true; // absorb everything else
}
//! draws the element and its children
void CGUIModalScreen::draw()
{
IGUISkin *skin = Environment->getSkin();
if (!skin)
return;
u32 now = os::Timer::getTime();
if (now - MouseDownTime < 300 && (now / 70)%2)
{
core::list<IGUIElement*>::Iterator it = Children.begin();
core::rect<s32> r;
video::SColor c = Environment->getSkin()->getColor(gui::EGDC_3D_HIGH_LIGHT);
for (; it != Children.end(); ++it)
{
if ((*it)->isVisible())
{
r = (*it)->getAbsolutePosition();
r.LowerRightCorner.X += 1;
r.LowerRightCorner.Y += 1;
r.UpperLeftCorner.X -= 1;
r.UpperLeftCorner.Y -= 1;
skin->draw2DRectangle(this, c, r, &AbsoluteClippingRect);
}
}
}
IGUIElement::draw();
}
//! Removes a child.
void CGUIModalScreen::removeChild(IGUIElement* child)
{
IGUIElement::removeChild(child);
if (Children.empty())
{
remove();
}
}
//! adds a child
void CGUIModalScreen::addChild(IGUIElement* child)
{
IGUIElement::addChild(child);
Environment->setFocus(child);
}
void CGUIModalScreen::updateAbsolutePosition()
{
core::rect<s32> parentRect(0,0,0,0);
if (Parent)
{
parentRect = Parent->getAbsolutePosition();
RelativeRect.UpperLeftCorner.X = 0;
RelativeRect.UpperLeftCorner.Y = 0;
RelativeRect.LowerRightCorner.X = parentRect.getWidth();
RelativeRect.LowerRightCorner.Y = parentRect.getHeight();
}
IGUIElement::updateAbsolutePosition();
}
//! Writes attributes of the element.
void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIElement::serializeAttributes(out,options);
}
//! Reads attributes of the element
void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIElement::deserializeAttributes(in, options);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,70 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_MODAL_SCREEN_H_INCLUDED__
#define __C_GUI_MODAL_SCREEN_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIElement.h"
namespace irr
{
namespace gui
{
class CGUIModalScreen : public IGUIElement
{
public:
//! constructor
CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* parent, s32 id);
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! Removes a child.
virtual void removeChild(IGUIElement* child);
//! Adds a child
virtual void addChild(IGUIElement* child);
//! draws the element and its children
virtual void draw();
//! Updates the absolute position.
virtual void updateAbsolutePosition();
//! Modalscreen is not a typical element, but rather acts like a state for it's children.
//! isVisible is overriden to give this a useful behavior, so that a modal will no longer
//! be active when its parent is invisible or all its children are invisible.
virtual bool isVisible() const;
//! Modals are infinite so every point is inside
virtual bool isPointInside(const core::position2d<s32>& point) const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
protected:
virtual bool canTakeFocus(IGUIElement* target) const;
private:
u32 MouseDownTime;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
@@ -0,0 +1,572 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIScrollBar.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "CGUIButton.h"
#include "IGUIFont.h"
#include "IGUIFontBitmap.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIScrollBar::CGUIScrollBar(bool horizontal, IGUIEnvironment* environment,
IGUIElement* parent, s32 id,
core::rect<s32> rectangle, bool noclip)
: IGUIScrollBar(environment, parent, id, rectangle), UpButton(0),
DownButton(0), Dragging(false), Horizontal(horizontal),
DraggedBySlider(false), TrayClick(false), Pos(0), DrawPos(0),
DrawHeight(0), Min(0), Max(100), SmallStep(10), LargeStep(50), DesiredPos(0),
LastChange(0)
{
#ifdef _DEBUG
setDebugName("CGUIScrollBar");
#endif
refreshControls();
setNotClipped(noclip);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
setPos(0);
}
//! destructor
CGUIScrollBar::~CGUIScrollBar()
{
if (UpButton)
UpButton->drop();
if (DownButton)
DownButton->drop();
}
//! called if an event happened.
bool CGUIScrollBar::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
const s32 oldPos = Pos;
bool absorb = true;
switch (event.KeyInput.Key)
{
case IRR_KEY_LEFT:
case IRR_KEY_UP:
setPos(Pos-SmallStep);
break;
case IRR_KEY_RIGHT:
case IRR_KEY_DOWN:
setPos(Pos+SmallStep);
break;
case IRR_KEY_HOME:
setPos(Min);
break;
case IRR_KEY_PRIOR:
setPos(Pos-LargeStep);
break;
case IRR_KEY_END:
setPos(Max);
break;
case IRR_KEY_NEXT:
setPos(Pos+LargeStep);
break;
default:
absorb = false;
}
if (Pos != oldPos)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
}
if (absorb)
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
if (event.GUIEvent.Caller == UpButton)
setPos(Pos-SmallStep);
else
if (event.GUIEvent.Caller == DownButton)
setPos(Pos+SmallStep);
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
return true;
}
else
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == this)
Dragging = false;
}
break;
case EET_MOUSE_INPUT_EVENT:
{
const core::position2di p(event.MouseInput.X, event.MouseInput.Y);
bool isInside = isPointInside ( p );
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
if (Environment->hasFocus(this))
{
// thanks to a bug report by REAPER
// thanks to tommi by tommi for another bugfix
// everybody needs a little thanking. hallo niko!;-)
setPos( getPos() +
( event.MouseInput.Wheel * SmallStep * (Horizontal ? 1 : -1 ) )
);
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
return true;
}
break;
case EMIE_LMOUSE_PRESSED_DOWN:
{
if (isInside)
{
Dragging = true;
DraggedBySlider = SliderRect.isPointInside(p);
TrayClick = !DraggedBySlider;
DesiredPos = getPosFromMousePos(p);
Environment->setFocus ( this );
return true;
}
break;
}
case EMIE_LMOUSE_LEFT_UP:
case EMIE_MOUSE_MOVED:
{
if ( !event.MouseInput.isLeftPressed () )
Dragging = false;
if ( !Dragging )
{
if ( event.MouseInput.Event == EMIE_MOUSE_MOVED )
break;
return isInside;
}
if ( event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP )
Dragging = false;
const s32 newPos = getPosFromMousePos(p);
const s32 oldPos = Pos;
if (!DraggedBySlider)
{
if ( isInside )
{
DraggedBySlider = SliderRect.isPointInside(p);
TrayClick = !DraggedBySlider;
}
if (DraggedBySlider)
{
setPos(newPos);
}
else
{
TrayClick = false;
if (event.MouseInput.Event == EMIE_MOUSE_MOVED)
return isInside;
}
}
if (DraggedBySlider)
{
setPos(newPos);
}
else
{
DesiredPos = newPos;
}
if (Pos != oldPos && Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
}
return isInside;
} break;
default:
break;
}
} break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUIScrollBar::OnPostRender(u32 timeMs)
{
if (Dragging && !DraggedBySlider && TrayClick && timeMs > LastChange + 200)
{
LastChange = timeMs;
const s32 oldPos = Pos;
if (DesiredPos >= Pos + LargeStep)
setPos(Pos + LargeStep);
else
if (DesiredPos <= Pos - LargeStep)
setPos(Pos - LargeStep);
else
if (DesiredPos >= Pos - LargeStep && DesiredPos <= Pos + LargeStep)
setPos(DesiredPos);
if (Pos != oldPos && Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
Parent->OnEvent(newEvent);
}
}
}
//! draws the element and its children
void CGUIScrollBar::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::SColor iconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
if ( iconColor != CurrentIconColor )
{
refreshControls();
}
SliderRect = AbsoluteRect;
// draws the background
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), SliderRect, &AbsoluteClippingRect);
if ( core::isnotzero ( range() ) )
{
// recalculate slider rectangle
if (Horizontal)
{
SliderRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + DrawPos + RelativeRect.getHeight() - DrawHeight/2;
SliderRect.LowerRightCorner.X = SliderRect.UpperLeftCorner.X + DrawHeight;
}
else
{
SliderRect.UpperLeftCorner.Y = AbsoluteRect.UpperLeftCorner.Y + DrawPos + RelativeRect.getWidth() - DrawHeight/2;
SliderRect.LowerRightCorner.Y = SliderRect.UpperLeftCorner.Y + DrawHeight;
}
skin->draw3DButtonPaneStandard(this, SliderRect, &AbsoluteClippingRect);
}
// draw buttons
IGUIElement::draw();
}
void CGUIScrollBar::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
// todo: properly resize
refreshControls();
setPos ( Pos );
}
//!
s32 CGUIScrollBar::getPosFromMousePos(const core::position2di &pos) const
{
f32 w, p;
if (Horizontal)
{
w = RelativeRect.getWidth() - f32(RelativeRect.getHeight())*3.0f;
p = pos.X - AbsoluteRect.UpperLeftCorner.X - RelativeRect.getHeight()*1.5f;
}
else
{
w = RelativeRect.getHeight() - f32(RelativeRect.getWidth())*3.0f;
p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - RelativeRect.getWidth()*1.5f;
}
return (s32) ( p/w * range() ) + Min;
}
//! sets the position of the scrollbar
void CGUIScrollBar::setPos(s32 pos)
{
Pos = core::s32_clamp ( pos, Min, Max );
if ( !core::isnotzero ( range() ) )
return;
if (Horizontal)
{
f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / range();
DrawPos = (s32)( ( ( Pos - Min ) * f) + ((f32)RelativeRect.getHeight() * 0.5f));
DrawHeight = RelativeRect.getHeight();
}
else
{
f32 f = (RelativeRect.getHeight() - ((f32)RelativeRect.getWidth()*3.0f)) / range();
DrawPos = (s32)( ( ( Pos - Min ) * f) + ((f32)RelativeRect.getWidth() * 0.5f));
DrawHeight = RelativeRect.getWidth();
}
}
//! gets the small step value
s32 CGUIScrollBar::getSmallStep() const
{
return SmallStep;
}
//! sets the small step value
void CGUIScrollBar::setSmallStep(s32 step)
{
if (step > 0)
SmallStep = step;
else
SmallStep = 10;
}
//! gets the small step value
s32 CGUIScrollBar::getLargeStep() const
{
return LargeStep;
}
//! sets the small step value
void CGUIScrollBar::setLargeStep(s32 step)
{
if (step > 0)
LargeStep = step;
else
LargeStep = 50;
}
//! gets the maximum value of the scrollbar.
s32 CGUIScrollBar::getMax() const
{
return Max;
}
//! sets the maximum value of the scrollbar.
void CGUIScrollBar::setMax(s32 max)
{
Max = max;
if ( Min > Max )
Min = Max;
bool enable = core::isnotzero ( range() );
UpButton->setEnabled(enable);
DownButton->setEnabled(enable);
setPos(Pos);
}
//! gets the minimum value of the scrollbar.
s32 CGUIScrollBar::getMin() const
{
return Min;
}
//! sets the minimum value of the scrollbar.
void CGUIScrollBar::setMin(s32 min)
{
Min = min;
if ( Max < Min )
Max = Min;
bool enable = core::isnotzero ( range() );
UpButton->setEnabled(enable);
DownButton->setEnabled(enable);
setPos(Pos);
}
//! gets the current position of the scrollbar
s32 CGUIScrollBar::getPos() const
{
return Pos;
}
//! refreshes the position and text on child buttons
void CGUIScrollBar::refreshControls()
{
CurrentIconColor = video::SColor(255,255,255,255);
IGUISkin* skin = Environment->getSkin();
IGUISpriteBank* sprites = 0;
if (skin)
{
sprites = skin->getSpriteBank();
CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
}
if (Horizontal)
{
s32 h = RelativeRect.getHeight();
if (!UpButton)
{
UpButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,0, h, h), NoClip);
UpButton->setSubElement(true);
UpButton->setTabStop(false);
}
if (sprites)
{
UpButton->setSpriteBank(sprites);
UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_LEFT), CurrentIconColor);
UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT), CurrentIconColor);
}
UpButton->setRelativePosition(core::rect<s32>(0,0, h, h));
UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
if (!DownButton)
{
DownButton = new CGUIButton(Environment, this, -1, core::rect<s32>(RelativeRect.getWidth()-h, 0, RelativeRect.getWidth(), h), NoClip);
DownButton->setSubElement(true);
DownButton->setTabStop(false);
}
if (sprites)
{
DownButton->setSpriteBank(sprites);
DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_RIGHT), CurrentIconColor);
DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT), CurrentIconColor);
}
DownButton->setRelativePosition(core::rect<s32>(RelativeRect.getWidth()-h, 0, RelativeRect.getWidth(), h));
DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
}
else
{
s32 w = RelativeRect.getWidth();
if (!UpButton)
{
UpButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,0, w, w), NoClip);
UpButton->setSubElement(true);
UpButton->setTabStop(false);
}
if (sprites)
{
UpButton->setSpriteBank(sprites);
UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_UP), CurrentIconColor);
UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_UP), CurrentIconColor);
}
UpButton->setRelativePosition(core::rect<s32>(0,0, w, w));
UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
if (!DownButton)
{
DownButton = new CGUIButton(Environment, this, -1, core::rect<s32>(0,RelativeRect.getHeight()-w, w, RelativeRect.getHeight()), NoClip);
DownButton->setSubElement(true);
DownButton->setTabStop(false);
}
if (sprites)
{
DownButton->setSpriteBank(sprites);
DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), CurrentIconColor);
DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), CurrentIconColor);
}
DownButton->setRelativePosition(core::rect<s32>(0,RelativeRect.getHeight()-w, w, RelativeRect.getHeight()));
DownButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
}
}
//! Writes attributes of the element.
void CGUIScrollBar::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIScrollBar::serializeAttributes(out,options);
out->addBool("Horizontal", Horizontal);
out->addInt ("Value", Pos);
out->addInt ("Min", Min);
out->addInt ("Max", Max);
out->addInt ("SmallStep", SmallStep);
out->addInt ("LargeStep", LargeStep);
// CurrentIconColor - not serialized as continuiously updated
}
//! Reads attributes of the element
void CGUIScrollBar::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIScrollBar::deserializeAttributes(in,options);
Horizontal = in->getAttributeAsBool("Horizontal");
setMin(in->getAttributeAsInt("Min"));
setMax(in->getAttributeAsInt("Max"));
setPos(in->getAttributeAsInt("Value"));
setSmallStep(in->getAttributeAsInt("SmallStep"));
setLargeStep(in->getAttributeAsInt("LargeStep"));
// CurrentIconColor - not serialized as continuiously updated
refreshControls();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,113 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_SCROLL_BAR_H_INCLUDED__
#define __C_GUI_SCROLL_BAR_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIScrollBar.h"
#include "IGUIButton.h"
namespace irr
{
namespace gui
{
class CGUIScrollBar : public IGUIScrollBar
{
public:
//! constructor
CGUIScrollBar(bool horizontal, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, core::rect<s32> rectangle,
bool noclip=false);
//! destructor
virtual ~CGUIScrollBar();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
virtual void OnPostRender(u32 timeMs);
//! gets the maximum value of the scrollbar.
virtual s32 getMax() const;
//! sets the maximum value of the scrollbar.
virtual void setMax(s32 max);
//! gets the minimum value of the scrollbar.
virtual s32 getMin() const;
//! sets the minimum value of the scrollbar.
virtual void setMin(s32 min);
//! gets the small step value
virtual s32 getSmallStep() const;
//! sets the small step value
virtual void setSmallStep(s32 step);
//! gets the large step value
virtual s32 getLargeStep() const;
//! sets the large step value
virtual void setLargeStep(s32 step);
//! gets the current position of the scrollbar
virtual s32 getPos() const;
//! sets the position of the scrollbar
virtual void setPos(s32 pos);
//! updates the rectangle
virtual void updateAbsolutePosition();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
void refreshControls();
s32 getPosFromMousePos(const core::position2di &p) const;
IGUIButton* UpButton;
IGUIButton* DownButton;
core::rect<s32> SliderRect;
bool Dragging;
bool Horizontal;
bool DraggedBySlider;
bool TrayClick;
s32 Pos;
s32 DrawPos;
s32 DrawHeight;
s32 Min;
s32 Max;
s32 SmallStep;
s32 LargeStep;
s32 DesiredPos;
u32 LastChange;
video::SColor CurrentIconColor;
f32 range () const { return (f32) ( Max - Min ); }
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
File diff suppressed because it is too large Load Diff
+253
View File
@@ -0,0 +1,253 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_SKIN_H_INCLUDED__
#define __C_GUI_SKIN_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "irrString.h"
namespace irr
{
namespace video
{
class IVideoDriver;
}
namespace gui
{
class CGUISkin : public IGUISkin
{
public:
CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver);
//! destructor
virtual ~CGUISkin();
//! returns default color
virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const;
//! sets a default color
virtual void setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor);
//! returns size for the given size type
virtual s32 getSize(EGUI_DEFAULT_SIZE size) const;
//! sets a default size
virtual void setSize(EGUI_DEFAULT_SIZE which, s32 size);
//! returns the default font
virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) const;
//! sets a default font
virtual void setFont(IGUIFont* font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT);
//! sets the sprite bank used for drawing icons
virtual void setSpriteBank(IGUISpriteBank* bank);
//! gets the sprite bank used for drawing icons
virtual IGUISpriteBank* getSpriteBank() const;
//! Returns a default icon
/** Returns the sprite index within the sprite bank */
virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const;
//! Sets a default icon
/** Sets the sprite index used for drawing icons like arrows,
close buttons and ticks in checkboxes
\param icon: Enum specifying which icon to change
\param index: The sprite index used to draw this icon */
virtual void setIcon(EGUI_DEFAULT_ICON icon, u32 index);
//! Returns a default text.
/** For example for Message box button captions:
"OK", "Cancel", "Yes", "No" and so on. */
virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const;
//! Sets a default text.
/** For example for Message box button captions:
"OK", "Cancel", "Yes", "No" and so on. */
virtual void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText);
//! draws a standard 3d button pane
/** Used for drawing for example buttons in normal state.
It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and
EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.
\param rect: Defining area where to draw.
\param clip: Clip area.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly. */
virtual void draw3DButtonPaneStandard(IGUIElement* element,
const core::rect<s32>& rect,
const core::rect<s32>* clip=0);
//! draws a pressed 3d button pane
/** Used for drawing for example buttons in pressed state.
It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and
EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.
\param rect: Defining area where to draw.
\param clip: Clip area.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly. */
virtual void draw3DButtonPanePressed(IGUIElement* element,
const core::rect<s32>& rect,
const core::rect<s32>* clip=0);
//! draws a sunken 3d pane
/** Used for drawing the background of edit, combo or check boxes.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param bgcolor: Background color.
\param flat: Specifies if the sunken pane should be flat or displayed as sunken
deep into the ground.
\param rect: Defining area where to draw.
\param clip: Clip area. */
virtual void draw3DSunkenPane(IGUIElement* element,
video::SColor bgcolor, bool flat,
bool fillBackGround,
const core::rect<s32>& rect,
const core::rect<s32>* clip=0);
//! draws a window background
/** Used for drawing the background of dialogs and windows.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param titleBarColor: Title color.
\param drawTitleBar: True to enable title drawing.
\param rect: Defining area where to draw.
\param clip: Clip area.
\param checkClientArea: When set to non-null the function will not draw anything,
but will instead return the clientArea which can be used for drawing by the calling window.
That is the area without borders and without titlebar.
\return Returns rect where it would be good to draw title bar text. This will
work even when checkClientArea is set to a non-null value.*/
virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element,
bool drawTitleBar, video::SColor titleBarColor,
const core::rect<s32>& rect,
const core::rect<s32>* clip,
core::rect<s32>* checkClientArea);
//! draws a standard 3d menu pane
/** Used for drawing for menus and context menus.
It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and
EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param rect: Defining area where to draw.
\param clip: Clip area. */
virtual void draw3DMenuPane(IGUIElement* element,
const core::rect<s32>& rect,
const core::rect<s32>* clip=0);
//! draws a standard 3d tool bar
/** Used for drawing for toolbars and menus.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param rect: Defining area where to draw.
\param clip: Clip area. */
virtual void draw3DToolBar(IGUIElement* element,
const core::rect<s32>& rect,
const core::rect<s32>* clip=0);
//! draws a tab button
/** Used for drawing for tab buttons on top of tabs.
\param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param active: Specifies if the tab is currently active.
\param rect: Defining area where to draw.
\param clip: Clip area. */
virtual void draw3DTabButton(IGUIElement* element, bool active,
const core::rect<s32>& rect, const core::rect<s32>* clip=0, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT);
//! draws a tab control body
/** \param element: Pointer to the element which wishes to draw this. This parameter
is usually not used by ISkin, but can be used for example by more complex
implementations to find out how to draw the part exactly.
\param border: Specifies if the border should be drawn.
\param background: Specifies if the background should be drawn.
\param rect: Defining area where to draw.
\param clip: Clip area. */
virtual void draw3DTabBody(IGUIElement* element, bool border, bool background,
const core::rect<s32>& rect, const core::rect<s32>* clip=0, s32 tabHeight=-1, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT);
//! draws an icon, usually from the skin's sprite bank
/** \param element: Pointer to the element which wishes to draw this icon.
This parameter is usually not used by IGUISkin, but can be used for example
by more complex implementations to find out how to draw the part exactly.
\param icon: Specifies the icon to be drawn.
\param position: The position to draw the icon
\param starttime: The time at the start of the animation
\param currenttime: The present time, used to calculate the frame number
\param loop: Whether the animation should loop or not
\param clip: Clip area. */
virtual void drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,
const core::position2di position,
u32 starttime=0, u32 currenttime=0,
bool loop=false, const core::rect<s32>* clip=0);
//! draws a 2d rectangle.
/** \param element: Pointer to the element which wishes to draw this icon.
This parameter is usually not used by IGUISkin, but can be used for example
by more complex implementations to find out how to draw the part exactly.
\param color: Color of the rectangle to draw. The alpha component specifies how
transparent the rectangle will be.
\param pos: Position of the rectangle.
\param clip: Pointer to rectangle against which the rectangle will be clipped.
If the pointer is null, no clipping will be performed. */
virtual void draw2DRectangle(IGUIElement* element, const video::SColor &color,
const core::rect<s32>& pos, const core::rect<s32>* clip = 0);
//! get the type of this skin
virtual EGUI_SKIN_TYPE getType() const;
//! Writes attributes of the object.
//! Implement this to expose the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml serialization purposes.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the object.
//! Implement this to set the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml deserialization purposes.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
virtual void draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
const video::SColor* const colors, bool useAlphaChannelOfTexture);
private:
video::SColor Colors[EGDC_COUNT];
s32 Sizes[EGDS_COUNT];
u32 Icons[EGDI_COUNT];
IGUIFont* Fonts[EGDF_COUNT];
IGUISpriteBank* SpriteBank;
core::stringw Texts[EGDT_COUNT];
video::IVideoDriver* Driver;
bool UseGradient;
EGUI_SKIN_TYPE Type;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
@@ -0,0 +1,327 @@
// Copyright (C) 2006-2012 Michael Zeilfelder
// This file uses the licence of the Irrlicht Engine.
#include "CGUISpinBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "CGUIEditBox.h"
#include "CGUIButton.h"
#include "IGUIEnvironment.h"
#include "IEventReceiver.h"
#include "fast_atof.h"
#include <wchar.h>
namespace irr
{
namespace gui
{
//! constructor
CGUISpinBox::CGUISpinBox(const wchar_t* text, bool border,IGUIEnvironment* environment,
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle)
: IGUISpinBox(environment, parent, id, rectangle),
EditBox(0), ButtonSpinUp(0), ButtonSpinDown(0), StepSize(1.f),
RangeMin(-FLT_MAX), RangeMax(FLT_MAX), FormatString(L"%f"),
DecimalPlaces(-1)
{
#ifdef _DEBUG
setDebugName("CGUISpinBox");
#endif
CurrentIconColor = video::SColor(255,255,255,255);
s32 ButtonWidth = 16;
ButtonSpinDown = Environment->addButton(
core::rect<s32>(rectangle.getWidth() - ButtonWidth, rectangle.getHeight()/2 +1,
rectangle.getWidth(), rectangle.getHeight()), this);
ButtonSpinDown->grab();
ButtonSpinDown->setSubElement(true);
ButtonSpinDown->setTabStop(false);
ButtonSpinDown->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_CENTER, EGUIA_LOWERRIGHT);
ButtonSpinUp = Environment->addButton(
core::rect<s32>(rectangle.getWidth() - ButtonWidth, 0,
rectangle.getWidth(), rectangle.getHeight()/2), this);
ButtonSpinUp->grab();
ButtonSpinUp->setSubElement(true);
ButtonSpinUp->setTabStop(false);
ButtonSpinUp->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_CENTER);
const core::rect<s32> rectEdit(0, 0, rectangle.getWidth() - ButtonWidth - 1, rectangle.getHeight());
EditBox = Environment->addEditBox(text, rectEdit, border, this, -1);
EditBox->grab();
EditBox->setSubElement(true);
EditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
refreshSprites();
}
//! destructor
CGUISpinBox::~CGUISpinBox()
{
if (ButtonSpinUp)
ButtonSpinUp->drop();
if (ButtonSpinDown)
ButtonSpinDown->drop();
if (EditBox)
EditBox->drop();
}
void CGUISpinBox::refreshSprites()
{
IGUISpriteBank *sb = 0;
if (Environment && Environment->getSkin())
{
sb = Environment->getSkin()->getSpriteBank();
}
if (sb)
{
IGUISkin * skin = Environment->getSkin();
CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
ButtonSpinDown->setSpriteBank(sb);
ButtonSpinDown->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_SMALL_CURSOR_DOWN), CurrentIconColor);
ButtonSpinDown->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_SMALL_CURSOR_DOWN), CurrentIconColor);
ButtonSpinUp->setSpriteBank(sb);
ButtonSpinUp->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_SMALL_CURSOR_UP), CurrentIconColor);
ButtonSpinUp->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_SMALL_CURSOR_UP), CurrentIconColor);
}
else
{
ButtonSpinDown->setText(L"-");
ButtonSpinUp->setText(L"+");
}
}
IGUIEditBox* CGUISpinBox::getEditBox() const
{
return EditBox;
}
void CGUISpinBox::setValue(f32 val)
{
wchar_t str[100];
swprintf(str, 99, FormatString.c_str(), val);
EditBox->setText(str);
verifyValueRange();
}
f32 CGUISpinBox::getValue() const
{
const wchar_t* val = EditBox->getText();
if ( !val )
return 0.f;
core::stringc tmp(val);
return core::fast_atof(tmp.c_str());
}
void CGUISpinBox::setRange(f32 min, f32 max)
{
if (max<min)
core::swap(min, max);
RangeMin = min;
RangeMax = max;
// we have to round the range - otherwise we can get into an infinte setValue/verifyValueRange cycle.
wchar_t str[100];
swprintf(str, 99, FormatString.c_str(), RangeMin);
RangeMin = core::fast_atof(core::stringc(str).c_str());
swprintf(str, 99, FormatString.c_str(), RangeMax);
RangeMax = core::fast_atof(core::stringc(str).c_str());
verifyValueRange();
}
f32 CGUISpinBox::getMin() const
{
return RangeMin;
}
f32 CGUISpinBox::getMax() const
{
return RangeMax;
}
f32 CGUISpinBox::getStepSize() const
{
return StepSize;
}
void CGUISpinBox::setStepSize(f32 step)
{
StepSize = step;
}
//! Sets the number of decimal places to display.
void CGUISpinBox::setDecimalPlaces(s32 places)
{
DecimalPlaces = places;
if (places == -1)
FormatString = "%f";
else
{
FormatString = "%.";
FormatString += places;
FormatString += "f";
}
setRange( RangeMin, RangeMax );
setValue(getValue());
}
bool CGUISpinBox::OnEvent(const SEvent& event)
{
if (IsEnabled)
{
bool changeEvent = false;
switch(event.EventType)
{
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
{
f32 val = getValue() + (StepSize * (event.MouseInput.Wheel < 0 ? -1.f : 1.f));
setValue(val);
changeEvent = true;
}
break;
default:
break;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
if (event.GUIEvent.Caller == ButtonSpinUp)
{
f32 val = getValue();
val += StepSize;
setValue(val);
changeEvent = true;
}
else if ( event.GUIEvent.Caller == ButtonSpinDown)
{
f32 val = getValue();
val -= StepSize;
setValue(val);
changeEvent = true;
}
}
if (event.GUIEvent.EventType == EGET_EDITBOX_CHANGED || event.GUIEvent.EventType == EGET_EDITBOX_ENTER)
{
if (event.GUIEvent.Caller == EditBox)
{
verifyValueRange();
changeEvent = true;
}
}
break;
default:
break;
}
if ( changeEvent )
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_SPINBOX_CHANGED;
if ( Parent )
Parent->OnEvent(e);
return true;
}
}
return IGUIElement::OnEvent(event);
}
void CGUISpinBox::draw()
{
if ( !isVisible() )
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::SColor iconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
if ( iconColor != CurrentIconColor )
{
refreshSprites();
}
IGUISpinBox::draw();
}
void CGUISpinBox::verifyValueRange()
{
f32 val = getValue();
if ( val+core::ROUNDING_ERROR_f32 < RangeMin )
val = RangeMin;
else if ( val-core::ROUNDING_ERROR_f32 > RangeMax )
val = RangeMax;
else
return;
setValue(val);
}
//! Sets the new caption of the element
void CGUISpinBox::setText(const core::stringw& text)
{
EditBox->setText(text);
setValue(getValue());
verifyValueRange();
}
//! Returns caption of this element.
const wchar_t* CGUISpinBox::getText() const
{
return EditBox->getText();
}
//! Writes attributes of the element.
void CGUISpinBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IGUIElement::serializeAttributes(out, options);
out->addFloat("Min", getMin());
out->addFloat("Max", getMax());
out->addFloat("Step", getStepSize());
out->addInt("DecimalPlaces", DecimalPlaces);
}
//! Reads attributes of the element
void CGUISpinBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IGUIElement::deserializeAttributes(in, options);
setRange(in->getAttributeAsFloat("Min"), in->getAttributeAsFloat("Max"));
setStepSize(in->getAttributeAsFloat("Step"));
setDecimalPlaces(in->getAttributeAsInt("DecimalPlaces"));
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
+108
View File
@@ -0,0 +1,108 @@
// Copyright (C) 2006-2012 Michael Zeilfelder
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_SPIN_BOX_H_INCLUDED__
#define __C_GUI_SPIN_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISpinBox.h"
namespace irr
{
namespace gui
{
class IGUIEditBox;
class IGUIButton;
class CGUISpinBox : public IGUISpinBox
{
public:
//! constructor
CGUISpinBox(const wchar_t* text, bool border, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle);
//! destructor
virtual ~CGUISpinBox();
//! Access the edit box used in the spin control
/** \param enable: If set to true, the override color, which can be set
with IGUIEditBox::setOverrideColor is used, otherwise the
EGDC_BUTTON_TEXT color of the skin. */
virtual IGUIEditBox* getEditBox() const;
//! set the current value of the spinbox
/** \param val: value to be set in the spinbox */
virtual void setValue(f32 val);
//! Get the current value of the spinbox
virtual f32 getValue() const;
//! set the range of values which can be used in the spinbox
/** \param min: minimum value
\param max: maximum value */
virtual void setRange(f32 min, f32 max);
//! get the minimum value which can be used in the spinbox
virtual f32 getMin() const;
//! get the maximum value which can be used in the spinbox
virtual f32 getMax() const;
//! step size by which values are changed when pressing the spin buttons
/** \param step: stepsize used for value changes when pressing spin buttons */
virtual void setStepSize(f32 step=1.f);
//! returns the step size
virtual f32 getStepSize() const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! Draws the element and its children.
virtual void draw();
//! Sets the new caption of the element
virtual void setText(const core::stringw& text);
//! Returns caption of this element.
virtual const wchar_t* getText() const;
//! Sets the number of decimal places to display.
//! Note that this also rounds the range to the same number of decimal places.
/** \param places: The number of decimal places to display, use -1 to reset */
virtual void setDecimalPlaces(s32 places);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
protected:
virtual void verifyValueRange();
void refreshSprites();
IGUIEditBox * EditBox;
IGUIButton * ButtonSpinUp;
IGUIButton * ButtonSpinDown;
video::SColor CurrentIconColor;
f32 StepSize;
f32 RangeMin;
f32 RangeMax;
core::stringw FormatString;
s32 DecimalPlaces;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_SPIN_BOX_H_INCLUDED__
@@ -0,0 +1,250 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUISpriteBank.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "ITexture.h"
namespace irr
{
namespace gui
{
CGUISpriteBank::CGUISpriteBank(IGUIEnvironment* env) :
Environment(env), Driver(0)
{
#ifdef _DEBUG
setDebugName("CGUISpriteBank");
#endif
if (Environment)
{
Driver = Environment->getVideoDriver();
if (Driver)
Driver->grab();
}
}
CGUISpriteBank::~CGUISpriteBank()
{
// drop textures
for (u32 i=0; i<Textures.size(); ++i)
if (Textures[i])
Textures[i]->drop();
// drop video driver
if (Driver)
Driver->drop();
}
core::array< core::rect<s32> >& CGUISpriteBank::getPositions()
{
return Rectangles;
}
core::array< SGUISprite >& CGUISpriteBank::getSprites()
{
return Sprites;
}
u32 CGUISpriteBank::getTextureCount() const
{
return Textures.size();
}
video::ITexture* CGUISpriteBank::getTexture(u32 index) const
{
if (index < Textures.size())
return Textures[index];
else
return 0;
}
void CGUISpriteBank::addTexture(video::ITexture* texture)
{
if (texture)
texture->grab();
Textures.push_back(texture);
}
void CGUISpriteBank::setTexture(u32 index, video::ITexture* texture)
{
while (index >= Textures.size())
Textures.push_back(0);
if (texture)
texture->grab();
if (Textures[index])
Textures[index]->drop();
Textures[index] = texture;
}
//! clear everything
void CGUISpriteBank::clear()
{
// drop textures
for (u32 i=0; i<Textures.size(); ++i)
if (Textures[i])
Textures[i]->drop();
Textures.clear();
Sprites.clear();
Rectangles.clear();
}
//! Add the texture and use it for a single non-animated sprite.
s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture)
{
if ( !texture )
return -1;
addTexture(texture);
u32 textureIndex = getTextureCount() - 1;
u32 rectangleIndex = Rectangles.size();
Rectangles.push_back( core::rect<s32>(0,0, texture->getOriginalSize().Width, texture->getOriginalSize().Height) );
SGUISprite sprite;
sprite.frameTime = 0;
SGUISpriteFrame frame;
frame.textureNumber = textureIndex;
frame.rectNumber = rectangleIndex;
sprite.Frames.push_back( frame );
Sprites.push_back( sprite );
return Sprites.size() - 1;
}
//! draws a sprite in 2d with scale and color
void CGUISpriteBank::draw2DSprite(u32 index, const core::position2di& pos,
const core::rect<s32>* clip, const video::SColor& color,
u32 starttime, u32 currenttime, bool loop, bool center)
{
if (index >= Sprites.size() || Sprites[index].Frames.empty() )
return;
// work out frame number
u32 frame = 0;
if (Sprites[index].frameTime)
{
u32 f = ((currenttime - starttime) / Sprites[index].frameTime);
if (loop)
frame = f % Sprites[index].Frames.size();
else
frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size()-1 : f;
}
const video::ITexture* tex = Textures[Sprites[index].Frames[frame].textureNumber];
if (!tex)
return;
const u32 rn = Sprites[index].Frames[frame].rectNumber;
if (rn >= Rectangles.size())
return;
const core::rect<s32>& r = Rectangles[rn];
if (center)
{
core::position2di p = pos;
p -= r.getSize() / 2;
Driver->draw2DImage(tex, p, r, clip, color, true);
}
else
{
Driver->draw2DImage(tex, pos, r, clip, color, true);
}
}
void CGUISpriteBank::draw2DSpriteBatch( const core::array<u32>& indices,
const core::array<core::position2di>& pos,
const core::rect<s32>* clip,
const video::SColor& color,
u32 starttime, u32 currenttime,
bool loop, bool center)
{
const irr::u32 drawCount = core::min_<u32>(indices.size(), pos.size());
if( Textures.empty() )
return;
core::array<SDrawBatch> drawBatches(Textures.size());
for(u32 i = 0;i < Textures.size();i++)
{
drawBatches.push_back(SDrawBatch());
drawBatches[i].positions.reallocate(drawCount);
drawBatches[i].sourceRects.reallocate(drawCount);
}
for(u32 i = 0;i < drawCount;i++)
{
const u32 index = indices[i];
if (index >= Sprites.size() || Sprites[index].Frames.empty() )
continue;
// work out frame number
u32 frame = 0;
if (Sprites[index].frameTime)
{
u32 f = ((currenttime - starttime) / Sprites[index].frameTime);
if (loop)
frame = f % Sprites[index].Frames.size();
else
frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size()-1 : f;
}
const u32 texNum = Sprites[index].Frames[frame].textureNumber;
SDrawBatch& currentBatch = drawBatches[texNum];
const u32 rn = Sprites[index].Frames[frame].rectNumber;
if (rn >= Rectangles.size())
return;
const core::rect<s32>& r = Rectangles[rn];
if (center)
{
core::position2di p = pos[i];
p -= r.getSize() / 2;
currentBatch.positions.push_back(p);
currentBatch.sourceRects.push_back(r);
}
else
{
currentBatch.positions.push_back(pos[i]);
currentBatch.sourceRects.push_back(r);
}
}
for(u32 i = 0;i < drawBatches.size();i++)
{
if(!drawBatches[i].positions.empty() && !drawBatches[i].sourceRects.empty())
Driver->draw2DImageBatch(Textures[i], drawBatches[i].positions,
drawBatches[i].sourceRects, clip, color, true);
}
}
} // namespace gui
} // namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,84 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_SPRITE_BANK_H_INCLUDED__
#define __C_GUI_SPRITE_BANK_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISpriteBank.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class ITexture;
}
namespace gui
{
class IGUIEnvironment;
//! Sprite bank interface.
class CGUISpriteBank : public IGUISpriteBank
{
public:
CGUISpriteBank(IGUIEnvironment* env);
virtual ~CGUISpriteBank();
virtual core::array< core::rect<s32> >& getPositions();
virtual core::array< SGUISprite >& getSprites();
virtual u32 getTextureCount() const;
virtual video::ITexture* getTexture(u32 index) const;
virtual void addTexture(video::ITexture* texture);
virtual void setTexture(u32 index, video::ITexture* texture);
//! Add the texture and use it for a single non-animated sprite.
virtual s32 addTextureAsSprite(video::ITexture* texture);
//! clears sprites, rectangles and textures
virtual void clear();
//! Draws a sprite in 2d with position and color
virtual void draw2DSprite(u32 index, const core::position2di& pos, const core::rect<s32>* clip=0,
const video::SColor& color= video::SColor(255,255,255,255),
u32 starttime=0, u32 currenttime=0, bool loop=true, bool center=false);
//! Draws a sprite batch in 2d using an array of positions and a color
virtual void draw2DSpriteBatch(const core::array<u32>& indices, const core::array<core::position2di>& pos,
const core::rect<s32>* clip=0,
const video::SColor& color= video::SColor(255,255,255,255),
u32 starttime=0, u32 currenttime=0,
bool loop=true, bool center=false);
protected:
struct SDrawBatch
{
core::array<core::position2di> positions;
core::array<core::recti> sourceRects;
u32 textureNumber;
};
core::array<SGUISprite> Sprites;
core::array< core::rect<s32> > Rectangles;
core::array<video::ITexture*> Textures;
IGUIEnvironment* Environment;
video::IVideoDriver* Driver;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_SPRITE_BANK_H_INCLUDED__
@@ -0,0 +1,517 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIStaticText.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IGUIFont.h"
#include "IVideoDriver.h"
#include "rect.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIStaticText::CGUIStaticText(const core::stringw& text, bool border,
IGUIEnvironment* environment, IGUIElement* parent,
s32 id, const core::rect<s32>& rectangle,
bool background)
: IGUIStaticText(environment, parent, id, rectangle),
HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
RestrainTextInside(true),
OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
OverrideFont(0), LastBreakFont(0), m_use_glyph_layouts_only(false)
{
#ifdef _DEBUG
setDebugName("CGUIStaticText");
#endif
Text = text;
if (environment && environment->getSkin())
{
BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
}
}
//! destructor
CGUIStaticText::~CGUIStaticText()
{
if (OverrideFont)
OverrideFont->drop();
}
//! draws the element and its children
void CGUIStaticText::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> frameRect(AbsoluteRect);
// draw background
if (Background)
{
if ( !OverrideBGColorEnabled ) // skin-colors can change
BGColor = skin->getColor(gui::EGDC_3D_FACE);
driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
}
// draw the border
if (Border)
{
skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
}
// draw the text layout
if (!m_glyph_layouts.empty())
{
IGUIFont* font = getActiveFont();
if (font)
{
if (font != LastBreakFont)
breakText();
core::rect<s32> r = frameRect;
bool hcenter;
const core::rect<s32>* clip;
getDrawPosition(&r, &hcenter, &clip);
font->draw(m_glyph_layouts, r,
OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
hcenter, false, clip);
}
}
IGUIElement::draw();
}
//! Sets another skin independent font.
void CGUIStaticText::setOverrideFont(IGUIFont* font)
{
if (OverrideFont == font)
return;
if (OverrideFont)
OverrideFont->drop();
OverrideFont = font;
if (OverrideFont)
OverrideFont->grab();
breakText();
}
//! Gets the override font (if any)
IGUIFont * CGUIStaticText::getOverrideFont() const
{
return OverrideFont;
}
//! Get the font which is used right now for drawing
IGUIFont* CGUIStaticText::getActiveFont() const
{
if ( OverrideFont )
return OverrideFont;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getFont();
return 0;
}
//! Sets another color for the text.
void CGUIStaticText::setOverrideColor(video::SColor color)
{
OverrideColor = color;
OverrideColorEnabled = true;
}
//! Sets another color for the text.
void CGUIStaticText::setBackgroundColor(video::SColor color)
{
BGColor = color;
OverrideBGColorEnabled = true;
Background = true;
}
//! Sets whether to draw the background
void CGUIStaticText::setDrawBackground(bool draw)
{
Background = draw;
}
//! Gets the background color
video::SColor CGUIStaticText::getBackgroundColor() const
{
return BGColor;
}
//! Checks if background drawing is enabled
bool CGUIStaticText::isDrawBackgroundEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Background;
}
//! Sets whether to draw the border
void CGUIStaticText::setDrawBorder(bool draw)
{
Border = draw;
}
//! Checks if border drawing is enabled
bool CGUIStaticText::isDrawBorderEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Border;
}
void CGUIStaticText::setTextRestrainedInside(bool restrainTextInside)
{
RestrainTextInside = restrainTextInside;
}
bool CGUIStaticText::isTextRestrainedInside() const
{
return RestrainTextInside;
}
void CGUIStaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
{
HAlign = horizontal;
VAlign = vertical;
}
video::SColor CGUIStaticText::getOverrideColor() const
{
return OverrideColor;
}
//! Sets if the static text should use the overide color or the
//! color in the gui skin.
void CGUIStaticText::enableOverrideColor(bool enable)
{
OverrideColorEnabled = enable;
}
bool CGUIStaticText::isOverrideColorEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return OverrideColorEnabled;
}
//! Enables or disables word wrap for using the static text as
//! multiline text control.
void CGUIStaticText::setWordWrap(bool enable)
{
WordWrap = enable;
breakText();
}
bool CGUIStaticText::isWordWrapEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return WordWrap;
}
//! Breaks the single text line.
void CGUIStaticText::breakText()
{
m_glyph_layouts.clear();
IGUISkin* skin = Environment->getSkin();
IGUIFont* font = getActiveFont();
if (!font)
return;
LastBreakFont = font;
f32 elWidth = (f32)RelativeRect.getWidth();
if (Border)
elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
if (!m_use_glyph_layouts_only)
font->initGlyphLayouts(Text, m_glyph_layouts);
if (WordWrap)
breakGlyphLayouts(m_glyph_layouts, elWidth, font->getInverseShaping(), font->getScale());
}
//! Sets the new caption of this element.
void CGUIStaticText::setText(const core::stringw& text)
{
if (text == Text)
return;
IGUIElement::setText(text);
breakText();
}
void CGUIStaticText::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
// If use glyph layouts only there is no way at the moment to re-break the
// text
if (!m_use_glyph_layouts_only)
breakText();
}
//! Returns the height of the text in pixels when it is drawn.
s32 CGUIStaticText::getTextHeight() const
{
IGUIFont* font = getActiveFont();
if (!font)
return 0;
auto dim = getGlyphLayoutsDimension(m_glyph_layouts,
font->getHeightPerLine(), font->getInverseShaping(), font->getScale());
return dim.Height;
}
s32 CGUIStaticText::getTextWidth() const
{
IGUIFont * font = getActiveFont();
if (!font)
return 0;
auto dim = getGlyphLayoutsDimension(m_glyph_layouts,
font->getHeightPerLine(), font->getInverseShaping(), font->getScale());
return dim.Width;
}
//! Writes attributes of the element.
//! Implement this to expose the attributes of your element for
//! scripting languages, editors, debuggers or xml serialization purposes.
void CGUIStaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIStaticText::serializeAttributes(out,options);
out->addBool ("Border", Border);
out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
out->addBool ("WordWrap", WordWrap);
out->addBool ("Background", Background);
out->addBool ("RestrainTextInside", RestrainTextInside);
out->addColor ("OverrideColor", OverrideColor);
out->addColor ("BGColor", BGColor);
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
// out->addFont ("OverrideFont", OverrideFont);
}
//! Reads attributes of the element
void CGUIStaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIStaticText::deserializeAttributes(in,options);
Border = in->getAttributeAsBool("Border");
enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
setWordWrap(in->getAttributeAsBool("WordWrap"));
Background = in->getAttributeAsBool("Background");
RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
OverrideColor = in->getAttributeAsColor("OverrideColor");
BGColor = in->getAttributeAsColor("BGColor");
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
// OverrideFont = in->getAttributeAsFont("OverrideFont");
}
bool CGUIStaticText::OnEvent(const SEvent& event)
{
if (IsEnabled)
{
switch(event.EventType)
{
case EET_MOUSE_INPUT_EVENT:
{
if (m_callback && m_callback(this, event.MouseInput))
return true;
}
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
s32 CGUIStaticText::getCluster(int x, int y, std::shared_ptr<std::u32string>* out_orig_str, int* out_glyph_idx)
{
core::position2di p;
p.X = x;
p.Y = y;
if (p.X < 0 || p.Y < 0)
return -1;
if (m_glyph_layouts.empty())
return -1;
core::rect<s32> draw_pos = AbsoluteRect;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return -1;
if (Border)
draw_pos.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
IGUIFont* font = getActiveFont();
bool hcenter;
const core::rect<s32>* clip;
getDrawPosition(&draw_pos, &hcenter, &clip);
core::position2d<float> offset;
f32 next_line_height = 0.0f;
std::vector<f32> width_per_line;
if (!gui::getDrawOffset(draw_pos, hcenter, false, m_glyph_layouts,
font->getInverseShaping(), font->getFaceFontMaxHeight(),
font->getFaceGlyphMaxHeight(), font->getScale(), clip, &offset,
&next_line_height, &width_per_line))
return -1;
// Check if the line is RTL
bool rtl = (m_glyph_layouts[0].flags & gui::GLF_RTL_LINE) != 0;
if (!hcenter && rtl)
offset.X += (s32)(draw_pos.getWidth() - width_per_line[0]);
unsigned cur_line = 0;
bool line_changed = false;
int idx = -1;
core::recti test_rect;
test_rect.UpperLeftCorner.X = test_rect.LowerRightCorner.X = (s32)offset.X;
test_rect.UpperLeftCorner.Y = (s32)offset.Y;
test_rect.LowerRightCorner.Y = (s32)offset.Y + (s32)next_line_height;
for (unsigned i = 0; i < m_glyph_layouts.size(); i++)
{
const GlyphLayout& glyph_layout = m_glyph_layouts[i];
// Newline handling (from font with face render)
if ((glyph_layout.flags & GLF_NEWLINE) != 0)
{
test_rect.UpperLeftCorner.Y += (int)next_line_height;
test_rect.LowerRightCorner.Y += (int)next_line_height;
cur_line++;
line_changed = true;
continue;
}
if (line_changed)
{
line_changed = false;
rtl = (glyph_layout.flags & gui::GLF_RTL_LINE) != 0;
offset.X = float(draw_pos.UpperLeftCorner.X);
if (hcenter)
{
offset.X += (s32)(
(draw_pos.getWidth() - width_per_line.at(cur_line)) / 2.f);
}
else if (rtl)
{
offset.X +=
(s32)(draw_pos.getWidth() - width_per_line.at(cur_line));
}
test_rect.UpperLeftCorner.X = test_rect.LowerRightCorner.X =
(s32)offset.X;
}
test_rect.LowerRightCorner.X += s32(
(f32)glyph_layout.x_advance * font->getInverseShaping() *
font->getScale());
if (test_rect.isPointInside(p))
{
idx = i;
break;
}
}
if (idx == -1)
return -1;
std::shared_ptr<std::u32string> s = m_glyph_layouts[idx].orig_string;
if (!s)
return -1;
unsigned cluster = m_glyph_layouts[idx].cluster.front();
if (cluster > s->size())
return -1;
*out_orig_str = s;
if (out_glyph_idx)
*out_glyph_idx = idx;
return cluster;
}
void CGUIStaticText::getDrawPosition(core::rect<s32>* draw_pos, bool* hcenter, const core::rect<s32>** clip)
{
core::rect<s32> r = *draw_pos;
IGUIFont* font = getActiveFont();
auto dim = getGlyphLayoutsDimension(m_glyph_layouts,
font->getHeightPerLine(), font->getInverseShaping(), font->getScale());
s32 totalHeight = dim.Height;
if (VAlign == EGUIA_CENTER)
{
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
}
else if (VAlign == EGUIA_LOWERRIGHT)
{
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
}
if (HAlign == EGUIA_LOWERRIGHT)
{
r.UpperLeftCorner.X = AbsoluteRect.LowerRightCorner.X - dim.Width;
}
*draw_pos = r;
*hcenter = (HAlign == EGUIA_CENTER);
*clip = (RestrainTextInside ? &AbsoluteClippingRect : NULL);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,147 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_STATIC_TEXT_H_INCLUDED__
#define __C_GUI_STATIC_TEXT_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIStaticText.h"
#include "irrArray.h"
#include "GlyphLayout.h"
namespace irr
{
namespace gui
{
class CGUIStaticText : public IGUIStaticText
{
public:
//! constructor
CGUIStaticText(const core::stringw& text, bool border, IGUIEnvironment* environment,
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
bool background = false);
//! destructor
virtual ~CGUIStaticText();
//! draws the element and its children
virtual void draw();
//! Sets another skin independent font.
virtual void setOverrideFont(IGUIFont* font=0);
//! Gets the override font (if any)
virtual IGUIFont* getOverrideFont() const;
//! Get the font which is used right now for drawing
virtual IGUIFont* getActiveFont() const;
//! Sets another color for the text.
virtual void setOverrideColor(video::SColor color);
//! Sets another color for the background.
virtual void setBackgroundColor(video::SColor color);
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
//! Gets the background color
virtual video::SColor getBackgroundColor() const;
//! Checks if background drawing is enabled
virtual bool isDrawBackgroundEnabled() const;
//! Sets whether to draw the border
virtual void setDrawBorder(bool draw);
//! Checks if border drawing is enabled
virtual bool isDrawBorderEnabled() const;
//! Sets alignment mode for text
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
//! Gets the override color
virtual video::SColor getOverrideColor() const;
//! Sets if the static text should use the overide color or the
//! color in the gui skin.
virtual void enableOverrideColor(bool enable);
//! Checks if an override color is enabled
virtual bool isOverrideColorEnabled() const;
//! Set whether the text in this label should be clipped if it goes outside bounds
virtual void setTextRestrainedInside(bool restrainedInside);
//! Checks if the text in this label should be clipped if it goes outside bounds
virtual bool isTextRestrainedInside() const;
//! Enables or disables word wrap for using the static text as
//! multiline text control.
virtual void setWordWrap(bool enable);
//! Checks if word wrap is enabled
virtual bool isWordWrapEnabled() const;
//! Sets the new caption of this element.
virtual void setText(const core::stringw& text);
//! Returns the height of the text in pixels when it is drawn.
virtual s32 getTextHeight() const;
//! Returns the width of the current text, in the current font
virtual s32 getTextWidth() const;
//! Updates the absolute position, splits text if word wrap is enabled
virtual void updateAbsolutePosition();
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
virtual const std::vector<GlyphLayout>& getGlyphLayouts() const { return m_glyph_layouts; }
virtual void setGlyphLayouts(std::vector<GlyphLayout>& gls) { m_glyph_layouts = gls; }
virtual void clearGlyphLayouts() { m_glyph_layouts.clear(); }
virtual void setUseGlyphLayoutsOnly(bool gls_only) { m_use_glyph_layouts_only = gls_only; }
virtual bool useGlyphLayoutsOnly() const { return m_use_glyph_layouts_only; }
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
virtual void setMouseCallback(std::function<bool(IGUIStaticText* text, SEvent::SMouseInput)> cb) { m_callback = cb; }
virtual s32 getCluster(int x, int y, std::shared_ptr<std::u32string>* out_orig_str, int* out_glyph_idx = NULL);
private:
//! Breaks the single text line.
void breakText();
void getDrawPosition(core::rect<s32>* draw_pos, bool* hcenter, const core::rect<s32>** clip);
EGUI_ALIGNMENT HAlign, VAlign;
bool Border;
bool OverrideColorEnabled;
bool OverrideBGColorEnabled;
bool WordWrap;
bool Background;
bool RestrainTextInside;
video::SColor OverrideColor, BGColor;
gui::IGUIFont* OverrideFont;
gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
//! If true, setText / updating this element will not reshape with Text object
bool m_use_glyph_layouts_only;
std::vector<GlyphLayout> m_glyph_layouts;
std::function<bool(IGUIStaticText* text, irr::SEvent::SMouseInput)> m_callback;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,202 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_TAB_CONTROL_H_INCLUDED__
#define __C_GUI_TAB_CONTROL_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUITabControl.h"
#include "irrArray.h"
#include "IGUISkin.h"
namespace irr
{
namespace gui
{
class CGUITabControl;
class IGUIButton;
// A tab, onto which other gui elements could be added.
class CGUITab : public IGUITab
{
public:
//! constructor
CGUITab(s32 number, IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
s32 id);
//! destructor
//virtual ~CGUITab();
//! Returns number of this tab in tabcontrol. Can be accessed
//! later IGUITabControl::getTab() by this number.
virtual s32 getNumber() const;
//! Sets the number
virtual void setNumber(s32 n);
//! draws the element and its children
virtual void draw();
//! sets if the tab should draw its background
virtual void setDrawBackground(bool draw=true);
//! sets the color of the background, if it should be drawn.
virtual void setBackgroundColor(video::SColor c);
//! sets the color of the text
virtual void setTextColor(video::SColor c);
//! returns true if the tab is drawing its background, false if not
virtual bool isDrawingBackground() const;
//! returns the color of the background
virtual video::SColor getBackgroundColor() const;
virtual video::SColor getTextColor() const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
//! only for internal use by CGUITabControl
void refreshSkinColors();
private:
s32 Number;
video::SColor BackColor;
bool OverrideTextColorEnabled;
video::SColor TextColor;
bool DrawBackground;
};
//! A standard tab control
class CGUITabControl : public IGUITabControl
{
public:
//! destructor
CGUITabControl(IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
bool fillbackground=true, bool border=true, s32 id=-1);
//! destructor
virtual ~CGUITabControl();
//! Adds a tab
virtual IGUITab* addTab(const wchar_t* caption, s32 id=-1);
//! Adds a tab that has already been created
virtual void addTab(CGUITab* tab);
//! Insert the tab at the given index
virtual IGUITab* insertTab(s32 idx, const wchar_t* caption, s32 id=-1);
//! Removes a tab from the tabcontrol
virtual void removeTab(s32 idx);
//! Clears the tabcontrol removing all tabs
virtual void clear();
//! Returns amount of tabs in the tabcontrol
virtual s32 getTabCount() const;
//! Returns a tab based on zero based index
virtual IGUITab* getTab(s32 idx) const;
//! Brings a tab to front.
virtual bool setActiveTab(s32 idx);
//! Brings a tab to front.
virtual bool setActiveTab(IGUITab *tab);
//! Returns which tab is currently active
virtual s32 getActiveTab() const;
//! get the the id of the tab at the given absolute coordinates
virtual s32 getTabAt(s32 xpos, s32 ypos) const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Removes a child.
virtual void removeChild(IGUIElement* child);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Set the height of the tabs
virtual void setTabHeight( s32 height );
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
//! Get the height of the tabs
virtual s32 getTabHeight() const;
//! set the maximal width of a tab. Per default width is 0 which means "no width restriction".
virtual void setTabMaxWidth(s32 width );
//! get the maximal width of a tab
virtual s32 getTabMaxWidth() const;
//! Set the alignment of the tabs
//! note: EGUIA_CENTER is not an option
virtual void setTabVerticalAlignment( gui::EGUI_ALIGNMENT alignment );
//! Get the alignment of the tabs
virtual gui::EGUI_ALIGNMENT getTabVerticalAlignment() const;
//! Set the extra width added to tabs on each side of the text
virtual void setTabExtraWidth( s32 extraWidth );
//! Get the extra width added to tabs on each side of the text
virtual s32 getTabExtraWidth() const;
//! Update the position of the element, decides scroll button status
virtual void updateAbsolutePosition();
private:
void scrollLeft();
void scrollRight();
bool needScrollControl( s32 startIndex=0, bool withScrollControl=false );
s32 calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, bool withScrollControl ) const;
core::rect<s32> calcTabPos();
void recalculateScrollButtonPlacement();
void recalculateScrollBar();
void refreshSprites();
core::array<CGUITab*> Tabs; // CGUITab* because we need setNumber (which is certainly not nice)
s32 ActiveTab;
bool Border;
bool FillBackground;
bool ScrollControl;
s32 TabHeight;
gui::EGUI_ALIGNMENT VerticalAlignment;
IGUIButton* UpButton;
IGUIButton* DownButton;
s32 TabMaxWidth;
s32 CurrentScrollTabIndex;
s32 TabExtraWidth;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
File diff suppressed because it is too large Load Diff
+224
View File
@@ -0,0 +1,224 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// 07.10.2005 - Multicolor-Listbox addet by A. Buschhueter (Acki)
// A_Buschhueter@gmx.de
#ifndef __C_GUI_TABLE_BAR_H_INCLUDED__
#define __C_GUI_TABLE_BAR_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUITable.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class IGUIFont;
class IGUIScrollBar;
class CGUITable : public IGUITable
{
public:
//! constructor
CGUITable(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, const core::rect<s32>& rectangle, bool clip=true,
bool drawBack=false, bool moveOverSelect=true);
//! destructor
~CGUITable();
//! Adds a column
//! If columnIndex is outside the current range, do push new colum at the end
virtual void addColumn(const wchar_t* caption, s32 columnIndex=-1);
//! remove a column from the table
virtual void removeColumn(u32 columnIndex);
//! Returns the number of columns in the table control
virtual s32 getColumnCount() const;
//! Makes a column active. This will trigger an ordering process.
/** \param idx: The id of the column to make active.
\return True if successful. */
virtual bool setActiveColumn(s32 columnIndex, bool doOrder=false);
//! Returns which header is currently active
virtual s32 getActiveColumn() const;
//! Returns the ordering used by the currently active column
virtual EGUI_ORDERING_MODE getActiveColumnOrdering() const;
//! set a column width
virtual void setColumnWidth(u32 columnIndex, u32 width);
//! Get the width of a column
virtual u32 getColumnWidth(u32 columnIndex) const;
//! columns can be resized by drag 'n drop
virtual void setResizableColumns(bool resizable);
//! can columns be resized by dran 'n drop?
virtual bool hasResizableColumns() const;
//! This tells the table control which ordering mode should be used when
//! a column header is clicked.
/** \param columnIndex: The index of the column header.
\param state: If true, a EGET_TABLE_HEADER_CHANGED message will be sent and you can order the table data as you whish.*/
//! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING
virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode);
//! Returns which row is currently selected
virtual s32 getSelected() const;
//! set wich row is currently selected
virtual void setSelected( s32 index );
//! Returns amount of rows in the tabcontrol
virtual s32 getRowCount() const;
//! adds a row to the table
/** \param rowIndex: zero based index of rows. The row will be
inserted at this position. If a row already exists
there, it will be placed after it. If the row is larger
than the actual number of rows by more than one, it
won't be created. Note that if you create a row that is
not at the end, there might be performance issues*/
virtual u32 addRow(u32 rowIndex);
//! Remove a row from the table
virtual void removeRow(u32 rowIndex);
//! clear the table rows, but keep the columns intact
virtual void clearRows();
//! Swap two row positions. This is useful for a custom ordering algo.
virtual void swapRows(u32 rowIndexA, u32 rowIndexB);
//! This tells the table to start ordering all the rows. You
//! need to explicitly tell the table to reorder the rows when
//! a new row is added or the cells data is changed. This makes
//! the system more flexible and doesn't make you pay the cost
//! of ordering when adding a lot of rows.
//! \param columnIndex: When set to -1 the active column is used.
virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE);
//! Set the text of a cell
virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text);
//! Set the text of a cell, and set a color of this cell.
virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color);
//! Set the data of a cell
//! data will not be serialized.
virtual void setCellData(u32 rowIndex, u32 columnIndex, void *data);
//! Set the color of a cell text
virtual void setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color);
//! Get the text of a cell
virtual const wchar_t* getCellText(u32 rowIndex, u32 columnIndex ) const;
//! Get the data of a cell
virtual void* getCellData(u32 rowIndex, u32 columnIndex ) const;
//! clears the table, deletes all items in the table
virtual void clear();
//! called if an event happened.
virtual bool OnEvent(const SEvent &event);
//! draws the element and its children
virtual void draw();
//! Set flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout
virtual void setDrawFlags(s32 flags);
//! Get the flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout
virtual s32 getDrawFlags() const;
//! Writes attributes of the object.
//! Implement this to expose the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml serialization purposes.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the object.
//! Implement this to set the attributes of your scene node animator for
//! scripting languages, editors, debuggers or xml deserialization purposes.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
protected:
virtual void refreshControls();
virtual void checkScrollbars();
private:
struct Cell
{
Cell() : IsOverrideColor(false), Data(0) {}
core::stringw Text;
core::stringw BrokenText;
bool IsOverrideColor;
video::SColor Color;
void *Data;
};
struct Row
{
Row() {}
core::array<Cell> Items;
};
struct Column
{
Column() : Width(0), OrderingMode(EGCO_NONE) {}
core::stringw Name;
u32 Width;
EGUI_COLUMN_ORDERING OrderingMode;
};
void breakText(const core::stringw &text, core::stringw & brokenText, u32 cellWidth);
void selectNew(s32 ypos, bool onlyHover=false);
bool selectColumnHeader(s32 xpos, s32 ypos);
bool dragColumnStart(s32 xpos, s32 ypos);
bool dragColumnUpdate(s32 xpos);
void recalculateHeights();
void recalculateWidths();
core::array< Column > Columns;
core::array< Row > Rows;
gui::IGUIFont* Font;
gui::IGUIScrollBar* VerticalScrollBar;
gui::IGUIScrollBar* HorizontalScrollBar;
bool Clip;
bool DrawBack;
bool MoveOverSelect;
bool Selecting;
s32 CurrentResizedColumn;
s32 ResizeStart;
bool ResizableColumns;
s32 ItemHeight;
s32 TotalItemHeight;
s32 TotalItemWidth;
s32 Selected;
s32 CellHeightPadding;
s32 CellWidthPadding;
s32 ActiveTab;
EGUI_ORDERING_MODE CurrentOrdering;
s32 DrawFlags;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
@@ -0,0 +1,176 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIToolBar.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIFont.h"
#include "CGUIButton.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIToolBar::CGUIToolBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
:IGUIToolBar(environment, parent, id, rectangle), ButtonX(5)
{
#ifdef _DEBUG
setDebugName("CGUIToolBar");
#endif
// calculate position and find other menubars
s32 y = 0;
s32 parentwidth = 100;
if (parent)
{
parentwidth = Parent->getAbsolutePosition().getWidth();
const core::list<IGUIElement*>& children = parent->getChildren();
core::list<IGUIElement*>::ConstIterator it = children.begin();
for (; it != children.end(); ++it)
{
core::rect<s32> r = (*it)->getAbsolutePosition();
if (r.UpperLeftCorner.X == 0 && r.UpperLeftCorner.Y <= y &&
r.LowerRightCorner.X == parentwidth)
y = r.LowerRightCorner.Y;
}
}
core::rect<s32> rr;
rr.UpperLeftCorner.X = 0;
rr.UpperLeftCorner.Y = y;
s32 height = Environment->getSkin()->getSize ( EGDS_MENU_HEIGHT );
/*IGUISkin* skin = Environment->getSkin();
IGUIFont* font = skin->getFont();
if (font)
{
s32 t = font->getDimension(L"A").Height + 5;
if (t > height)
height = t;
}*/
rr.LowerRightCorner.X = parentwidth;
rr.LowerRightCorner.Y = rr.UpperLeftCorner.Y + height;
setRelativePosition(rr);
}
//! called if an event happened.
bool CGUIToolBar::OnEvent(const SEvent& event)
{
if (isEnabled())
{
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
if (AbsoluteClippingRect.isPointInside(core::position2di(event.MouseInput.X, event.MouseInput.Y)))
return true;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUIToolBar::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
core::rect<s32> rect = AbsoluteRect;
core::rect<s32>* clip = &AbsoluteClippingRect;
// draw frame
skin->draw3DToolBar(this, rect, clip);
IGUIElement::draw();
}
//! Updates the absolute position.
void CGUIToolBar::updateAbsolutePosition()
{
if (Parent)
{
DesiredRect.UpperLeftCorner.X = 0;
DesiredRect.LowerRightCorner.X = Parent->getAbsolutePosition().getWidth();
}
IGUIElement::updateAbsolutePosition();
}
//! Adds a button to the tool bar
IGUIButton* CGUIToolBar::addButton(s32 id, const wchar_t* text,const wchar_t* tooltiptext,
video::ITexture* img, video::ITexture* pressed, bool isPushButton,
bool useAlphaChannel)
{
ButtonX += 3;
core::rect<s32> rectangle(ButtonX,2,ButtonX+1,3);
if ( img )
{
const core::dimension2du &size = img->getOriginalSize();
rectangle.LowerRightCorner.X = rectangle.UpperLeftCorner.X + size.Width + 8;
rectangle.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + size.Height + 6;
}
if ( text )
{
IGUISkin* skin = Environment->getSkin();
IGUIFont * font = skin->getFont(EGDF_BUTTON);
if ( font )
{
core::dimension2d<u32> dim = font->getDimension(text);
if ( (s32)dim.Width > rectangle.getWidth() )
rectangle.LowerRightCorner.X = rectangle.UpperLeftCorner.X + dim.Width + 8;
if ( (s32)dim.Height > rectangle.getHeight() )
rectangle.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + dim.Height + 6;
}
}
ButtonX += rectangle.getWidth();
IGUIButton* button = new CGUIButton(Environment, this, id, rectangle);
button->drop();
if (text)
button->setText(text);
if (tooltiptext)
button->setToolTipText(tooltiptext);
if (img)
button->setImage(img);
if (pressed)
button->setPressedImage(pressed);
if (isPushButton)
button->setIsPushButton(isPushButton);
if (useAlphaChannel)
button->setUseAlphaChannel(useAlphaChannel);
return button;
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
@@ -0,0 +1,52 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_TOOL_BAR_H_INCLUDED__
#define __C_GUI_TOOL_BAR_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIToolbar.h"
namespace irr
{
namespace gui
{
//! Stays at the top of its parent like the menu bar and contains tool buttons
class CGUIToolBar : public IGUIToolBar
{
public:
//! constructor
CGUIToolBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Updates the absolute position.
virtual void updateAbsolutePosition();
//! Adds a button to the tool bar
virtual IGUIButton* addButton(s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext=0,
video::ITexture* img=0, video::ITexture* pressed=0,
bool isPushButton=false, bool useAlphaChannel=false);
private:
s32 ButtonX;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif
File diff suppressed because it is too large Load Diff
+331
View File
@@ -0,0 +1,331 @@
// This file is part of the "Irrlicht Engine".
// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de
#ifndef __C_GUI_TREE_VIEW_H_INCLUDED__
#define __C_GUI_TREE_VIEW_H_INCLUDED__
#include "IGUITreeView.h"
#include "irrList.h"
namespace irr
{
namespace gui
{
// forward declarations
class IGUIFont;
class IGUIScrollBar;
class CGUITreeView;
//! Node for gui tree view
class CGUITreeViewNode : public IGUITreeViewNode
{
friend class CGUITreeView;
public:
//! constructor
CGUITreeViewNode( CGUITreeView* owner, CGUITreeViewNode* parent );
//! destructor
~CGUITreeViewNode();
//! returns the owner (tree view) of this node
virtual IGUITreeView* getOwner() const;
//! Returns the parent node of this node.
virtual IGUITreeViewNode* getParent() const;
//! returns the text of the node
virtual const wchar_t* getText() const
{ return Text.c_str(); }
//! sets the text of the node
virtual void setText( const wchar_t* text );
//! returns the icon text of the node
virtual const wchar_t* getIcon() const
{ return Icon.c_str(); }
//! sets the icon text of the node
virtual void setIcon( const wchar_t* icon );
//! returns the image index of the node
virtual u32 getImageIndex() const
{ return ImageIndex; }
//! sets the image index of the node
virtual void setImageIndex( u32 imageIndex )
{ ImageIndex = imageIndex; }
//! returns the image index of the node
virtual u32 getSelectedImageIndex() const
{ return SelectedImageIndex; }
//! sets the image index of the node
virtual void setSelectedImageIndex( u32 imageIndex )
{ SelectedImageIndex = imageIndex; }
//! returns the user data (void*) of this node
virtual void* getData() const
{ return Data; }
//! sets the user data (void*) of this node
virtual void setData( void* data )
{ Data = data; }
//! returns the user data2 (IReferenceCounted) of this node
virtual IReferenceCounted* getData2() const
{ return Data2; }
//! sets the user data2 (IReferenceCounted) of this node
virtual void setData2( IReferenceCounted* data )
{
if( Data2 )
{
Data2->drop();
}
Data2 = data;
if( Data2 )
{
Data2->grab();
}
}
//! returns the child item count
virtual u32 getChildCount() const
{ return Children.getSize(); }
//! removes all children (recursive) from this node
virtual void clearChildren();
//! returns true if this node has child nodes
virtual bool hasChildren() const
{ return !Children.empty(); }
//! Adds a new node behind the last child node.
//! \param text text of the new node
//! \param icon icon text of the new node
//! \param imageIndex index of the image for the new node (-1 = none)
//! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex)
//! \param data user data (void*) of the new node
//! \param data2 user data2 (IReferenceCounted*) of the new node
//! \return
//! returns the new node
virtual IGUITreeViewNode* addChildBack(
const wchar_t* text,
const wchar_t* icon = 0,
s32 imageIndex = -1,
s32 selectedImageIndex = -1,
void* data = 0,
IReferenceCounted* data2 = 0);
//! Adds a new node before the first child node.
//! \param text text of the new node
//! \param icon icon text of the new node
//! \param imageIndex index of the image for the new node (-1 = none)
//! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex)
//! \param data user data (void*) of the new node
//! \param data2 user data2 (IReferenceCounted*) of the new node
//! \return
//! returns the new node
virtual IGUITreeViewNode* addChildFront(
const wchar_t* text,
const wchar_t* icon = 0,
s32 imageIndex = -1,
s32 selectedImageIndex = -1,
void* data = 0,
IReferenceCounted* data2 = 0 );
//! Adds a new node behind the other node.
//! The other node has also te be a child node from this node.
//! \param text text of the new node
//! \param icon icon text of the new node
//! \param imageIndex index of the image for the new node (-1 = none)
//! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex)
//! \param data user data (void*) of the new node
//! \param data2 user data2 (IReferenceCounted*) of the new node
//! \return
//! returns the new node or 0 if other is no child node from this
virtual IGUITreeViewNode* insertChildAfter(
IGUITreeViewNode* other,
const wchar_t* text,
const wchar_t* icon = 0,
s32 imageIndex = -1,
s32 selectedImageIndex = -1,
void* data = 0,
IReferenceCounted* data2 = 0 );
//! Adds a new node before the other node.
//! The other node has also te be a child node from this node.
//! \param text text of the new node
//! \param icon icon text of the new node
//! \param imageIndex index of the image for the new node (-1 = none)
//! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex)
//! \param data user data (void*) of the new node
//! \param data2 user data2 (IReferenceCounted*) of the new node
//! \return
//! returns the new node or 0 if other is no child node from this
virtual IGUITreeViewNode* insertChildBefore(
IGUITreeViewNode* other,
const wchar_t* text,
const wchar_t* icon = 0,
s32 imageIndex = -1,
s32 selectedImageIndex = -1,
void* data = 0,
IReferenceCounted* data2 = 0 );
//! Return the first child note from this node.
virtual IGUITreeViewNode* getFirstChild() const;
//! Return the last child note from this node.
virtual IGUITreeViewNode* getLastChild() const;
//! Returns the preverse sibling node from this node.
virtual IGUITreeViewNode* getPrevSibling() const;
//! Returns the next sibling node from this node.
virtual IGUITreeViewNode* getNextSibling() const;
//! Returns the next visible (expanded, may be out of scrolling) node from this node.
virtual IGUITreeViewNode* getNextVisible() const;
//! Deletes a child node.
virtual bool deleteChild( IGUITreeViewNode* child );
//! Moves a child node one position up.
virtual bool moveChildUp( IGUITreeViewNode* child );
//! Moves a child node one position down.
virtual bool moveChildDown( IGUITreeViewNode* child );
//! Returns true if the node is expanded (children are visible).
virtual bool getExpanded() const
{ return Expanded; }
//! Sets if the node is expanded.
virtual void setExpanded( bool expanded );
//! Returns true if the node is currently selected.
virtual bool getSelected() const;
//! Sets this node as selected.
virtual void setSelected( bool selected );
//! Returns true if this node is the root node.
virtual bool isRoot() const;
//! Returns the level of this node.
virtual s32 getLevel() const;
//! Returns true if this node is visible (all parents are expanded).
virtual bool isVisible() const;
private:
CGUITreeView* Owner;
CGUITreeViewNode* Parent;
core::stringw Text;
core::stringw Icon;
s32 ImageIndex;
s32 SelectedImageIndex;
void* Data;
IReferenceCounted* Data2;
bool Expanded;
core::list<CGUITreeViewNode*> Children;
};
//! Default tree view GUI element.
class CGUITreeView : public IGUITreeView
{
friend class CGUITreeViewNode;
public:
//! constructor
CGUITreeView( IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool clip = true,
bool drawBack = false, bool scrollBarVertical = true, bool scrollBarHorizontal = true );
//! destructor
virtual ~CGUITreeView();
//! returns the root node (not visible) from the tree.
virtual IGUITreeViewNode* getRoot() const
{ return Root; }
//! returns the selected node of the tree or 0 if none is selected
virtual IGUITreeViewNode* getSelected() const
{ return Selected; }
//! returns true if the tree lines are visible
virtual bool getLinesVisible() const
{ return LinesVisible; }
//! sets if the tree lines are visible
virtual void setLinesVisible( bool visible )
{ LinesVisible = visible; }
//! called if an event happened.
virtual bool OnEvent( const SEvent &event );
//! draws the element and its children
virtual void draw();
//! Sets the font which should be used as icon font. This font is set to the Irrlicht engine
//! built-in-font by default. Icons can be displayed in front of every list item.
//! An icon is a string, displayed with the icon font. When using the build-in-font of the
//! Irrlicht engine as icon font, the icon strings defined in GUIIcons.h can be used.
virtual void setIconFont( IGUIFont* font );
//! Sets the image list which should be used for the image and selected image of every node.
//! The default is 0 (no images).
virtual void setImageList( IGUIImageList* imageList );
//! Returns the image list which is used for the nodes.
virtual IGUIImageList* getImageList() const
{ return ImageList; }
//! Sets if the image is left of the icon. Default is true.
virtual void setImageLeftOfIcon( bool bLeftOf )
{ ImageLeftOfIcon = bLeftOf; }
//! Returns if the Image is left of the icon. Default is true.
virtual bool getImageLeftOfIcon() const
{ return ImageLeftOfIcon; }
//! Returns the node which is associated to the last event.
virtual IGUITreeViewNode* getLastEventNode() const
{ return LastEventNode; }
private:
//! calculates the heigth of an node and of all visible nodes.
void recalculateItemHeight();
//! executes an mouse action (like selectNew of CGUIListBox)
void mouseAction( s32 xpos, s32 ypos, bool onlyHover = false );
CGUITreeViewNode* Root;
IGUITreeViewNode* Selected;
s32 ItemHeight;
s32 IndentWidth;
s32 TotalItemHeight;
s32 TotalItemWidth;
IGUIFont* Font;
IGUIFont* IconFont;
IGUIScrollBar* ScrollBarH;
IGUIScrollBar* ScrollBarV;
IGUIImageList* ImageList;
IGUITreeViewNode* LastEventNode;
bool LinesVisible;
bool Selecting;
bool Clip;
bool DrawBack;
bool ImageLeftOfIcon;
};
} // end namespace gui
} // end namespace irr
#endif
+404
View File
@@ -0,0 +1,404 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIWindow.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIFont.h"
#include "IGUIFontBitmap.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUIWindow(environment, parent, id, rectangle), Dragging(false), IsDraggable(true), DrawBackground(true), DrawTitlebar(true), IsActive(false)
{
#ifdef _DEBUG
setDebugName("CGUIWindow");
#endif
IGUISkin* skin = 0;
if (environment)
skin = environment->getSkin();
CurrentIconColor = video::SColor(255,255,255,255);
s32 buttonw = 15;
if (skin)
{
buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
}
s32 posx = RelativeRect.getWidth() - buttonw - 4;
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close" );
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
posx -= buttonw + 2;
RestoreButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_RESTORE) : L"Restore" );
RestoreButton->setVisible(false);
RestoreButton->setSubElement(true);
RestoreButton->setTabStop(false);
RestoreButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
posx -= buttonw + 2;
MinButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_MINIMIZE) : L"Minimize" );
MinButton->setVisible(false);
MinButton->setSubElement(true);
MinButton->setTabStop(false);
MinButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
MinButton->grab();
RestoreButton->grab();
CloseButton->grab();
// this element is a tab group
setTabGroup(true);
setTabStop(true);
setTabOrder(-1);
refreshSprites();
updateClientRect();
}
//! destructor
CGUIWindow::~CGUIWindow()
{
if (MinButton)
MinButton->drop();
if (RestoreButton)
RestoreButton->drop();
if (CloseButton)
CloseButton->drop();
}
void CGUIWindow::refreshSprites()
{
if (!Environment)
return;
IGUISkin* skin = Environment->getSkin();
if ( !skin )
return;
IGUISpriteBank* sprites = skin->getSpriteBank();
if ( !sprites )
return;
CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
if (sprites)
{
CloseButton->setSpriteBank(sprites);
CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor);
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor);
RestoreButton->setSpriteBank(sprites);
RestoreButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor);
RestoreButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor);
MinButton->setSpriteBank(sprites);
MinButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor);
MinButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor);
}
}
//! called if an event happened.
bool CGUIWindow::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
Dragging = false;
IsActive = false;
}
else
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
if (Parent && ((event.GUIEvent.Caller == this) || isMyChild(event.GUIEvent.Caller)))
{
Parent->bringToFront(this);
IsActive = true;
}
else
{
IsActive = false;
}
}
else
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
if (event.GUIEvent.Caller == CloseButton)
{
if (Parent)
{
// send close event to parent
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
// if the event was not absorbed
if (!Parent->OnEvent(e))
remove();
return true;
}
else
{
remove();
return true;
}
}
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = IsDraggable;
if (Parent)
Parent->bringToFront(this);
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
return true;
case EMIE_MOUSE_MOVED:
if (!event.MouseInput.isLeftPressed())
Dragging = false;
if (Dragging)
{
// gui window should not be dragged outside its parent
if (Parent &&
(event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1))
return true;
move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
return true;
}
break;
default:
break;
}
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! Updates the absolute position.
void CGUIWindow::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
}
//! draws the element and its children
void CGUIWindow::draw()
{
if (IsVisible)
{
IGUISkin* skin = Environment->getSkin();
// update each time because the skin is allowed to change this always.
updateClientRect();
if ( CurrentIconColor != skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL) )
refreshSprites();
core::rect<s32> rect = AbsoluteRect;
// draw body fast
if (DrawBackground)
{
rect = skin->draw3DWindowBackground(this, DrawTitlebar,
skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect);
if (DrawTitlebar && Text.size())
{
rect.UpperLeftCorner.X += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_X);
rect.UpperLeftCorner.Y += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_Y);
rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;
IGUIFont* font = skin->getFont(EGDF_WINDOW);
if (font)
{
font->draw(Text.c_str(), rect,
skin->getColor(IsActive ? EGDC_ACTIVE_CAPTION:EGDC_INACTIVE_CAPTION),
false, true, &AbsoluteClippingRect);
}
}
}
}
IGUIElement::draw();
}
//! Returns pointer to the close button
IGUIButton* CGUIWindow::getCloseButton() const
{
return CloseButton;
}
//! Returns pointer to the minimize button
IGUIButton* CGUIWindow::getMinimizeButton() const
{
return MinButton;
}
//! Returns pointer to the maximize button
IGUIButton* CGUIWindow::getMaximizeButton() const
{
return RestoreButton;
}
//! Returns true if the window is draggable, false if not
bool CGUIWindow::isDraggable() const
{
return IsDraggable;
}
//! Sets whether the window is draggable
void CGUIWindow::setDraggable(bool draggable)
{
IsDraggable = draggable;
if (Dragging && !IsDraggable)
Dragging = false;
}
//! Set if the window background will be drawn
void CGUIWindow::setDrawBackground(bool draw)
{
DrawBackground = draw;
}
//! Get if the window background will be drawn
bool CGUIWindow::getDrawBackground() const
{
return DrawBackground;
}
//! Set if the window titlebar will be drawn
void CGUIWindow::setDrawTitlebar(bool draw)
{
DrawTitlebar = draw;
}
//! Get if the window titlebar will be drawn
bool CGUIWindow::getDrawTitlebar() const
{
return DrawTitlebar;
}
void CGUIWindow::updateClientRect()
{
if (! DrawBackground )
{
ClientRect = core::rect<s32>(0,0, AbsoluteRect.getWidth(), AbsoluteRect.getHeight());
return;
}
IGUISkin* skin = Environment->getSkin();
skin->draw3DWindowBackground(this, DrawTitlebar,
skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect, &ClientRect);
ClientRect -= AbsoluteRect.UpperLeftCorner;
}
//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars)
core::rect<s32> CGUIWindow::getClientRect() const
{
return ClientRect;
}
//! Writes attributes of the element.
void CGUIWindow::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIWindow::serializeAttributes(out,options);
out->addBool("IsDraggable", IsDraggable);
out->addBool("DrawBackground", DrawBackground);
out->addBool("DrawTitlebar", DrawTitlebar);
// Currently we can't just serialize attributes of sub-elements.
// To do this we either
// a) allow further serialization after attribute serialiation (second function, callback or event)
// b) add an IGUIElement attribute
// c) extend the attribute system to allow attributes to have sub-attributes
// We just serialize the most important info for now until we can do one of the above solutions.
out->addBool("IsCloseVisible", CloseButton->isVisible());
out->addBool("IsMinVisible", MinButton->isVisible());
out->addBool("IsRestoreVisible", RestoreButton->isVisible());
}
//! Reads attributes of the element
void CGUIWindow::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIWindow::deserializeAttributes(in,options);
Dragging = false;
IsActive = false;
IsDraggable = in->getAttributeAsBool("IsDraggable");
DrawBackground = in->getAttributeAsBool("DrawBackground");
DrawTitlebar = in->getAttributeAsBool("DrawTitlebar");
CloseButton->setVisible(in->getAttributeAsBool("IsCloseVisible"));
MinButton->setVisible(in->getAttributeAsBool("IsMinVisible"));
RestoreButton->setVisible(in->getAttributeAsBool("IsRestoreVisible"));
updateClientRect();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

Some files were not shown because too many files have changed in this diff Show More