Merge from trunk, revisions 3831-3909. All fixes and additions from the last three month.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@3910 dfc29bdd-3216-0410-991c-e03cc46cb475
master
hybrid 2011-09-08 22:15:27 +00:00
parent 7687813257
commit 5caf2b4045
73 changed files with 3264 additions and 1119 deletions

View File

@ -1,5 +1,27 @@
Changes in 1.8 (??.??.2011)
- Add IGUIComboBox::setMaxSelectionRows and IGUIComboBox::getMaxSelectionRows
- Scenemanager switches from type ESNT_UNKNOWN to type ESNT_SCENE_MANAGER.
- Add getActiveFont to all elements which have setOverrideFont for cleaner code
- Add getOverrideFont to all elements which have setOverrideFont to have a consistent interface
- IGUIEditBox: added missing serialization for Border
- IGUIEditBox: remove bug that added spaces to the end of each line
- IGUIEditBox: fix crash that happened when wordwrapping was enabled, spaces were entered beyond the border and then cursor-key was pressed.
- IGUIEditBox::setDrawBackground added.
- CGUISkin::draw3DSunkenPane no longer ignores fillBackGround in non-flat mode. Also borderlines are no longer drawn overlapping to avoid ugly corners.
- CDummyTransformationSceneNode::clone() added.
- IParticleSystemSceneNode::doParticleSystem now public to allow rendering outside scenegraph.
- Renamed IOSOperator::getOperationSystemVersion to getOperatingSystemVersion. Changed return type from wchar_t to core::stringc, as that's the internal representation the name is built on.
- Added IGUITabControl::insertTab, IGUITabControl::removeTab, IGUITabControl::clear and IGUITabControl::getTabAt
@ -12,7 +34,7 @@ Changes in 1.8 (??.??.2011)
- Added ISceneManager::createSceneNodeAnimator to create animators by name
- The Makefile now creates a symlink from the soname to the binary name during install. Binary compatibility is only confirmed between minor releases, so the only useful symlink is from libIrrlicht.so.1.8 to libIrrlicht.so.1.8.0; others should rightly fail.
- The Makefile now creates a symlink from the soname to the binary name during install. Binary compatibility is only confirmed between same minor releases.
- Added SMF mesh loader, loads meshes from 3D World Studio. Originally written by Joseph Ellis
@ -266,6 +288,27 @@ The following names can be queried for the given types:
-----------------------------
Changes in 1.7.3 (??.??.2011)
- editbox no longer moves text into next line when it fails wrapping creating senseless empty lines which mess up scrolling.
- Fix crash in editbox when scrolling up with empty first lines caused by textwrapping.
- triangle3d::isPointInside can now work with larger integers, old version failed already with values in the 3-digit range. It got also faster. (thx @ Eigen for report + testcase and REDDemon for patch proposal).
- Fix focus problem when removing an unfocused modal dialog reported by Reiko here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44358
- Add integer template specialization for vector3d::getSphericalCoordinateAngles which rounds angles to nearest integer now.
- Recalculate FrameRect and ScrollPos in CGUIEditBox when AbsoluteRect gets changed (thx @ serengeor for report + testcase)
- Fix 'k' in bigfont.png (thx @ Scrappi for reporting)
- fix serialization for CBillboardSceneNode, it had missed 2 color (thx for finding + patch from pc0de)
- EMIE_MOUSE_WHEEL messages now handled correctly in several gui-element when wheel isn't just 1.0 or -1.0 (thx @ Reiko for reporting)
- Fix problems in Textwrapping in CGUIStaticText. Did use wrong size and did ignore last word of the text (thx @ Reiko for bugreport)
- Fix crash in collada (.dae) loading
- Fix memory-leaks in example 22 MaterialViewer

View File

@ -24,8 +24,8 @@
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-W" />
<Add option="-g" />
<Add option="-W" />
<Add option="-D_IRR_STATIC_LIB_" />
<Add directory="../../lib/Linux" />
</Compiler>
@ -33,7 +33,7 @@
<Add library="Xxf86vm" />
<Add library="Xcursor" />
<Add library="GL" />
<Add directory="../../lib/gcc" />
<Add directory="../../lib/Linux" />
</Linker>
</Target>
</Build>

View File

@ -18,7 +18,9 @@
<Option type="1" />
<Option compiler="gcc" />
<Linker>
<Add library="Irrlicht" />
<Add library="Xxf86vm" />
<Add library="Xcursor" />
<Add library="GL" />
<Add directory="../../lib/Linux" />
</Linker>
</Target>
@ -27,7 +29,7 @@
<Add directory="../../include" />
</Compiler>
<Linker>
<Add option="../../lib/Win32-gcc/libIrrlicht.a" />
<Add library="Irrlicht" />
</Linker>
<Unit filename="main.cpp" />
<Extensions>

View File

@ -18,6 +18,9 @@ namespace scene
name clashes with external scene nodes.*/
enum ESCENE_NODE_TYPE
{
//! of type CSceneManager (note that ISceneManager is not(!) an ISceneNode)
ESNT_SCENE_MANAGER = MAKE_IRR_ID('s','m','n','g'),
//! simple cube scene node
ESNT_CUBE = MAKE_IRR_ID('c','u','b','e'),

View File

@ -76,6 +76,9 @@ namespace scene
/** 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.
Note that setTarget uses the current absolute position
internally, so if you changed setPosition since last rendering you must
call updateAbsolutePosition before using this function.
\param pos Look at target of the camera, in world co-ordinates. */
virtual void setTarget(const core::vector3df& pos) =0;

View File

@ -284,7 +284,7 @@ struct SEvent
//! Y position of mouse cursor
s32 Y;
//! mouse wheel delta, usually 1.0 or -1.0.
//! mouse wheel delta, often 1.0 or -1.0, but can have other values < 0.f or > 0.f;
/** Only valid if event was EMIE_MOUSE_WHEEL */
f32 Wheel;

View File

@ -65,6 +65,15 @@ namespace gui
\param font: New font to set. */
virtual void setOverrideFont(IGUIFont* font=0) = 0;
//! Gets the override font (if any)
/** \return The override font (may be 0) */
virtual IGUIFont* getOverrideFont(void) const = 0;
//! 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 = 0;
//! Sets an image which should be displayed on the button when it is in normal state.
/** \param image: Image to be displayed */
virtual void setImage(video::ITexture* image=0) = 0;

View File

@ -55,6 +55,12 @@ namespace gui
\param vertical: EGUIA_UPPERLEFT to align with top edge,
EGUIA_LOWEERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) = 0;
//! Set the maximal number of rows for the selection listbox
virtual void setMaxSelectionRows(u32 max) = 0;
//! Get the maximimal number of rows for the selection listbox
virtual u32 getMaxSelectionRows() const = 0;
};

View File

@ -28,6 +28,15 @@ namespace gui
\param font: New font to set. */
virtual void setOverrideFont(IGUIFont* font=0) = 0;
//! Gets the override font (if any)
/** \return The override font (may be 0) */
virtual IGUIFont* getOverrideFont() const = 0;
//! 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 = 0;
//! Sets another color for the text.
/** If set, the edit box does not use the EGDC_BUTTON_TEXT color defined
in the skin, but the set color instead. You don't need to call
@ -51,6 +60,9 @@ namespace gui
/** \return true if the override color is enabled, false otherwise */
virtual bool isOverrideColorEnabled(void) const = 0;
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw) = 0;
//! Turns the border on or off
/** \param border: true if you want the border to be drawn, false if not */
virtual void setDrawBorder(bool border) = 0;

View File

@ -50,6 +50,7 @@ namespace gui
virtual void setStepSize(f32 step=1.f) = 0;
//! 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) = 0;

View File

@ -32,6 +32,11 @@ namespace gui
/** \return The override font (may be 0) */
virtual IGUIFont* getOverrideFont(void) const = 0;
//! 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 = 0;
//! Sets another color for the text.
/** If set, the static text does not use the EGDC_BUTTON_TEXT color defined
in the skin, but the set color instead. You don't need to call
@ -91,10 +96,10 @@ namespace gui
/** If the text is broken, this returns the width of the widest line
\return The width of the text, or the widest broken line. */
virtual s32 getTextWidth(void) const = 0;
//! Set whether the text in this label should be clipped if it goes outside bounds
virtual void setTextRestrainedInside(bool restrainedInside) = 0;
//! Checks if the text in this label should be clipped if it goes outside bounds
virtual bool isTextRestrainedInside() const = 0;

View File

@ -67,6 +67,11 @@ public:
//! Remove all currently visible particles
virtual void clearParticles() = 0;
//! Do manually update the particles.
//! This should only be called when you want to render the node outside the scenegraph,
//! as the node will care about this otherwise automatically.
virtual void doParticleSystem(u32 time) = 0;
//! Gets the particle emitter, which creates the particles.
/** \return The particle emitter. Can be 0 if none is set. */
virtual IParticleEmitter* getEmitter() =0;

View File

@ -90,7 +90,7 @@ namespace scene
//! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order.
ESNRP_TRANSPARENT_EFFECT =32,
//! Drawn after the transparent nodes, the time for drawing shadow volumes
//! Drawn after the solid nodes, before the transparent nodes, the time for drawing shadow volumes
ESNRP_SHADOW =64
};

View File

@ -14,10 +14,6 @@ namespace irr
class ITimer : public virtual IReferenceCounted
{
public:
//! destructor
virtual ~ITimer() {}
//! Returns current real time in milliseconds of the system.
/** This value does not start with 0 when the application starts.
For example in one implementation the value returned could be the
@ -105,4 +101,3 @@ public:
} // end namespace irr
#endif

View File

@ -20,6 +20,7 @@ namespace irr
{
class ILogger;
class IEventReceiver;
class IRandomizer;
namespace io {
class IFileSystem;
@ -131,6 +132,22 @@ namespace irr
\return Pointer to the ITimer object. */
virtual ITimer* getTimer() = 0;
//! Provides access to the engine's currently set randomizer.
/** \return Pointer to the IRandomizer object. */
virtual IRandomizer* getRandomizer() const =0;
//! Sets a new randomizer.
/** \param r Pointer to the new IRandomizer object. This object is
grab()'ed by the engine and will be released upon the next setRandomizer
call or upon device destruction. */
virtual void setRandomizer(IRandomizer* r) =0;
//! Creates a new default randomizer.
/** The default randomizer provides the random sequence known from previous
Irrlicht versions and is the initial randomizer set on device creation.
\return Pointer to the default IRandomizer object. */
virtual IRandomizer* createDefaultRandomizer() const =0;
//! Sets the caption of the window.
/** \param text: New text of the window caption. */
virtual void setWindowCaption(const wchar_t* text) = 0;

View File

@ -58,6 +58,12 @@ class map
return Value;
}
ValueTypeRB& getValue()
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Value;
}
KeyTypeRB getKey() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
@ -157,7 +163,7 @@ class map
return Cur==0;
}
Node* getNode()
Node* getNode() const
{
return Cur;
}
@ -179,13 +185,12 @@ class map
dec();
}
Node* operator -> ()
Node* operator->()
{
return getNode();
}
Node& operator* ()
Node& operator*()
{
_IRR_DEBUG_BREAK_IF(atEnd()) // access violation
@ -194,14 +199,14 @@ class map
private:
Node* getMin(Node* n)
Node* getMin(Node* n) const
{
while(n && n->getLeftChild())
n = n->getLeftChild();
return n;
}
Node* getMax(Node* n)
Node* getMax(Node* n) const
{
while(n && n->getRightChild())
n = n->getRightChild();
@ -275,6 +280,153 @@ class map
Node* Cur;
}; // Iterator
//! Const Iterator
class ConstIterator
{
public:
ConstIterator() : Root(0), Cur(0) {}
// Constructor(Node*)
ConstIterator(const Node* root) : Root(root)
{
reset();
}
// Copy constructor
ConstIterator(const ConstIterator& src) : Root(src.Root), Cur(src.Cur) {}
ConstIterator(const Iterator& src) : Root(src.Root), Cur(src.Cur) {}
void reset(bool atLowest=true)
{
if (atLowest)
Cur = getMin(Root);
else
Cur = getMax(Root);
}
bool atEnd() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Cur==0;
}
const Node* getNode() const
{
return Cur;
}
ConstIterator& operator=(const ConstIterator& src)
{
Root = src.Root;
Cur = src.Cur;
return (*this);
}
void operator++(int)
{
inc();
}
void operator--(int)
{
dec();
}
const Node* operator->()
{
return getNode();
}
const Node& operator*()
{
_IRR_DEBUG_BREAK_IF(atEnd()) // access violation
return *Cur;
}
private:
const Node* getMin(const Node* n) const
{
while(n && n->getLeftChild())
n = n->getLeftChild();
return n;
}
const Node* getMax(const Node* n) const
{
while(n && n->getRightChild())
n = n->getRightChild();
return n;
}
void inc()
{
// Already at end?
if (Cur==0)
return;
if (Cur->getRightChild())
{
// If current node has a right child, the next higher node is the
// node with lowest key beneath the right child.
Cur = getMin(Cur->getRightChild());
}
else if (Cur->isLeftChild())
{
// No right child? Well if current node is a left child then
// the next higher node is the parent
Cur = Cur->getParent();
}
else
{
// Current node neither is left child nor has a right child.
// Ie it is either right child or root
// The next higher node is the parent of the first non-right
// child (ie either a left child or the root) up in the
// hierarchy. Root's parent is 0.
while(Cur->isRightChild())
Cur = Cur->getParent();
Cur = Cur->getParent();
}
}
void dec()
{
// Already at end?
if (Cur==0)
return;
if (Cur->getLeftChild())
{
// If current node has a left child, the next lower node is the
// node with highest key beneath the left child.
Cur = getMax(Cur->getLeftChild());
}
else if (Cur->isRightChild())
{
// No left child? Well if current node is a right child then
// the next lower node is the parent
Cur = Cur->getParent();
}
else
{
// Current node neither is right child nor has a left child.
// Ie it is either left child or root
// The next higher node is the parent of the first non-left
// child (ie either a right child or the root) up in the
// hierarchy. Root's parent is 0.
while(Cur->isLeftChild())
Cur = Cur->getParent();
Cur = Cur->getParent();
}
}
const Node* Root;
const Node* Cur;
}; // ConstIterator
//! Parent First Iterator.
@ -286,11 +438,7 @@ class map
{
public:
ParentFirstIterator() : Root(0), Cur(0)
{
}
ParentFirstIterator() : Root(0), Cur(0) {}
explicit ParentFirstIterator(Node* root) : Root(root), Cur(0)
{
@ -302,7 +450,6 @@ class map
Cur = Root;
}
bool atEnd() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
@ -314,7 +461,6 @@ class map
return Cur;
}
ParentFirstIterator& operator=(const ParentFirstIterator& src)
{
Root = src.Root;
@ -322,13 +468,11 @@ class map
return (*this);
}
void operator++(int)
{
inc();
}
Node* operator -> ()
{
return getNode();
@ -795,27 +939,36 @@ class map
//------------------------------
//! Returns an iterator
Iterator getIterator()
Iterator getIterator() const
{
Iterator it(getRoot());
return it;
}
//! Returns a Constiterator
ConstIterator getConstIterator() const
{
Iterator it(getRoot());
return it;
}
//! Returns a ParentFirstIterator.
//! Traverses the tree from top to bottom. Typical usage is
//! when storing the tree structure, because when reading it
//! later (and inserting elements) the tree structure will
//! be the same.
ParentFirstIterator getParentFirstIterator()
ParentFirstIterator getParentFirstIterator() const
{
ParentFirstIterator it(getRoot());
return it;
}
//! Returns a ParentLastIterator to traverse the tree from
//! bottom to top.
//! Typical usage is when deleting all elements in the tree
//! because you must delete the children before you delete
//! their parent.
ParentLastIterator getParentLastIterator()
ParentLastIterator getParentLastIterator() const
{
ParentLastIterator it(getRoot());
return it;

View File

@ -112,6 +112,7 @@
#include "IMeshManipulator.h"
#include "IMeshSceneNode.h"
#include "IMeshWriter.h"
#include "IColladaMeshWriter.h"
#include "IMetaTriangleSelector.h"
#include "IOSOperator.h"
#include "IParticleSystemSceneNode.h" // also includes all emitters and attractors

View File

@ -648,24 +648,20 @@ inline core::quaternion& quaternion::rotationFromTo(const vector3df& from, const
else if (d <= -1.0f) // exactly opposite
{
core::vector3df axis(1.0f, 0.f, 0.f);
axis = axis.crossProduct(core::vector3df(X,Y,Z));
axis = axis.crossProduct(v0);
if (axis.getLength()==0)
{
axis.set(0.f,1.f,0.f);
axis.crossProduct(core::vector3df(X,Y,Z));
axis.crossProduct(v0);
}
return this->fromAngleAxis(core::PI, axis);
// same as fromAngleAxis(core::PI, axis).normalize();
return set(axis.X, axis.Y, axis.Z, 0).normalize();
}
const f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt
const f32 invs = 1.f / s;
const vector3df c = v0.crossProduct(v1)*invs;
X = c.X;
Y = c.Y;
Z = c.Z;
W = s * 0.5f;
return *this;
return set(c.X, c.Y, c.Z, s * 0.5f).normalize();
}

View File

@ -81,21 +81,39 @@ namespace core
return d2 < d3 ? rbc : rca;
}
//! Check if a point is inside the triangle
//! Check if a point is inside the triangle (border-points count also as inside)
/** \param p Point to test. Assumes that this point is already
on the plane of the triangle.
\return True if the point is inside the triangle, otherwise false. */
bool isPointInside(const vector3d<T>& p) const
{
return (isOnSameSide(p, pointA, pointB, pointC) &&
isOnSameSide(p, pointB, pointA, pointC) &&
isOnSameSide(p, pointC, pointA, pointB));
const vector3d<T> a = pointC - pointA;
const vector3d<T> b = pointB - pointA;
const vector3d<T> c = p - pointA;
const f64 dotAA = a.dotProduct( a);
const f64 dotAB = a.dotProduct( b);
const f64 dotAC = a.dotProduct( c);
const f64 dotBB = b.dotProduct( b);
const f64 dotBC = b.dotProduct( c);
// get coordinates in barycentric coordinate system
const f64 invDenom = 1/(dotAA * dotBB - dotAB * dotAB);
const f64 u = (dotBB * dotAC - dotAB * dotBC) * invDenom;
const f64 v = (dotAA * dotBC - dotAB * dotAC ) * invDenom;
// We count border-points as inside to keep downward compatibility.
// That's why we use >= and <= instead of > and < as more commonly seen on the web.
return (u >= 0) && (v >= 0) && (u + v <= 1);
}
//! Check if a point is inside the triangle.
/** This method is an implementation of the example used in a
paper by Kasper Fauerby original written by Keidy from
Mr-Gamemaker.
This was once faster than an old isPointInside implementation, but the
current isPointInside is usualy as fast, sometimes even faster.
Border-points in isPointInsideFast are not defined, some are inside and some outside.
\param p Point to test. Assumes that this point is already
on the plane of the triangle.
\return True if point is inside the triangle, otherwise false. */

View File

@ -246,7 +246,7 @@ public:
if (tmp < 0.0)
tmp = -tmp;
if ( tmp > 1.0 ) // avoid floating-point trouble
tmp = 1.0;
tmp = 1.0;
return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64;
}

View File

@ -421,6 +421,26 @@ namespace core
template <>
inline vector3d<s32>& vector3d<s32>::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;}
template <>
inline vector3d<s32> vector3d<s32>::getSphericalCoordinateAngles()
{
vector3d<s32> angle;
const f64 length = X*X + Y*Y + Z*Z;
if (length)
{
if (X!=0)
{
angle.Y = round32((f32)(atan2((f64)Z,(f64)X) * RADTODEG64));
}
else if (Z<0)
angle.Y=180;
angle.X = round32((f32)(acos(Y * core::reciprocal_squareroot(length)) * RADTODEG64));
}
return angle;
}
//! Typedef for a f32 3d vector.
typedef vector3d<f32> vector3df;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -15,8 +15,7 @@ namespace scene
{
const s32 MD2_FRAME_SHIFT = 2;
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT );
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / (1 << MD2_FRAME_SHIFT);
const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162;
@ -194,27 +193,27 @@ struct SMD2AnimationType
static const SMD2AnimationType MD2AnimationTypeList[21] =
{
{ 0, 39, 9 }, // STAND
{ 40, 45, 10 }, // RUN
{ 46, 53, 10 }, // ATTACK
{ 54, 57, 7 }, // PAIN_A
{ 58, 61, 7 }, // PAIN_B
{ 62, 65, 7 }, // PAIN_C
{ 66, 71, 7 }, // JUMP
{ 72, 83, 7 }, // FLIP
{ 84, 94, 7 }, // SALUTE
{ 95, 111, 10 }, // FALLBACK
{ 112, 122, 7 }, // WAVE
{ 123, 134, 6 }, // POINT
{ 135, 153, 10 }, // CROUCH_STAND
{ 154, 159, 7 }, // CROUCH_WALK
{ 160, 168, 10 }, // CROUCH_ATTACK
{ 169, 172, 7 }, // CROUCH_PAIN
{ 173, 177, 5 }, // CROUCH_DEATH
{ 178, 183, 7 }, // DEATH_FALLBACK
{ 184, 189, 7 }, // DEATH_FALLFORWARD
{ 190, 197, 7 }, // DEATH_FALLBACKSLOW
{ 198, 198, 5 }, // BOOM
{ 0, 39, 9}, // STAND
{ 40, 45, 10}, // RUN
{ 46, 53, 10}, // ATTACK
{ 54, 57, 7}, // PAIN_A
{ 58, 61, 7}, // PAIN_B
{ 62, 65, 7}, // PAIN_C
{ 66, 71, 7}, // JUMP
{ 72, 83, 7}, // FLIP
{ 84, 94, 7}, // SALUTE
{ 95, 111, 10}, // FALLBACK
{112, 122, 7}, // WAVE
{123, 134, 6}, // POINT
{135, 153, 10}, // CROUCH_STAND
{154, 159, 7}, // CROUCH_WALK
{160, 168, 10}, // CROUCH_ATTACK
{169, 172, 7}, // CROUCH_PAIN
{173, 177, 5}, // CROUCH_DEATH
{178, 183, 7}, // DEATH_FALLBACK
{184, 189, 7}, // DEATH_FALLFORWARD
{190, 197, 7}, // DEATH_FALLBACKSLOW
{198, 198, 5}, // BOOM
};
@ -238,6 +237,7 @@ CAnimatedMeshMD2::~CAnimatedMeshMD2()
InterpolationBuffer->drop();
}
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
u32 CAnimatedMeshMD2::getFrameCount() const
{
@ -294,7 +294,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
{
u32 firstFrame, secondFrame;
f32 div;
core::vector3df* NormalTable = (core::vector3df*)&Q2_VERTEX_NORMAL_TABLE;
// TA: resolve missing ipol in loop between end-start
@ -311,10 +310,10 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
u32 e = endFrameLoop >> MD2_FRAME_SHIFT;
firstFrame = frame >> MD2_FRAME_SHIFT;
secondFrame = core::if_c_a_else_b ( firstFrame + 1 > e, s, firstFrame + 1 );
secondFrame = core::if_c_a_else_b(firstFrame + 1 > e, s, firstFrame + 1);
firstFrame = core::s32_min ( FrameCount - 1, firstFrame );
secondFrame = core::s32_min ( FrameCount - 1, secondFrame );
firstFrame = core::s32_min(FrameCount - 1, firstFrame);
secondFrame = core::s32_min(FrameCount - 1, secondFrame);
//div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT);
frame &= (1<<MD2_FRAME_SHIFT) - 1;
@ -322,24 +321,29 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
}
video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices());
SMD2Vert* first = FrameList[firstFrame].pointer();
SMD2Vert* second = FrameList[secondFrame].pointer();
SMD2Vert* first = FrameList[firstFrame].pointer();
SMD2Vert* second = FrameList[secondFrame].pointer();
// interpolate both frames
const u32 count = FrameList[firstFrame].size();
for (u32 i=0; i<count; ++i)
{
core::vector3df one, two;
one.X = f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X;
one.Y = f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y;
one.Z = f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z;
two.X = f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X;
two.Y = f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y;
two.Z = f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z;
target->Pos = (two - one) * div + one;
target->Normal = (NormalTable[second->NormalIdx] - NormalTable[first->NormalIdx]) * div
+ NormalTable[first->NormalIdx];
const core::vector3df one = core::vector3df(f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X,
f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y,
f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z);
const core::vector3df two = core::vector3df(f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X,
f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y,
f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z);
target->Pos = two.getInterpolated(one, div);
const core::vector3df n1(
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][0],
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][2],
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][1]);
const core::vector3df n2(
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][0],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][2],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][1]);
target->Normal = n2.getInterpolated(n1, div);
++target;
++first;
++second;
@ -381,7 +385,7 @@ const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
//! set user axis aligned bounding box
void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box)
void CAnimatedMeshMD2::setBoundingBox(const core::aabbox3df& box)
{
InterpolationBuffer->BoundingBox = box;
}
@ -396,7 +400,7 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
//! Returns frame loop data for a special MD2 animation type.
void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
s32& outBegin, s32& outEnd, s32& outFPS) const
s32& outBegin, s32& outEnd, s32& outFPS) const
{
if (l < 0 || l >= EMAT_COUNT)
return;
@ -405,7 +409,7 @@ void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT;
// correct to anim between last->first frame
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1;
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT;
}
@ -420,7 +424,7 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
{
outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT;
outEnd = AnimationData[i].end << MD2_FRAME_SHIFT;
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1;
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT;
return true;
}

View File

@ -196,7 +196,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0;
#endif
#else
// As multiple scene nodes may be sharing the same skinned mesh, we have to
// re-animate it every frame to ensure that this node gets the mesh that it needs.
@ -230,6 +230,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
}
return skinnedMesh;
#endif
}
}
@ -579,7 +580,7 @@ IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName)
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
return 0;
#endif
#else
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
{
@ -606,6 +607,7 @@ IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName)
}
return JointChildSceneNodes[number];
#endif
}
@ -617,7 +619,7 @@ IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(u32 jointID)
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING);
return 0;
#endif
#else
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
{
@ -634,6 +636,7 @@ IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(u32 jointID)
}
return JointChildSceneNodes[jointID];
#endif
}
//! Gets joint count.
@ -641,7 +644,7 @@ u32 CAnimatedMeshSceneNode::getJointCount() const
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0;
#endif
#else
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
return 0;
@ -649,6 +652,7 @@ u32 CAnimatedMeshSceneNode::getJointCount() const
ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh;
return skinnedMesh->getJointCount();
#endif
}
@ -949,7 +953,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return;
#endif
#else
if (Mesh && Mesh->getMeshType() == EAMT_SKINNED )
{
checkJoints();
@ -1021,6 +1025,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
}
}
}
#endif
}
/*!
@ -1029,7 +1034,7 @@ void CAnimatedMeshSceneNode::checkJoints()
{
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return;
#endif
#else
if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED)
return;
@ -1047,6 +1052,7 @@ void CAnimatedMeshSceneNode::checkJoints()
JointsUsed=true;
JointMode=EJUOR_READ;
}
#endif
}
/*!

View File

@ -181,6 +181,8 @@ void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttrib
Size.Height = in->getAttributeAsFloat("Height");
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;
setSize(Size);
}

View File

@ -1272,7 +1272,7 @@ void CColladaFileLoader::readTexture(io::IXMLReaderUTF8* reader)
if (input)
{
const core::stringc imageName = input->Source;
texture.Texture = getTextureFromImage(imageName);
texture.Texture = getTextureFromImage(imageName, NULL);
}
}
}
@ -1370,6 +1370,7 @@ void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect *
{
Effects.push_back(SColladaEffect());
effect = &Effects.getLast();
effect->Parameters = new io::CAttributes();
effect->Id = readId(reader);
effect->Transparency = 1.f;
effect->Mat.Lighting=true;
@ -1388,7 +1389,7 @@ void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect *
readEffect(reader,effect);
else
if (newParamName == reader->getNodeName())
readParameter(reader);
readParameter(reader, effect->Parameters);
else
// these are the actual materials inside technique
if (constantNode == reader->getNodeName() ||
@ -1538,10 +1539,10 @@ void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect *
effect->Mat.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA;
effect->Mat.ZWriteEnable = false;
}
effect->Mat.setFlag(video::EMF_TEXTURE_WRAP, !Parameters.getAttributeAsBool("wrap_s"));
effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, Parameters.getAttributeAsBool("bilinear"));
effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, Parameters.getAttributeAsBool("trilinear"));
effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, Parameters.getAttributeAsBool("anisotropic"));
effect->Mat.setFlag(video::EMF_TEXTURE_WRAP, !effect->Parameters->getAttributeAsBool("wrap_s"));
effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, effect->Parameters->getAttributeAsBool("bilinear"));
effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, effect->Parameters->getAttributeAsBool("trilinear"));
effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, effect->Parameters->getAttributeAsBool("anisotropic"));
}
@ -1569,7 +1570,7 @@ const SColladaMaterial* CColladaFileLoader::findMaterial(const core::stringc& ma
// found the effect, instantiate by copying into the material
Materials[mat].Mat = Effects[effect].Mat;
if (Effects[effect].Textures.size())
Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0]));
Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0], &(Effects[effect])));
Materials[mat].Transparency = Effects[effect].Transparency;
// and indicate the material is instantiated by removing the effect ref
Materials[mat].InstanceEffectId = "";
@ -2494,7 +2495,7 @@ void CColladaFileLoader::readColladaInputs(io::IXMLReaderUTF8* reader, const cor
} // end while reader->read();
}
//! parses all collada parameters inside an element and stores them in Parameters
//! parses all collada parameters inside an element and stores them in ColladaParameters
void CColladaFileLoader::readColladaParameters(io::IXMLReaderUTF8* reader,
const core::stringc& parentName)
{
@ -2719,6 +2720,8 @@ void CColladaFileLoader::clearData()
Inputs.clear();
// clear all effects
for ( u32 i=0; i<Effects.size(); ++i )
Effects[i].Parameters->drop();
Effects.clear();
// clear all the materials to bind
@ -2751,7 +2754,7 @@ core::stringc CColladaFileLoader::readId(io::IXMLReaderUTF8* reader)
//! create an Irrlicht texture from the reference
video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri)
video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri, SColladaEffect * effect)
{
#ifdef COLLADA_READER_DEBUG
os::Printer::log("COLLADA searching texture", uri);
@ -2792,9 +2795,9 @@ video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri)
break;
}
}
if (Parameters.getAttributeType(uri.c_str())==io::EAT_STRING)
if (effect && effect->Parameters->getAttributeType(uri.c_str())==io::EAT_STRING)
{
uri = Parameters.getAttributeAsString(uri.c_str());
uri = effect->Parameters->getAttributeAsString(uri.c_str());
#ifdef COLLADA_READER_DEBUG
os::Printer::log("COLLADA now searching texture", uri.c_str());
#endif
@ -2807,12 +2810,15 @@ video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri)
//! read a parameter and value
void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters)
{
#ifdef COLLADA_READER_DEBUG
os::Printer::log("COLLADA reading parameter");
#endif
if ( !parameters )
return;
const core::stringc name = reader->getAttributeValue("sid");
if (!reader->isEmptyElement())
{
@ -2823,7 +2829,7 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
if (floatNodeName == reader->getNodeName())
{
const f32 f = readFloatNode(reader);
Parameters.addFloat(name.c_str(), f);
parameters->addFloat(name.c_str(), f);
}
else
if (float2NodeName == reader->getNodeName())
@ -2837,14 +2843,14 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
{
f32 f[3];
readFloatsInsideElement(reader, f, 3);
Parameters.addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2]));
parameters->addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2]));
}
else
if ((initFromName == reader->getNodeName()) ||
(sourceSectionName == reader->getNodeName()))
{
reader->read();
Parameters.addString(name.c_str(), reader->getNodeData());
parameters->addString(name.c_str(), reader->getNodeData());
}
else
if (wrapsName == reader->getNodeName())
@ -2852,7 +2858,7 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
reader->read();
const core::stringc val = reader->getNodeData();
if (val == "WRAP")
Parameters.addBool("wrap_s", true);
parameters->addBool("wrap_s", true);
}
else
if (wraptName == reader->getNodeName())
@ -2860,7 +2866,7 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
reader->read();
const core::stringc val = reader->getNodeData();
if (val == "WRAP")
Parameters.addBool("wrap_t", true);
parameters->addBool("wrap_t", true);
}
else
if (minfilterName == reader->getNodeName())
@ -2868,10 +2874,10 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
reader->read();
const core::stringc val = reader->getNodeData();
if (val == "LINEAR_MIPMAP_LINEAR")
Parameters.addBool("trilinear", true);
parameters->addBool("trilinear", true);
else
if (val == "LINEAR_MIPMAP_NEAREST")
Parameters.addBool("bilinear", true);
parameters->addBool("bilinear", true);
}
else
if (magfilterName == reader->getNodeName())
@ -2880,14 +2886,14 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader)
const core::stringc val = reader->getNodeData();
if (val != "LINEAR")
{
Parameters.addBool("bilinear", false);
Parameters.addBool("trilinear", false);
parameters->addBool("bilinear", false);
parameters->addBool("trilinear", false);
}
}
else
if (mipfilterName == reader->getNodeName())
{
Parameters.addBool("anisotropic", true);
parameters->addBool("anisotropic", true);
}
}
else

View File

@ -135,6 +135,8 @@ struct SColladaEffect
f32 Transparency;
core::array<core::stringc> Textures;
video::SMaterial Mat;
// TODO: Parameters looks somewhat lazy workaround, I think we should really read all parameters correct.
io::IAttributes * Parameters;
inline bool operator< (const SColladaEffect & other) const
{
@ -298,7 +300,7 @@ private:
//! clears all loaded data
void clearData();
//! parses all collada parameters inside an element and stores them in Parameters
//! parses all collada parameters inside an element and stores them in ColladaParameters
void readColladaParameters(io::IXMLReaderUTF8* reader, const core::stringc& parentName);
//! returns a collada parameter or none if not found
@ -332,10 +334,10 @@ private:
void readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id);
//! create an Irrlicht texture from the SColladaImage
video::ITexture* getTextureFromImage(core::stringc uri);
video::ITexture* getTextureFromImage(core::stringc uri, SColladaEffect * effect);
//! read a parameter and value
void readParameter(io::IXMLReaderUTF8* reader);
void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters);
scene::ISceneManager* SceneManager;
io::IFileSystem* FileSystem;
@ -360,7 +362,6 @@ private:
core::map<core::stringc,u32> MaterialsToBind;
//! Array of buffers for each material binding
core::array< core::array<irr::scene::IMeshBuffer*> > MeshesToBind;
io::CAttributes Parameters;
bool CreateInstances;
};

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,9 @@
#ifndef __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__
#define __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__
#include "IMeshWriter.h"
#include "IColladaMeshWriter.h"
#include "S3DVertex.h"
#include "irrMap.h"
#include "IVideoDriver.h"
namespace irr
@ -19,19 +20,59 @@ namespace io
namespace scene
{
//! Callback interface for properties which can be used to influence collada writing
// (Implementer note: keep namespace labels here to make it easier for users copying this one)
class CColladaMeshWriterProperties : public virtual IColladaMeshWriterProperties
{
public:
//! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
virtual irr::scene::E_COLLADA_TECHNIQUE_FX getTechniqueFx(const irr::video::SMaterial& material) const;
//! Which texture index should be used when writing the texture of the given sampler color.
virtual irr::s32 getTextureIdx(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const;
//! Return which color from Irrlicht should be used for the color requested by collada
virtual irr::scene::E_COLLADA_IRR_COLOR getColorMapping(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const;
//! Return custom colors for certain color types requested by collada.
virtual irr::video::SColor getCustomColor(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const;
//! Return the settings for transparence
virtual irr::scene::E_COLLADA_TRANSPARENT_FX getTransparentFx(const irr::video::SMaterial& material) const;
//! Transparency value for that material.
virtual irr::f32 getTransparency(const irr::video::SMaterial& material) const;
//! Reflectivity value for that material
virtual irr::f32 getReflectivity(const irr::video::SMaterial& material) const;
//! Return index of refraction for that material
virtual irr::f32 getIndexOfRefraction(const irr::video::SMaterial& material) const;
//! Should node be used in scene export? By default all visible nodes are exported.
virtual bool isExportable(const irr::scene::ISceneNode * node) const;
//! Return the mesh for the given nod. If it has no mesh or shouldn't export it's mesh return 0.
virtual irr::scene::IMesh* getMesh(irr::scene::ISceneNode * node);
};
//! class to write meshes, implementing a COLLADA (.dae, .xml) writer
/** This writer implementation has been originally developed for irrEdit and then
merged out to the Irrlicht Engine */
class CColladaMeshWriter : public IMeshWriter
class CColladaMeshWriter : public IColladaMeshWriter
{
public:
CColladaMeshWriter(video::IVideoDriver* driver, io::IFileSystem* fs);
CColladaMeshWriter(ISceneManager * smgr, video::IVideoDriver* driver, io::IFileSystem* fs);
virtual ~CColladaMeshWriter();
//! Returns the type of the mesh writer
virtual EMESH_WRITER_TYPE getType() const;
//! writes a scene starting with the given node
virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root);
//! writes a mesh
virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE);
@ -40,9 +81,48 @@ protected:
bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const;
inline irr::core::stringw toString(const irr::core::vector3df& vec) const;
inline irr::core::stringw uvToString(const irr::core::vector2df& vec) const;
inline irr::core::stringw toString(const irr::core::vector2df& vec) const;
inline irr::core::stringw toString(const irr::video::SColorf& colorf) const;
inline void writeColorAttribute(wchar_t * parentTag, io::IAttributes* attributes, s32 attridx);
inline irr::core::stringw toString(const irr::video::SColorf& colorf, bool writeAlpha=true) const;
inline irr::core::stringw toString(const irr::video::ECOLOR_FORMAT format) const;
inline irr::core::stringw toString(const irr::video::E_TEXTURE_CLAMP clamp) const;
inline irr::core::stringw toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const;
inline irr::core::stringw toRef(const irr::core::stringw& source) const;
irr::core::stringw uniqueNameForMesh(const scene::IMesh* mesh) const;
irr::core::stringw uniqueNameForLight(const scene::ISceneNode* lightNode) const;
irr::core::stringw uniqueNameForNode(const scene::ISceneNode* node) const;
irr::core::stringw minTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringw magTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringw pathToNCName(const irr::io::path& path) const;
irr::core::stringw pathToURI(const irr::io::path& path) const;
inline bool isXmlNameStartChar(wchar_t c) const;
inline bool isXmlNameChar(wchar_t c) const;
s32 getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs);
video::SColor getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType);
void writeAsset();
void makeMeshNames(irr::scene::ISceneNode * node);
void writeNodeMaterials(irr::scene::ISceneNode * node);
void writeNodeEffects(irr::scene::ISceneNode * node);
void writeNodeLights(irr::scene::ISceneNode * node);
void writeNodeGeometries(irr::scene::ISceneNode * node);
void writeSceneNode(irr::scene::ISceneNode * node);
void writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material);
void writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeLightInstance(const irr::core::stringw& lightName);
void writeLibraryImages();
void writeColorFx(const irr::core::stringw& meshname, const video::SMaterial & material, const wchar_t * colorname, E_COLLADA_COLOR_SAMPLER cs, const wchar_t* attr1Name=0, const wchar_t* attr1Value=0);
void writeAmbientLightElement(const video::SColorf & col);
void writeColorElement(const video::SColor & col, bool writeAlpha=true);
void writeColorElement(const video::SColorf & col, bool writeAlpha=true);
void writeTextureSampler(const irr::core::stringw& meshname, s32 textureIdx);
void writeFxElement(const irr::core::stringw& meshname, const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx);
void writeFloatElement(irr::f32 value);
void writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle);
void writeScaleElement(const irr::core::vector3df& scale);
void writeTranslateElement(const irr::core::vector3df& translate);
struct SComponentGlobalStartPos
{
@ -68,6 +148,30 @@ protected:
io::IFileSystem* FileSystem;
video::IVideoDriver* VideoDriver;
io::IXMLWriter* Writer;
core::array<video::ITexture*> LibraryImages;
io::path Directory;
struct ColladaMesh
{
ColladaMesh() : MaterialWritten(false), EffectWritten(false), GeometryWritten(false)
{
}
irr::core::stringw Name;
bool MaterialWritten;
bool EffectWritten;
bool GeometryWritten;
};
typedef core::map<IMesh*, ColladaMesh>::Node MeshNode;
core::map<IMesh*, ColladaMesh> Meshes;
struct ColladaLight
{
ColladaLight() {}
irr::core::stringw Name;
};
typedef core::map<ISceneNode*, ColladaLight>::Node LightNode;
core::map<ISceneNode*, ColladaLight> LightNodes;
};
@ -76,3 +180,4 @@ protected:
#endif

View File

@ -1053,7 +1053,7 @@ bool CD3D9Driver::updateVertexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer)
}
DWORD flags = D3DUSAGE_WRITEONLY; // SIO2: Default to D3DUSAGE_WRITEONLY
if(hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
flags |= D3DUSAGE_DYNAMIC;
if (FAILED(pID3DDevice->CreateVertexBuffer(bufSize, flags, FVF, D3DPOOL_DEFAULT, &hwBuffer->vertexBuffer, NULL)))
@ -1061,7 +1061,7 @@ bool CD3D9Driver::updateVertexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer)
hwBuffer->vertexBufferSize = bufSize;
flags = 0; // SIO2: Reset flags before Lock
if(hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
flags = D3DLOCK_DISCARD;
void* lockedBuffer = 0;
@ -1187,7 +1187,9 @@ bool CD3D9Driver::updateHardwareBuffer(SHWBufferLink *hwBuffer)
//! Create hardware buffer from meshbuffer
CD3D9Driver::SHWBufferLink *CD3D9Driver::createHardwareBuffer(const scene::IMeshBuffer* mb)
{
if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
// Looks like d3d does not support only partial buffering, so refuse
// in any case of NEVER
if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER || mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
return 0;
SHWBufferLink_d3d9 *hwBuffer=new SHWBufferLink_d3d9(mb);
@ -1252,12 +1254,20 @@ void CD3D9Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
const E_VERTEX_TYPE vType = mb->getVertexType();
const u32 stride = getVertexPitchFromType(vType);
const void* vPtr = mb->getVertices();
const void* iPtr = mb->getIndices();
if (HWBuffer->vertexBuffer)
{
pID3DDevice->SetStreamSource(0, HWBuffer->vertexBuffer, 0, stride);
vPtr=0;
}
if (HWBuffer->indexBuffer)
{
pID3DDevice->SetIndices(HWBuffer->indexBuffer);
iPtr=0;
}
drawVertexPrimitiveList(0, mb->getVertexCount(), 0, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType());
drawVertexPrimitiveList(vPtr, mb->getVertexCount(), iPtr, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType());
if (HWBuffer->vertexBuffer)
pID3DDevice->SetStreamSource(0, 0, 0, 0);
@ -2563,9 +2573,15 @@ void CD3D9Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChan
pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
}
pID3DDevice->SetTransform(D3DTS_WORLD, &UnitMatrixD3D9);
core::matrix4 m;
// this fixes some problems with pixel exact rendering, but also breaks nice texturing
// moreover, it would have to be tested in each call, as the texture flag can change each time
// if (!texture)
// m.setTranslation(core::vector3df(0.5f,0.5f,0));
pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)m.pointer()));
// adjust the view such that pixel center aligns with texels
// Otherwise, subpixel artifacts will occur
m.setTranslation(core::vector3df(-0.5f,-0.5f,0));
pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)m.pointer()));
@ -2574,6 +2590,7 @@ void CD3D9Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChan
m.setTranslation(core::vector3df(-1,1,0));
pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)m.pointer()));
// 2d elements are clipped in software
pID3DDevice->SetRenderState(D3DRS_CLIPPING, FALSE);
Transformation3DChanged = false;

View File

@ -44,6 +44,25 @@ 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;
}
} // end namespace scene
} // end namespace irr

View File

@ -36,6 +36,10 @@ namespace scene
//! 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:
core::matrix4 RelativeTransformationMatrix;

View File

@ -700,36 +700,66 @@ io::path& CFileSystem::flattenFilename(io::path& directory, const io::path& root
//! Get the relative filename, relative to the given directory
path CFileSystem::getRelativeFilename(const path& filename, const path& directory) const
{
io::path path1, file, ext;
core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext);
io::path path2(getAbsolutePath(directory));
core::list<io::path> list1, list2;
path1.split(list1, _IRR_TEXT("/\\"), 2);
path2.split(list2, _IRR_TEXT("/\\"), 2);
u32 i=0;
core::list<io::path>::ConstIterator it1,it2;
it1=list1.begin();
it2=list2.begin();
for (; i<list1.size() && i<list2.size() && (*it1==*it2); ++i)
{
++it1;
++it2;
}
path1=_IRR_TEXT("");
for (; i<list2.size(); ++i)
path1 += _IRR_TEXT("../");
while (it1 != list1.end())
{
path1 += *it1++;
path1 += _IRR_TEXT('/');
}
path1 += file;
if (ext.size())
{
path1 += _IRR_TEXT('.');
path1 += ext;
}
return path1;
if ( filename.empty() || directory.empty() )
return filename;
io::path path1, file, ext;
core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext);
io::path path2(getAbsolutePath(directory));
core::list<io::path> list1, list2;
path1.split(list1, _IRR_TEXT("/\\"), 2);
path2.split(list2, _IRR_TEXT("/\\"), 2);
u32 i=0;
core::list<io::path>::ConstIterator it1,it2;
it1=list1.begin();
it2=list2.begin();
#if defined (_IRR_WINDOWS_API_)
fschar_t partition1 = 0, partition2 = 0;
io::path prefix1, prefix2;
if ( it1 != list1.end() )
prefix1 = *it1;
if ( it2 != list2.end() )
prefix2 = *it2;
if ( prefix1.size() > 1 && prefix1[1] == _IRR_TEXT(':') )
partition1 = core::locale_lower(prefix1[0]);
if ( prefix2.size() > 1 && prefix2[1] == _IRR_TEXT(':') )
partition2 = core::locale_lower(prefix2[0]);
// must have the same prefix or we can't resolve it to a relative filename
if ( partition1 != partition2 )
{
return filename;
}
#endif
for (; i<list1.size() && i<list2.size()
#if defined (_IRR_WINDOWS_API_)
&& (io::path(*it1).make_lower()==io::path(*it2).make_lower())
#else
&& (*it1==*it2)
#endif
; ++i)
{
++it1;
++it2;
}
path1=_IRR_TEXT("");
for (; i<list2.size(); ++i)
path1 += _IRR_TEXT("../");
while (it1 != list1.end())
{
path1 += *it1++;
path1 += _IRR_TEXT('/');
}
path1 += file;
if (ext.size())
{
path1 += _IRR_TEXT('.');
path1 += ext;
}
return path1;
}

View File

@ -287,9 +287,7 @@ void CGUIButton::draw()
if (Text.size())
{
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont(EGDF_BUTTON);
IGUIFont* font = getActiveFont();
core::rect<s32> rect = AbsoluteRect;
if (Pressed)
@ -320,6 +318,22 @@ void CGUIButton::setOverrideFont(IGUIFont* font)
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();
return 0;
}
//! Sets an image which should be displayed on the button when it is in normal state.
void CGUIButton::setImage(video::ITexture* image)

View File

@ -37,6 +37,12 @@ namespace gui
//! 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);

View File

@ -24,7 +24,7 @@ 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), HasFocus(false)
Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false)
{
#ifdef _DEBUG
setDebugName("CGUIComboBox");
@ -81,6 +81,26 @@ void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT ve
}
//! 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
{
@ -408,10 +428,10 @@ void CGUIComboBox::openCloseMenu()
Parent->bringToFront(this);
IGUISkin* skin = Environment->getSkin();
s32 h = Items.size();
u32 h = Items.size();
if (h > 5)
h = 5;
if (h > getMaxSelectionRows())
h = getMaxSelectionRows();
if (h == 0)
h = 1;
@ -450,6 +470,7 @@ void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadW
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
out->addInt("MaxSelectionRows", (s32)MaxSelectionRows );
out->addInt ("Selected", Selected );
out->addInt ("ItemCount", Items.size());
@ -470,6 +491,7 @@ void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRead
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
setMaxSelectionRows( (u32)(in->getAttributeAsInt("MaxSelectionRows")) );
// clear the list
clear();

View File

@ -62,6 +62,12 @@ namespace gui
//! 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);
@ -97,6 +103,7 @@ namespace gui
s32 Selected;
EGUI_ALIGNMENT HAlign, VAlign;
u32 MaxSelectionRows;
bool HasFocus;
};

View File

@ -32,7 +32,7 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect<s32>& rectangle)
: IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false),
Border(border), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0),
Border(border), Background(true), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0),
OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0),
Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0),
WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false),
@ -55,17 +55,7 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border,
setTabStop(true);
setTabOrder(-1);
IGUISkin *skin = 0;
if (Environment)
skin = Environment->getSkin();
if (Border && skin)
{
FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
}
calculateFrameRect();
breakText();
calculateScrollPos();
@ -100,6 +90,22 @@ void CGUIEditBox::setOverrideFont(IGUIFont* font)
breakText();
}
//! Gets the override font (if any)
IGUIFont * CGUIEditBox::getOverrideFont() const
{
return OverrideFont;
}
//! Get the font which is used right now for drawing
IGUIFont* CGUIEditBox::getActiveFont() const
{
if ( OverrideFont )
return OverrideFont;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getFont();
return 0;
}
//! Sets another color for the text.
void CGUIEditBox::setOverrideColor(video::SColor color)
@ -121,6 +127,11 @@ void CGUIEditBox::setDrawBorder(bool border)
Border = border;
}
//! Sets whether to draw the background
void CGUIEditBox::setDrawBackground(bool draw)
{
Background = draw;
}
//! Sets if the text should use the overide color or the color in the gui skin.
void CGUIEditBox::enableOverrideColor(bool enable)
@ -148,7 +159,9 @@ void CGUIEditBox::updateAbsolutePosition()
IGUIElement::updateAbsolutePosition();
if ( oldAbsoluteRect != AbsoluteRect )
{
calculateFrameRect();
breakText();
calculateScrollPos();
}
}
@ -507,7 +520,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
{
s32 cp = CursorPos - BrokenTextPositions[lineNo];
if ((s32)BrokenText[lineNo-1].size() < cp)
CursorPos = BrokenTextPositions[lineNo-1] + (s32)BrokenText[lineNo-1].size()-1;
CursorPos = BrokenTextPositions[lineNo-1] + core::max_((u32)1, BrokenText[lineNo-1].size())-1;
else
CursorPos = BrokenTextPositions[lineNo-1] + cp;
}
@ -538,7 +551,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
{
s32 cp = CursorPos - BrokenTextPositions[lineNo];
if ((s32)BrokenText[lineNo+1].size() < cp)
CursorPos = BrokenTextPositions[lineNo+1] + BrokenText[lineNo+1].size()-1;
CursorPos = BrokenTextPositions[lineNo+1] + core::max_((u32)1, BrokenText[lineNo+1].size())-1;
else
CursorPos = BrokenTextPositions[lineNo+1] + cp;
}
@ -702,31 +715,29 @@ void CGUIEditBox::draw()
if (!skin)
return;
FrameRect = AbsoluteRect;
EGUI_DEFAULT_COLOR bgCol = EGDC_GRAY_EDITABLE;
if ( isEnabled() )
bgCol = focus ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE;
// draw the border
if (!Border && Background)
{
skin->draw2DRectangle(this, skin->getColor(bgCol), AbsoluteRect, &AbsoluteClippingRect);
}
if (Border)
{
EGUI_DEFAULT_COLOR col = EGDC_GRAY_EDITABLE;
if ( isEnabled() )
col = focus ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE;
skin->draw3DSunkenPane(this, skin->getColor(col),
false, true, FrameRect, &AbsoluteClippingRect);
// draw the border
skin->draw3DSunkenPane(this, skin->getColor(bgCol), false, Background, AbsoluteRect, &AbsoluteClippingRect);
FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
calculateFrameRect();
}
core::rect<s32> localClipRect = FrameRect;
localClipRect.clipAgainst(AbsoluteClippingRect);
// draw the text
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont();
IGUIFont* font = getActiveFont();
s32 cursorLine = 0;
s32 charcursorpos = 0;
@ -1024,10 +1035,7 @@ bool CGUIEditBox::processMouse(const SEvent& event)
s32 CGUIEditBox::getCursorPos(s32 x, s32 y)
{
IGUIFont* font = OverrideFont;
IGUISkin* skin = Environment->getSkin();
if (!OverrideFont)
font = skin->getFont();
IGUIFont* font = getActiveFont();
const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
@ -1056,7 +1064,10 @@ s32 CGUIEditBox::getCursorPos(s32 x, s32 y)
if (x < CurrentTextRect.UpperLeftCorner.X)
x = CurrentTextRect.UpperLeftCorner.X;
s32 idx = txtLine ? font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X) : -1;
if ( !txtLine )
return 0;
s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
// click was on or left of the line
if (idx != -1)
@ -1070,18 +1081,13 @@ s32 CGUIEditBox::getCursorPos(s32 x, s32 y)
//! Breaks the single text line.
void CGUIEditBox::breakText()
{
IGUISkin* skin = Environment->getSkin();
if ((!WordWrap && !MultiLine) || !skin)
if ((!WordWrap && !MultiLine))
return;
BrokenText.clear(); // need to reallocate :/
BrokenTextPositions.set_used(0);
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont();
IGUIFont* font = getActiveFont();
if (!font)
return;
@ -1104,7 +1110,7 @@ void CGUIEditBox::breakText()
if (c == L'\r') // Mac or Windows breaks
{
lineBreak = true;
c = ' ';
c = 0;
if (Text[i+1] == L'\n') // Windows breaks
{
Text.erase(i+1);
@ -1114,7 +1120,7 @@ void CGUIEditBox::breakText()
else if (c == L'\n') // Unix breaks
{
lineBreak = true;
c = ' ';
c = 0;
}
// don't break if we're not a multi-line edit box
@ -1123,35 +1129,35 @@ void CGUIEditBox::breakText()
if (c == L' ' || c == 0 || i == (size-1))
{
if (word.size())
// here comes the next whitespace, look if
// we can break the last word to the next line
// We also break whitespace, otherwise cursor would vanish beside the right border.
s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
s32 worldlgth = font->getDimension(word.c_str()).Width;
if (WordWrap && length + worldlgth + whitelgth > elWidth && line.size() > 0)
{
// here comes the next whitespace, look if
// we can break the last word to the next line.
s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
s32 worldlgth = font->getDimension(word.c_str()).Width;
if (WordWrap && length + worldlgth + whitelgth > elWidth)
{
// break to next line
length = worldlgth;
BrokenText.push_back(line);
BrokenTextPositions.push_back(lastLineStart);
lastLineStart = i - (s32)word.size();
line = word;
}
else
{
// add word to line
line += whitespace;
line += word;
length += whitelgth + worldlgth;
}
word = L"";
whitespace = L"";
// break to next line
length = worldlgth;
BrokenText.push_back(line);
BrokenTextPositions.push_back(lastLineStart);
lastLineStart = i - (s32)word.size();
line = word;
}
else
{
// add word to line
line += whitespace;
line += word;
length += whitelgth + worldlgth;
}
whitespace += c;
word = L"";
whitespace = L"";
if ( c )
whitespace += c;
// compute line break
if (lineBreak)
@ -1183,17 +1189,15 @@ void CGUIEditBox::breakText()
void CGUIEditBox::setTextRect(s32 line)
{
core::dimension2du d;
IGUISkin* skin = Environment->getSkin();
if (!skin)
if ( line < 0 )
return;
IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
IGUIFont* font = getActiveFont();
if (!font)
return;
core::dimension2du d;
// get text dimension
const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
if (WordWrap || MultiLine)
@ -1321,16 +1325,15 @@ void CGUIEditBox::calculateScrollPos()
// calculate horizontal scroll position
s32 cursLine = getLineFromPos(CursorPos);
if ( cursLine < 0 )
return;
setTextRect(cursLine);
// don't do horizontal scrolling when wordwrap is enabled.
if (!WordWrap)
{
// get cursor position
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
IGUIFont* font = getActiveFont();
if (!font)
return;
@ -1364,6 +1367,21 @@ void CGUIEditBox::calculateScrollPos()
// todo: adjust scrollbar
}
void CGUIEditBox::calculateFrameRect()
{
FrameRect = AbsoluteRect;
IGUISkin *skin = 0;
if (Environment)
skin = Environment->getSkin();
if (Border && skin)
{
FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
}
}
//! set text markers
void CGUIEditBox::setTextMarkers(s32 begin, s32 end)
{
@ -1395,6 +1413,8 @@ void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWr
{
// IGUIEditBox::serializeAttributes(out,options);
out->addBool ("Border", Border);
out->addBool ("Background", Background);
out->addBool ("OverrideColorEnabled",OverrideColorEnabled );
out->addColor ("OverrideColor", OverrideColor);
// out->addFont("OverrideFont",OverrideFont);
@ -1418,6 +1438,8 @@ void CGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadW
{
IGUIEditBox::deserializeAttributes(in,options);
setDrawBorder( in->getAttributeAsBool("Border") );
setDrawBackground( in->getAttributeAsBool("Background") );
setOverrideColor(in->getAttributeAsColor("OverrideColor"));
enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
setMax(in->getAttributeAsInt("MaxChars"));

View File

@ -30,6 +30,15 @@ namespace gui
//! 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);
@ -44,6 +53,9 @@ namespace gui
/** \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);
@ -124,6 +136,8 @@ namespace gui
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
@ -135,6 +149,7 @@ namespace gui
bool MouseMarking;
bool Border;
bool Background;
bool OverrideColorEnabled;
s32 MarkBegin;
s32 MarkEnd;

View File

@ -405,7 +405,7 @@ bool CGUIListBox::OnEvent(const SEvent& event)
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
ScrollBar->setPos(ScrollBar->getPos() + (s32)event.MouseInput.Wheel*-ItemHeight/2);
ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2);
return true;
case EMIE_LMOUSE_PRESSED_DOWN:

View File

@ -33,7 +33,7 @@ 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
|| (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
;
}
@ -86,6 +86,13 @@ bool CGUIModalScreen::OnEvent(const SEvent& 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() )

View File

@ -146,7 +146,7 @@ bool CGUIScrollBar::OnEvent(const SEvent& event)
// thanks to tommi by tommi for another bugfix
// everybody needs a little thanking. hallo niko!;-)
setPos( getPos() +
( (s32)event.MouseInput.Wheel * SmallStep * (Horizontal ? 1 : -1 ) )
( (event.MouseInput.Wheel < 0 ? -1 : 1) * SmallStep * (Horizontal ? 1 : -1 ) )
);
SEvent newEvent;

View File

@ -47,9 +47,9 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)
Colors[EGDC_ICON] = video::SColor(200,255,255,255);
Colors[EGDC_ICON_HIGH_LIGHT] = video::SColor(200,8,36,107);
Colors[EGDC_GRAY_WINDOW_SYMBOL] = video::SColor(240,100,100,100);
Colors[EGDC_EDITABLE] = video::SColor(101,255,255,255);
Colors[EGDC_GRAY_EDITABLE] = video::SColor(101,200,200,200);
Colors[EGDC_FOCUSED_EDITABLE] = video::SColor(101,230,230,255);
Colors[EGDC_EDITABLE] = video::SColor(255,255,255,255);
Colors[EGDC_GRAY_EDITABLE] = video::SColor(255,120,120,120);
Colors[EGDC_FOCUSED_EDITABLE] = video::SColor(255,240,240,255);
Sizes[EGDS_SCROLLBAR_SIZE] = 14;
@ -414,49 +414,74 @@ void CGUISkin::draw3DSunkenPane(IGUIElement* element, video::SColor bgcolor,
core::rect<s32> rect = r;
if (fillBackGround)
Driver->draw2DRectangle(bgcolor, rect, clip);
if (flat)
{
// draw flat sunken pane
if (fillBackGround)
Driver->draw2DRectangle(bgcolor, rect, clip);
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip);
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top
++rect.UpperLeftCorner.Y;
rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip);
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left
rect = r;
++rect.UpperLeftCorner.Y;
rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right
rect = r;
++rect.UpperLeftCorner.X;
rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;
rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
--rect.LowerRightCorner.X;
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom
}
else
{
// draw deep sunken pane
if (fillBackGround)
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
rect.LowerRightCorner.X -= 1;
rect.LowerRightCorner.Y -= 1;
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip);
rect.UpperLeftCorner.X += 1;
rect.UpperLeftCorner.Y += 1;
Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip);
rect.LowerRightCorner.X -= 1;
rect.LowerRightCorner.Y -= 1;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top
++rect.UpperLeftCorner.X;
++rect.UpperLeftCorner.Y;
--rect.LowerRightCorner.X;
++rect.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip);
rect.UpperLeftCorner.X += 1;
rect.UpperLeftCorner.Y += 1;
Driver->draw2DRectangle(bgcolor, rect, clip);
rect.UpperLeftCorner.X = r.UpperLeftCorner.X;
rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y+1;
rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;
rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left
++rect.UpperLeftCorner.X;
++rect.UpperLeftCorner.Y;
++rect.LowerRightCorner.X;
--rect.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip);
rect = r;
rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;
++rect.UpperLeftCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right
--rect.UpperLeftCorner.X;
++rect.UpperLeftCorner.Y;
--rect.LowerRightCorner.X;
--rect.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip);
rect = r;
++rect.UpperLeftCorner.X;
rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;
--rect.LowerRightCorner.X;
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom
++rect.UpperLeftCorner.X;
--rect.UpperLeftCorner.Y;
--rect.LowerRightCorner.X;
--rect.LowerRightCorner.Y;
Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip);
}
}

View File

@ -133,6 +133,14 @@ void CGUISpinBox::setRange(f32 min, f32 max)
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();
}
@ -173,6 +181,7 @@ void CGUISpinBox::setDecimalPlaces(s32 places)
FormatString += places;
FormatString += "f";
}
setRange( RangeMin, RangeMax );
setValue(getValue());
}
@ -189,7 +198,7 @@ bool CGUISpinBox::OnEvent(const SEvent& event)
{
case EMIE_MOUSE_WHEEL:
{
f32 val = getValue() + (StepSize * event.MouseInput.Wheel);
f32 val = getValue() + (StepSize * (event.MouseInput.Wheel < 0 ? -1.f : 1.f));
setValue(val);
changeEvent = true;
}

View File

@ -72,6 +72,7 @@ namespace gui
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);

View File

@ -82,9 +82,7 @@ void CGUIStaticText::draw()
// draw the text
if (Text.size())
{
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont();
IGUIFont* font = getActiveFont();
if (font)
{
@ -162,12 +160,22 @@ void CGUIStaticText::setOverrideFont(IGUIFont* font)
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)
@ -204,7 +212,7 @@ void CGUIStaticText::setTextRestrainedInside(bool restrainTextInside)
{
RestrainTextInside = restrainTextInside;
}
bool CGUIStaticText::isTextRestrainedInside() const
{
@ -275,36 +283,34 @@ bool CGUIStaticText::isRightToLeft() const
//! Breaks the single text line.
void CGUIStaticText::breakText()
{
IGUISkin* skin = Environment->getSkin();
if (!WordWrap || !skin)
if (!WordWrap)
return;
BrokenText.clear();
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont();
IGUISkin* skin = Environment->getSkin();
IGUIFont* font = getActiveFont();
if (!font)
return;
LastBreakFont = font;
core::stringw line;
core::stringw word;
core::stringw whitespace;
s32 size = Text.size();
s32 length = 0;
s32 elWidth = RelativeRect.getWidth();
if (Border)
elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
wchar_t c;
// We have to deal with right-to-left and left-to-right differently
// However, most parts of the following code is the same, it's just
// some order and boundaries which change.
if (!RightToLeft)
{
// regular (left-to-right)
core::stringw line;
core::stringw word;
core::stringw whitespace;
s32 size = Text.size();
s32 length = 0;
s32 elWidth = RelativeRect.getWidth() - 6;
wchar_t c;
for (s32 i=0; i<size; ++i)
{
c = Text[i];
@ -326,7 +332,14 @@ void CGUIStaticText::breakText()
c = '\0';
}
if (c==L' ' || c==0 || i==(size-1))
bool isWhitespace = (c == L' ' || c == 0);
if ( !isWhitespace )
{
// part of a word
word += c;
}
if ( isWhitespace || i == (size-1))
{
if (word.size())
{
@ -334,7 +347,7 @@ void CGUIStaticText::breakText()
// we must break the last word to the next line.
const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
const s32 wordlgth = font->getDimension(word.c_str()).Width;
if (wordlgth > elWidth)
{
// This word is too long to fit in the available space, look for
@ -347,7 +360,7 @@ void CGUIStaticText::breakText()
core::stringw second = word.subString(where, word.size() - where);
BrokenText.push_back(line + first + L"-");
const s32 secondLength = font->getDimension(second.c_str()).Width;
length = secondLength;
line = second;
}
@ -380,7 +393,10 @@ void CGUIStaticText::breakText()
whitespace = L"";
}
whitespace += c;
if ( isWhitespace )
{
whitespace += c;
}
// compute line break
if (lineBreak)
@ -394,11 +410,6 @@ void CGUIStaticText::breakText()
length = 0;
}
}
else
{
// yippee this is a word..
word += c;
}
}
line += whitespace;
@ -408,14 +419,6 @@ void CGUIStaticText::breakText()
else
{
// right-to-left
core::stringw line;
core::stringw word;
core::stringw whitespace;
s32 size = Text.size();
s32 length = 0;
s32 elWidth = RelativeRect.getWidth() - 6;
wchar_t c;
for (s32 i=size; i>=0; --i)
{
c = Text[i];
@ -512,15 +515,7 @@ void CGUIStaticText::updateAbsolutePosition()
//! Returns the height of the text in pixels when it is drawn.
s32 CGUIStaticText::getTextHeight() const
{
IGUISkin* skin = Environment->getSkin();
if (!skin)
return 0;
IGUIFont* font = OverrideFont;
if (!OverrideFont)
font = skin->getFont();
IGUIFont* font = getActiveFont();
if (!font)
return 0;
@ -535,15 +530,7 @@ s32 CGUIStaticText::getTextHeight() const
s32 CGUIStaticText::getTextWidth() const
{
IGUIFont * font = OverrideFont;
if(!OverrideFont)
{
IGUISkin * skin = Environment->getSkin();
if(skin)
font = skin->getFont();
}
IGUIFont * font = getActiveFont();
if(!font)
return 0;

View File

@ -34,7 +34,10 @@ namespace gui
virtual void setOverrideFont(IGUIFont* font=0);
//! Gets the override font (if any)
virtual IGUIFont * getOverrideFont() const;
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);
@ -63,7 +66,7 @@ namespace gui
//! 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;

View File

@ -583,7 +583,7 @@ bool CGUITable::OnEvent(const SEvent &event)
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (s32)event.MouseInput.Wheel*-10);
VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-10);
return true;
case EMIE_LMOUSE_PRESSED_DOWN:

View File

@ -625,7 +625,7 @@ bool CGUITreeView::OnEvent( const SEvent &event )
{
case EMIE_MOUSE_WHEEL:
if ( ScrollBarV )
ScrollBarV->setPos( ScrollBarV->getPos() + (s32)event.MouseInput.Wheel * -10 );
ScrollBarV->setPos( ScrollBarV->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1) * -10 );
return true;
break;

View File

@ -12,6 +12,7 @@
#include "CTimer.h"
#include "CLogger.h"
#include "irrString.h"
#include "IRandomizer.h"
namespace irr
{
@ -19,7 +20,7 @@ namespace irr
CIrrDeviceStub::CIrrDeviceStub(const SIrrlichtCreationParameters& params)
: IrrlichtDevice(), VideoDriver(0), GUIEnvironment(0), SceneManager(0),
Timer(0), CursorControl(0), UserReceiver(params.EventReceiver), Logger(0), Operator(0),
FileSystem(0), InputReceivingSceneManager(0), CreationParams(params),
Randomizer(0), FileSystem(0), InputReceivingSceneManager(0), CreationParams(params),
Close(false)
{
Timer = new CTimer(params.UsePerformanceTimer);
@ -34,9 +35,10 @@ CIrrDeviceStub::CIrrDeviceStub(const SIrrlichtCreationParameters& params)
Logger = new CLogger(UserReceiver);
os::Printer::Logger = Logger;
}
Logger->setLogLevel( CreationParams.LoggingLevel );
Logger->setLogLevel(CreationParams.LoggingLevel);
os::Printer::Logger = Logger;
Randomizer = createDefaultRandomizer();
FileSystem = io::createFileSystem();
core::stringc s = "Irrlicht Engine version ";
@ -69,9 +71,13 @@ CIrrDeviceStub::~CIrrDeviceStub()
if (Operator)
Operator->drop();
if (Randomizer)
Randomizer->drop();
CursorControl = 0;
Timer->drop();
if (Timer)
Timer->drop();
if (Logger->drop())
os::Printer::Logger = 0;
@ -256,6 +262,61 @@ IOSOperator* CIrrDeviceStub::getOSOperator()
}
//! Provides access to the engine's currently set randomizer.
IRandomizer* CIrrDeviceStub::getRandomizer() const
{
return Randomizer;
}
//! Sets a new randomizer.
void CIrrDeviceStub::setRandomizer(IRandomizer* r)
{
if (r!=Randomizer)
{
if (Randomizer)
Randomizer->drop();
Randomizer=r;
if (Randomizer)
Randomizer->grab();
}
}
namespace
{
struct SDefaultRandomizer : public IRandomizer
{
virtual void reset(s32 value=0x0f0f0f0f)
{
os::Randomizer::reset(value);
}
virtual s32 rand() const
{
return os::Randomizer::rand();
}
virtual f32 frand() const
{
return os::Randomizer::frand();
}
virtual s32 randMax() const
{
return os::Randomizer::randMax();
}
};
}
//! Creates a new default randomizer.
IRandomizer* CIrrDeviceStub::createDefaultRandomizer() const
{
IRandomizer* r = new SDefaultRandomizer();
if (r)
r->reset();
return r;
}
//! Sets the input receiving scene manager.
void CIrrDeviceStub::setInputReceivingSceneManager(scene::ISceneManager* sceneManager)
{

View File

@ -15,6 +15,7 @@ namespace irr
// lots of prototypes:
class ILogger;
class CLogger;
class IRandomizer;
namespace gui
{
@ -97,6 +98,15 @@ namespace irr
//! Returns a pointer to the logger.
virtual ILogger* getLogger();
//! Provides access to the engine's currently set randomizer.
virtual IRandomizer* getRandomizer() const;
//! Sets a new randomizer.
virtual void setRandomizer(IRandomizer* r);
//! Creates a new default randomizer.
virtual IRandomizer* createDefaultRandomizer() const;
//! Returns the operation system opertator object.
virtual IOSOperator* getOSOperator();
@ -148,6 +158,7 @@ namespace irr
IEventReceiver* UserReceiver;
CLogger* Logger;
IOSOperator* Operator;
IRandomizer* Randomizer;
io::IFileSystem* FileSystem;
scene::ISceneManager* InputReceivingSceneManager;

View File

@ -289,6 +289,8 @@ const core::aabbox3d<f32>& COctreeSceneNode::getBoundingBox() const
//! creates the tree
/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic.
Thanks to Auria for fixing major parts of this method. */
bool COctreeSceneNode::createTree(IMesh* mesh)
{
if (!mesh)
@ -301,7 +303,7 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
Mesh = mesh;
u32 beginTime = os::Timer::getRealTime();
const u32 beginTime = os::Timer::getRealTime();
u32 nodeCount = 0;
u32 polyCount = 0;
@ -311,12 +313,28 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
if (mesh->getMeshBufferCount())
{
VertexType = mesh->getMeshBuffer(0)->getVertexType();
// check for "larger" buffer types
VertexType = video::EVT_STANDARD;
u32 meshReserve = 0;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
const IMeshBuffer* b = mesh->getMeshBuffer(i);
if (b->getVertexCount() && b->getIndexCount())
{
++meshReserve;
if (b->getVertexType() == video::EVT_2TCOORDS)
VertexType = video::EVT_2TCOORDS;
else if (b->getVertexType() == video::EVT_TANGENTS)
VertexType = video::EVT_TANGENTS;
}
}
Materials.reallocate(Materials.size()+meshReserve);
switch(VertexType)
{
case video::EVT_STANDARD:
{
StdMeshes.reallocate(StdMeshes.size() + meshReserve);
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
IMeshBuffer* b = mesh->getMeshBuffer(i);
@ -331,8 +349,21 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
u32 v;
nchunk.Vertices.reallocate(b->getVertexCount());
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
switch (b->getVertexType())
{
case video::EVT_STANDARD:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
break;
case video::EVT_2TCOORDS:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
break;
case video::EVT_TANGENTS:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
}
polyCount += b->getIndexCount();
@ -348,22 +379,11 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
break;
case video::EVT_2TCOORDS:
{
IMeshBuffer* b;
u32 meshReserve = 0;
for ( i=0; i < mesh->getMeshBufferCount(); ++i)
{
b = mesh->getMeshBuffer(i);
if (b->getVertexCount() && b->getIndexCount())
{
meshReserve += 1;
}
}
LightMapMeshes.reallocate ( LightMapMeshes.size() + meshReserve );
LightMapMeshes.reallocate(LightMapMeshes.size() + meshReserve);
for ( i=0; i < mesh->getMeshBufferCount(); ++i)
{
b = mesh->getMeshBuffer(i);
IMeshBuffer* b = mesh->getMeshBuffer(i);
if (b->getVertexCount() && b->getIndexCount())
{
@ -382,8 +402,21 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
u32 v;
nchunk.Vertices.reallocate(b->getVertexCount());
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
switch (b->getVertexType())
{
case video::EVT_STANDARD:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
break;
case video::EVT_2TCOORDS:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
break;
case video::EVT_TANGENTS:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
}
polyCount += b->getIndexCount();
nchunk.Indices.reallocate(b->getIndexCount());
@ -398,6 +431,8 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
break;
case video::EVT_TANGENTS:
{
TangentsMeshes.reallocate(TangentsMeshes.size() + meshReserve);
for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
{
IMeshBuffer* b = mesh->getMeshBuffer(i);
@ -411,8 +446,27 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
u32 v;
nchunk.Vertices.reallocate(b->getVertexCount());
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
switch (b->getVertexType())
{
case video::EVT_STANDARD:
for (v=0; v<b->getVertexCount(); ++v)
{
const video::S3DVertex& tmpV = ((video::S3DVertex*)b->getVertices())[v];
nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords));
}
break;
case video::EVT_2TCOORDS:
for (v=0; v<b->getVertexCount(); ++v)
{
const video::S3DVertex2TCoords& tmpV = ((video::S3DVertex2TCoords*)b->getVertices())[v];
nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords));
}
break;
case video::EVT_TANGENTS:
for (v=0; v<b->getVertexCount(); ++v)
nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
break;
}
polyCount += b->getIndexCount();
nchunk.Indices.reallocate(b->getIndexCount());
@ -428,7 +482,7 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
}
}
u32 endTime = os::Timer::getRealTime();
const u32 endTime = os::Timer::getRealTime();
c8 tmp[255];
sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)",
endTime - beginTime, nodeCount, polyCount/3);

View File

@ -193,6 +193,11 @@ public:
//! Remove all currently visible particles
virtual void clearParticles();
//! Do manually update the particles.
//! This should only be called when you want to render the node outside the scenegraph,
//! as the node will care about this otherwise automatically.
virtual void doParticleSystem(u32 time);
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
@ -204,7 +209,6 @@ public:
private:
void doParticleSystem(u32 time);
void reallocateBuffers();
core::list<IParticleAffector*> AffectorList;

View File

@ -358,6 +358,9 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d<f32>& ray,
}
s32 totalcnt = selector->getTriangleCount();
if ( totalcnt <= 0 )
return false;
Triangles.set_used(totalcnt);
s32 cnt = 0;
@ -889,7 +892,7 @@ core::position2d<s32> CSceneCollisionManager::getScreenCoordinatesFrom3DPosition
if (useViewPort)
dim.set(Driver->getViewPort().getWidth(), Driver->getViewPort().getHeight());
else
dim=(Driver->getScreenSize());
dim=(Driver->getCurrentRenderTargetSize());
dim.Width /= 2;
dim.Height /= 2;

View File

@ -2475,7 +2475,7 @@ IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)
#endif
case EMWT_COLLADA:
#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
return new CColladaMeshWriter(Driver, FileSystem);
return new CColladaMeshWriter(this, Driver, FileSystem);
#else
return 0;
#endif

View File

@ -433,7 +433,7 @@ namespace scene
virtual ISceneManager* createNewSceneManager(bool cloneContent);
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_UNKNOWN; }
virtual ESCENE_NODE_TYPE getType() const { return ESNT_SCENE_MANAGER; }
//! Returns the default scene node factory which can create all built in scene nodes
virtual ISceneNodeFactory* getDefaultSceneNodeFactory();

View File

@ -28,14 +28,7 @@ CWaterSurfaceSceneNode::CWaterSurfaceSceneNode(f32 waveHeight, f32 waveSpeed, f3
setDebugName("CWaterSurfaceSceneNode");
#endif
// create copy of the mesh
if (mesh)
{
// Mesh is set in CMeshSceneNode constructor, now it is moved to OriginalMesh
IMesh* clone = SceneManager->getMeshManipulator()->createMeshCopy(mesh);
OriginalMesh = Mesh;
Mesh = clone;
}
setMesh(mesh);
}
@ -71,6 +64,7 @@ void CWaterSurfaceSceneNode::OnAnimate(u32 timeMs)
OriginalMesh->getMeshBuffer(b)->getPosition(i),
time);
}// end for all mesh buffers
Mesh->setDirty(scene::EBT_VERTEX);
SceneManager->getMeshManipulator()->recalculateNormals(Mesh);
}
@ -88,6 +82,8 @@ void CWaterSurfaceSceneNode::setMesh(IMesh* mesh)
IMesh* clone = SceneManager->getMeshManipulator()->createMeshCopy(mesh);
OriginalMesh = mesh;
Mesh = clone;
Mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX);
// Mesh->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX);
}

View File

@ -104,7 +104,7 @@ IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreC
file->read(&sig, 2);
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(sig);
sig = os::Byteswap::byteswap(sig);
#endif
file->seek(0);
@ -126,7 +126,7 @@ bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const
file->read( &header.Sig, 4 );
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(header.Sig);
header.Sig = os::Byteswap::byteswap(header.Sig);
#endif
return header.Sig == 0x04034b50 || // ZIP
@ -192,8 +192,8 @@ bool CZipReader::scanGZipHeader()
{
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(header.sig);
os::Byteswap::byteswap(header.time);
header.sig = os::Byteswap::byteswap(header.sig);
header.time = os::Byteswap::byteswap(header.time);
#endif
// check header value
@ -209,7 +209,7 @@ bool CZipReader::scanGZipHeader()
File->read(&dataLen, 2);
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(dataLen);
dataLen = os::Byteswap::byteswap(dataLen);
#endif
// skip it
@ -274,8 +274,8 @@ bool CZipReader::scanGZipHeader()
File->read(&entry.header.DataDescriptor.UncompressedSize, 4);
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32);
os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize);
entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32);
entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize);
#endif
// now we've filled all the fields, this is just a standard deflate block

View File

@ -8,7 +8,7 @@
<Build>
<Target title="Win32 - Debug - dll">
<Option platforms="Windows;" />
<Option output="../../lib/Win32-gcc/Irrlicht" prefix_auto="1" extension_auto="1" />
<Option output="../../lib/Win32-gcc/libIrrlicht" prefix_auto="1" extension_auto="1" />
<Option object_output="../obj/win32-gcc-debug-dll" />
<Option type="3" />
<Option compiler="gcc" />
@ -52,7 +52,7 @@
</Target>
<Target title="Win32 - Release - accurate math - dll">
<Option platforms="Windows;" />
<Option output="../../lib/Win32-gcc/Irrlicht" prefix_auto="1" extension_auto="1" />
<Option output="../../lib/Win32-gcc/libIrrlicht" prefix_auto="1" extension_auto="1" />
<Option object_output="../obj/win32-gcc-release-dll" />
<Option type="3" />
<Option compiler="gcc" />
@ -94,7 +94,7 @@
</Target>
<Target title="Win32 - Release - fast math - dll">
<Option platforms="Windows;" />
<Option output="../../lib/Win32-gcc/Irrlicht" prefix_auto="1" extension_auto="1" />
<Option output="../../lib/Win32-gcc/libIrrlicht" prefix_auto="1" extension_auto="1" />
<Option object_output="../obj/win32-gcc-release-fast-dll" />
<Option type="3" />
<Option compiler="gcc" />
@ -455,6 +455,7 @@
<Unit filename="../../include/IBillboardTextSceneNode.h" />
<Unit filename="../../include/IBoneSceneNode.h" />
<Unit filename="../../include/ICameraSceneNode.h" />
<Unit filename="../../include/IColladaMeshWriter.h" />
<Unit filename="../../include/ICursorControl.h" />
<Unit filename="../../include/IDummyTransformationSceneNode.h" />
<Unit filename="../../include/IDynamicMeshBuffer.h" />

View File

@ -827,6 +827,7 @@
<ClInclude Include="..\..\include\IEventReceiver.h" />
<ClInclude Include="..\..\include\ILogger.h" />
<ClInclude Include="..\..\include\IOSOperator.h" />
<ClInclude Include="..\..\include\IRandomizer.h" />
<ClInclude Include="..\..\include\IReferenceCounted.h" />
<ClInclude Include="..\..\include\IrrCompileConfig.h" />
<ClInclude Include="..\..\include\irrlicht.h" />

View File

@ -1339,6 +1339,9 @@
<ClInclude Include="..\..\include\EDriverFeatures.h">
<Filter>include\video</Filter>
</ClInclude>
<ClInclude Include="..\..\include\IRandomizer.h">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\changes.txt">

View File

@ -1,9 +1,7 @@
VERSION_MAJOR = 1
VERSION_MINOR = 8
VERSION_RELEASE = 0-SVN
VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
COMPATIBILITY_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
# Irrlicht Engine 1.7.0-SVN
# Irrlicht Engine 1.8.0-SVN
# Makefile for Linux
#
# To use, just run:
@ -18,6 +16,10 @@ COMPATIBILITY_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
# make sharedlib
# make install
#
# If you want to compile in release mode run:
#
# make NDEBUG=1
#
# For cross-compilation for Win32 under Linux, just use the win32 targets. You have to set
# at least CXX, CC, and AR to the proper binaries.
#
@ -105,15 +107,19 @@ sharedlib_win32: LDFLAGS += -lgdi32 -lopengl32 -ld3dx9d -lwinmm
sharedlib_win32 staticlib_win32: CPPFLAGS += -DIRR_COMPILE_WITH_DX9_DEV_PACK -D__GNUWIN32__ -D_WIN32 -DWIN32 -D_WINDOWS -D_MBCS -D_USRDLL
staticlib_win32: CPPFLAGS += -D_IRR_STATIC_LIB_
VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
SHARED_FULLNAME = $(SHARED_LIB).$(VERSION)
SONAME = $(SHARED_LIB).$(VERSION_MAJOR).$(VERSION_MINOR)
####################
# All target, builds Irrlicht as static lib (libIrrlicht.a) and copies it into lib/Linux
all linux: staticlib
# Builds Irrlicht as shared lib (libIrrlicht.so.versionNumber) and copies it into lib/Linux
sharedlib: $(LINKOBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,$(SHARED_LIB).$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE) -o $(SHARED_LIB).$(VERSION) $^ $(LDFLAGS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,$(SONAME) -o $(SHARED_FULLNAME) $^ $(LDFLAGS)
mkdir -p $(LIB_PATH)
cp $(SHARED_LIB).$(VERSION) $(LIB_PATH)
cp $(SHARED_FULLNAME) $(LIB_PATH)
# Builds Irrlicht as static lib (libIrrlicht.a)
$(STATIC_LIB): $(LINKOBJ)
@ -135,17 +141,17 @@ staticlib_win32: $(STATIC_LIB)
# Builds Irrlicht as shared lib (libIrrlicht.so.versionNumber) and copies it into /lib/MacOSX
sharedlib_osx: $(LINKOBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -dynamiclib -Wl,-install_name,$(SHARED_LIB).$(COMPATIBILITY_VERSION) -o $(SHARED_LIB).$(VERSION) $^ $(LDFLAGS)
cp $(SHARED_LIB).$(VERSION) $(LIB_PATH)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -dynamiclib -Wl,-install_name,$(SONAME) -o $(SHARED_FULLNAME) $^ $(LDFLAGS)
cp $(SHARED_FULLNAME) $(LIB_PATH)
# Installs Irrlicht if it was created as shared lib
install install_osx:
$(RM) -r $(INSTALL_DIR)/../include/irrlicht
mkdir -p $(INSTALL_DIR)/../include/irrlicht
cp ../../include/*.h $(INSTALL_DIR)/../include/irrlicht/
cp $(LIB_PATH)/$(SHARED_LIB).$(VERSION) $(INSTALL_DIR)
cd $(INSTALL_DIR) && ln -s -f $(SHARED_LIB).$(VERSION) $(COMPATIBILITY_VERSION)
cp $(LIB_PATH)/$(SHARED_FULLNAME) $(INSTALL_DIR)
cd $(INSTALL_DIR) && ln -s -f $(SHARED_FULLNAME) $(SONAME)
cd $(INSTALL_DIR) && ln -s -f $(SONAME) $(SHARED_LIB)
# ldconfig -n $(INSTALL_DIR)
TAGS:
@ -180,7 +186,7 @@ help:
# Cleans all temporary files and compilation results.
clean:
$(RM) $(LINKOBJ) $(SHARED_LIB).$(VERSION) $(STATIC_LIB) $(LINKOBJ:.o=.d)
$(RM) $(LINKOBJ) $(SHARED_FULLNAME) $(STATIC_LIB) $(LINKOBJ:.o=.d)
.PHONY: all sharedlib staticlib sharedlib_win32 staticlib_win32 help install clean

View File

@ -222,9 +222,9 @@ namespace os
}
//! resets the randomizer
void Randomizer::reset()
void Randomizer::reset(s32 value)
{
seed = 0x0f0f0f0f;
seed = value;
}

View File

@ -51,7 +51,7 @@ namespace os
public:
//! resets the randomizer
static void reset();
static void reset(s32 value=0x0f0f0f0f);
//! generates a pseudo random number in the range 0..randMax()
static s32 rand();

View File

@ -9,23 +9,23 @@ namespace
// based on code and media from SuperTuxKart
class ScalableFont : public gui::IGUIFontBitmap
{
float m_scale;
struct TextureInfo
{
irr::core::stringc m_file_name;
bool m_has_alpha;
float m_scale;
TextureInfo()
{
m_has_alpha = false;
m_scale = 1.0f;
}
};
std::map<int /* texture file ID */, TextureInfo> m_texture_files;
void lazyLoadTexture(int texID)
float m_scale;
struct TextureInfo
{
irr::core::stringc m_file_name;
bool m_has_alpha;
float m_scale;
TextureInfo()
{
m_has_alpha = false;
m_scale = 1.0f;
}
};
std::map<int /* texture file ID */, TextureInfo> m_texture_files;
void lazyLoadTexture(int texID)
{
const bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
@ -33,7 +33,7 @@ class ScalableFont : public gui::IGUIFontBitmap
SpriteBank->setTexture(texID, Driver->getTexture( m_texture_files[texID].m_file_name ));
// set previous mip-map+filter state
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap);
// couldn't load texture, abort.
if (!SpriteBank->getTexture(texID))
{
@ -48,7 +48,7 @@ class ScalableFont : public gui::IGUIFontBitmap
}
}
}
void doReadXmlFile(io::IXMLReader* xml)
void doReadXmlFile(io::IXMLReader* xml)
{
while (xml->read())
{
@ -70,29 +70,29 @@ class ScalableFont : public gui::IGUIFontBitmap
core::stringc filename = xml->getAttributeValue(L"filename");
core::stringc fn = filename;
u32 i = (u32)xml->getAttributeValueAsInt(L"index");
float scale=1.0f;
if(xml->getAttributeValue(L"scale"))
if (xml->getAttributeValue(L"scale"))
scale = xml->getAttributeValueAsFloat(L"scale");
//std::cout << "scale = " << scale << std::endl;
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
//std::cout << "---- Adding font texture " << fn.c_str() << "; alpha=" << alpha.c_str() << std::endl;
// make sure the sprite bank has enough textures in it
while (i+1 > SpriteBank->getTextureCount())
{
SpriteBank->addTexture(NULL);
}
TextureInfo info;
info.m_file_name = fn;
info.m_has_alpha = (alpha == core::stringw("true"));
info.m_scale = scale;
m_texture_files[i] = info;
info.m_scale = scale;
m_texture_files[i] = info;
}
else if (core::stringw(L"c") == xml->getNodeName())
{
@ -101,16 +101,16 @@ class ScalableFont : public gui::IGUIFontBitmap
gui::SGUISpriteFrame f;
gui::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");
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];
wchar_t ch = xml->getAttributeValue(L"c")[0];
const c8 *c = rectstr.c_str();
s32 val;
val = 0;
@ -122,7 +122,7 @@ class ScalableFont : public gui::IGUIFontBitmap
}
rectangle.UpperLeftCorner.X = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
@ -132,7 +132,7 @@ class ScalableFont : public gui::IGUIFontBitmap
}
rectangle.UpperLeftCorner.Y = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
@ -142,7 +142,7 @@ class ScalableFont : public gui::IGUIFontBitmap
}
rectangle.LowerRightCorner.X = val;
while (*c == L' ' || *c == L',') c++;
val = 0;
while (*c >= '0' && *c <= '9')
{
@ -151,24 +151,24 @@ class ScalableFont : public gui::IGUIFontBitmap
c++;
}
rectangle.LowerRightCorner.Y = val;
CharacterMap[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);
}
@ -178,13 +178,13 @@ class ScalableFont : public gui::IGUIFontBitmap
public:
bool m_black_border;
ScalableFont* m_fallback_font;
float m_fallback_font_scale;
int m_fallback_kerning_width;
//! constructor
bool m_black_border;
ScalableFont* m_fallback_font;
float m_fallback_font_scale;
int m_fallback_kerning_width;
//! constructor
ScalableFont(gui::IGUIEnvironment *env, const io::path& filename)
: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
@ -192,12 +192,12 @@ public:
#ifdef _DEBUG
setDebugName("ScalableFont");
#endif
m_fallback_font = NULL;
m_fallback_font = NULL;
m_fallback_kerning_width = 0;
m_fallback_font_scale = 1.0f;
m_scale = 0.37f;
m_black_border = false;
m_fallback_font_scale = 1.0f;
m_scale = 0.37f;
m_black_border = false;
if (Environment)
{
@ -213,7 +213,7 @@ public:
Driver->grab();
setInvisibleCharacters ( L" " );
io::IXMLReader* reader = env->getFileSystem()->createXMLReader(filename.c_str());
if (reader)
{
@ -223,21 +223,23 @@ public:
assert(Areas.size() > 0);
}
//! destructor
virtual ~ScalableFont()
//! destructor
virtual ~ScalableFont()
{
if (Driver) Driver->drop();
if (SpriteBank) SpriteBank->drop();
if (Driver)
Driver->drop();
if (SpriteBank)
SpriteBank->drop();
}
//! loads a font from an XML file
bool load(io::IXMLReader* xml)
//! loads a font from an XML file
bool load(io::IXMLReader* xml)
{
if (!SpriteBank)
return false;
doReadXmlFile(xml);
// set bad character
WrongCharacter = getAreaIDFromCharacter(L' ', NULL);
@ -246,32 +248,33 @@ public:
for(wchar_t c='0'; c<='9'; c++)
{
SFontArea a = getAreaFromCharacter(c, NULL);
if(a.overhang > m_max_digit_area.overhang ) m_max_digit_area.overhang = a.overhang;
if(a.underhang > m_max_digit_area.underhang) m_max_digit_area.underhang = a.underhang;
if(a.width > m_max_digit_area.width ) m_max_digit_area.width = a.width;
if (a.overhang > m_max_digit_area.overhang ) m_max_digit_area.overhang = a.overhang;
if (a.underhang > m_max_digit_area.underhang) m_max_digit_area.underhang = a.underhang;
if (a.width > m_max_digit_area.width) m_max_digit_area.width = a.width;
}
m_max_digit_area.overhang = 0;m_max_digit_area.underhang=0;
m_max_digit_area.overhang = 0;
m_max_digit_area.underhang=0;
return true;
}
//! 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)
//! 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)
{
if (!Driver) return;
core::position2d<s32> offset = position.UpperLeftCorner;
core::dimension2d<s32> text_dimension;
// When we use the "tab" hack, disable right-alignment, it messes up everything
bool has_tab = (text.findFirst(L'\t') != -1);
// bool has_tab = (text.findFirst(L'\t') != -1);
// ---- collect character locations
const unsigned int text_size = text.size();
core::array<s32> indices(text_size);
core::array<s32> indices(text_size);
core::array<core::position2di> offsets(text_size);
core::array<bool> fallback;
core::array<bool> fallback;
fallback.set_used(text_size);
for (u32 i = 0; i<text_size; i++)
{
wchar_t c = text[i];
@ -282,11 +285,12 @@ public:
offset.X = position.UpperLeftCorner.X + position.getWidth()/2;
continue;
}
if (c == L'\r' || // Windows breaks
c == L'\n' ) // Unix breaks
if (c == L'\r' || // Windows breaks
c == L'\n') // Unix breaks
{
if(c==L'\r' && text[i+1]==L'\n') c = text[++i];
if (c==L'\r' && text[i+1]==L'\n')
c = text[++i];
offset.Y += (int)(MaxHeight*m_scale);
offset.X = position.UpperLeftCorner.X;
if (hcenter)
@ -296,23 +300,23 @@ public:
bool use_fallback_font = false;
const SFontArea &area = getAreaFromCharacter(c, &use_fallback_font);
fallback[i] = use_fallback_font;
offset.X += area.underhang;
fallback[i] = use_fallback_font;
offset.X += area.underhang;
offsets.push_back(offset);
// Invisible character. add something to the array anyway so that
// indices from the various arrays remain in sync
indices.push_back( Invisible.findFirst(c) < 0 ? area.spriteno
: -1 );
indices.push_back((Invisible.findFirst(c) < 0) ? (int)area.spriteno
: -1);
offset.X += getCharWidth(area, fallback[i]);
} // for i<text_size
// ---- do the actual rendering
const int indiceAmount = indices.size();
core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
core::array< core::rect<s32> >& positions = SpriteBank->getPositions();
const int indiceAmount = indices.size();
core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
core::array< core::rect<s32> >& positions = SpriteBank->getPositions();
core::array< gui::SGUISprite >* fallback_sprites;
core::array< core::rect<s32> >* fallback_positions;
if(m_fallback_font!=NULL)
if (m_fallback_font!=NULL)
{
fallback_sprites = &m_fallback_font->SpriteBank->getSprites();
fallback_positions = &m_fallback_font->SpriteBank->getPositions();
@ -324,50 +328,51 @@ public:
}
video::IVideoDriver* driver = Environment->getVideoDriver();
const int spriteAmount = sprites.size();
const int spriteAmount = sprites.size();
for (int n=0; n<indiceAmount; n++)
{
const int spriteID = indices[n];
if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount)) continue;
if (indices[n] == -1) continue;
if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount))
continue;
if (indices[n] == -1)
continue;
//assert(sprites[spriteID].Frames.size() > 0);
const int texID = (fallback[n] ?
(*fallback_sprites)[spriteID].Frames[0].textureNumber :
sprites[spriteID].Frames[0].textureNumber);
(*fallback_sprites)[spriteID].Frames[0].textureNumber :
sprites[spriteID].Frames[0].textureNumber);
core::rect<s32> source = (fallback[n] ?
(*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
positions[sprites[spriteID].Frames[0].rectNumber]);
(*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
positions[sprites[spriteID].Frames[0].rectNumber]);
const TextureInfo& info = (fallback[n] ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second);
float char_scale = info.m_scale;
core::dimension2d<s32> size = source.getSize();
float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale);
size.Width = (int)(size.Width * scale * char_scale);
size.Height = (int)(size.Height * scale * char_scale);
// align vertically if character is smaller
int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0);
core::rect<s32> dest(offsets[n] + core::position2di(0, y_shift), size);
video::SColor colors[] = {color, color, color, color};
video::ITexture* texture = (fallback[n] ?
m_fallback_font->SpriteBank->getTexture(texID) :
SpriteBank->getTexture(texID) );
if (texture == NULL)
{
// perform lazy loading
if (fallback[n])
{
m_fallback_font->lazyLoadTexture(texID);
@ -378,19 +383,19 @@ public:
lazyLoadTexture(texID);
texture = SpriteBank->getTexture(texID);
}
if (texture == NULL)
{
continue; // no such character
}
}
if (m_black_border)
{
// draw black border
video::SColor black(color.getAlpha(),0,0,0);
video::SColor black_colors[] = {black, black, black, black};
for (int x_delta=-2; x_delta<=2; x_delta++)
{
for (int y_delta=-2; y_delta<=2; y_delta++)
@ -401,10 +406,10 @@ public:
source,
clip,
black_colors, true);
}
}
}
}
if (fallback[n])
{
// draw text over
@ -424,23 +429,23 @@ public:
source,
clip,
colors, true);
}
}
}
//! returns the dimension of a text
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const
//! returns the dimension of a text
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const
{
assert(Areas.size() > 0);
core::dimension2d<u32> dim(0, 0);
core::dimension2d<u32> thisLine(0, (int)(MaxHeight*m_scale));
for (const wchar_t* p = text; *p; ++p)
{
if (*p == L'\r' || // Windows breaks
*p == L'\n' ) // Unix breaks
if (*p == L'\r' || // Windows breaks
*p == L'\n') // Unix breaks
{
if (*p==L'\r' && p[1] == L'\n') // Windows breaks
++p;
@ -453,26 +458,26 @@ public:
bool fallback = false;
const SFontArea &area = getAreaFromCharacter(*p, &fallback);
thisLine.Width += area.underhang;
thisLine.Width += getCharWidth(area, fallback);
}
dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width) dim.Width = thisLine.Width;
// std::cout << "ScalableFont::getDimension returns : " << dim.Width << ", " << dim.Height << " --> ";
// std::cout << "ScalableFont::getDimension returns : " << dim.Width << ", " << dim.Height << " --> ";
dim.Width = (int)(dim.Width + 0.9f); // round up
dim.Height = (int)(dim.Height + 0.9f);
//std::cout << dim.Width << ", " << dim.Height << std::endl;
return dim;
}
//! 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
//! 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
{
s32 x = 0;
s32 idx = 0;
@ -491,20 +496,20 @@ public:
return -1;
}
//! Returns the type of this font
virtual gui::EGUI_FONT_TYPE getType() const { return gui::EGFT_BITMAP; }
//! Returns the type of this font
virtual gui::EGUI_FONT_TYPE getType() const { return gui::EGFT_BITMAP; }
//! set an Pixel Offset on Drawing ( scale position on width )
virtual void setKerningWidth (s32 kerning)
//! set an Pixel Offset on Drawing ( scale position on width )
virtual void setKerningWidth (s32 kerning)
{
GlobalKerningWidth = kerning;
}
virtual void setKerningHeight (s32 kerning)
virtual void setKerningHeight (s32 kerning)
{
GlobalKerningHeight = kerning;
}
//! set an Pixel Offset on Drawing ( scale position on width )
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const
//! set an Pixel Offset on Drawing ( scale position on width )
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const
{
s32 ret = GlobalKerningWidth;
@ -520,67 +525,69 @@ public:
return ret;
}
virtual s32 getKerningHeight() const
virtual s32 getKerningHeight() const
{
return GlobalKerningHeight;
}
//! gets the sprite bank
virtual gui::IGUISpriteBank* getSpriteBank() const
//! gets the sprite bank
virtual gui::IGUISpriteBank* getSpriteBank() const
{
return SpriteBank;
}
//! returns the sprite number from a given character
virtual u32 getSpriteNoFromChar(const wchar_t *c) const
//! returns the sprite number from a given character
virtual u32 getSpriteNoFromChar(const wchar_t *c) const
{
return Areas[getAreaIDFromCharacter(*c, NULL)].spriteno;
}
virtual void setInvisibleCharacters( const wchar_t *s )
virtual void setInvisibleCharacters( const wchar_t *s )
{
Invisible = s;
}
private:
struct SFontArea
{
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
s32 underhang;
s32 overhang;
s32 width;
u32 spriteno;
};
int getCharWidth(const SFontArea& area, const bool fallback) const
struct SFontArea
{
core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
s32 underhang;
s32 overhang;
s32 width;
u32 spriteno;
};
int getCharWidth(const SFontArea& area, const bool fallback) const
{
core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
core::array< gui::SGUISprite >* fallback_sprites = (m_fallback_font != NULL ?
&m_fallback_font->SpriteBank->getSprites() :
NULL);
&m_fallback_font->SpriteBank->getSprites() :
NULL);
const int texID = (fallback ?
(*fallback_sprites)[area.spriteno].Frames[0].textureNumber :
sprites[area.spriteno].Frames[0].textureNumber);
(*fallback_sprites)[area.spriteno].Frames[0].textureNumber :
sprites[area.spriteno].Frames[0].textureNumber);
const TextureInfo& info = (fallback ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second);
const float char_scale = info.m_scale;
//std::cout << "area.spriteno=" << area.spriteno << ", char_scale=" << char_scale << std::endl;
if (fallback) return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
else return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale);
if (fallback)
return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
else
return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale);
}
s32 getAreaIDFromCharacter(const wchar_t c, bool* fallback_font) const
{
std::map<wchar_t, s32>::const_iterator n = CharacterMap.find(c);
if (n != CharacterMap.end())
{
if (fallback_font != NULL) *fallback_font = false;
if (fallback_font != NULL)
*fallback_font = false;
return (*n).second;
}
else if (m_fallback_font != NULL && fallback_font != NULL)
@ -591,19 +598,20 @@ private:
else
{
// std::cout << "The font does not have this character : <" << (int)c << ">" << std::endl;
if (fallback_font != NULL) *fallback_font = false;
if (fallback_font != NULL)
*fallback_font = false;
return WrongCharacter;
}
}
const SFontArea &getAreaFromCharacter(const wchar_t c, bool* fallback_font) const
const SFontArea &getAreaFromCharacter(const wchar_t c, bool* fallback_font) const
{
const int area_id = getAreaIDFromCharacter(c, fallback_font);
const bool use_fallback_font = (fallback_font && *fallback_font);
const bool use_fallback_font = (fallback_font && *fallback_font);
// Note: fallback_font can be NULL
return ( use_fallback_font ? m_fallback_font->Areas[area_id] : Areas[area_id]);
} // getAreaFromCharacter
void setMaxHeight()
void setMaxHeight()
{
// FIXME: should consider per-texture scaling
MaxHeight = 0;
@ -618,18 +626,18 @@ private:
MaxHeight = t;
}
}
core::array<SFontArea> Areas;
/** The maximum values of all digits, used in monospace_digits. */
mutable SFontArea m_max_digit_area;
std::map<wchar_t, s32> CharacterMap;
video::IVideoDriver* Driver;
gui::IGUISpriteBank* SpriteBank;
gui::IGUIEnvironment* Environment;
u32 WrongCharacter;
s32 MaxHeight;
s32 GlobalKerningWidth, GlobalKerningHeight;
core::array<SFontArea> Areas;
/** The maximum values of all digits, used in monospace_digits. */
mutable SFontArea m_max_digit_area;
std::map<wchar_t, s32> CharacterMap;
video::IVideoDriver* Driver;
gui::IGUISpriteBank* SpriteBank;
gui::IGUIEnvironment* Environment;
u32 WrongCharacter;
s32 MaxHeight;
s32 GlobalKerningWidth, GlobalKerningHeight;
core::stringw Invisible;
core::stringw Invisible;
};
}
@ -655,12 +663,12 @@ static bool draw2DImage4c(video::E_DRIVER_TYPE type)
logTestString("Testing driver %ls\n", driver->getName());
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,true);
driver->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_QUALITY,true);
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,true);
driver->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_QUALITY,true);
video::ITexture* images = driver->getTexture("../media/2ddemo.png");
driver->makeColorKeyTexture(images, core::position2d<s32>(0,0));
core::rect<s32> imp1(349,15,385,78);
core::rect<s32> imp2(387,15,423,78);
@ -668,54 +676,54 @@ static bool draw2DImage4c(video::E_DRIVER_TYPE type)
io::path cwd = device->getFileSystem()->getWorkingDirectory();
device->getFileSystem()->changeWorkingDirectoryTo("media");
ScalableFont* font = new ScalableFont(device->getGUIEnvironment(), "title_font.xml");
font->m_fallback_font_scale = 4.0f;
font->m_fallback_kerning_width = 15;
font->setKerningWidth(-18);
font->m_black_border = true;
ScalableFont* font = new ScalableFont(device->getGUIEnvironment(), "title_font.xml");
font->m_fallback_font_scale = 4.0f;
font->m_fallback_kerning_width = 15;
font->setKerningWidth(-18);
font->m_black_border = true;
/*
Prepare a nicely filtering 2d render mode for special cases.
*/
driver->getMaterial2D().UseMipMaps = true;
Prepare a nicely filtering 2d render mode for special cases.
*/
driver->getMaterial2D().UseMipMaps = true;
driver->getMaterial2D().TextureLayer[0].BilinearFilter = true;
{
driver->beginScene(true, true, video::SColor(255,120,102,136));
driver->enableMaterial2D();
driver->enableMaterial2D();
// draw fire & dragons background world
driver->draw2DImage(images, core::position2di(),
core::rect<s32>(0,0,342,224), 0,
video::SColor(255,255,255,255), true);
core::rect<s32>(0,0,342,224), 0,
video::SColor(255,255,255,255), true);
// draw flying imp
driver->draw2DImage(images, core::position2d<s32>(114,75),
imp1, 0, video::SColor(255,255,255,255), true);
imp1, 0, video::SColor(255,255,255,255), true);
// draw second flying imp
driver->draw2DImage(images, core::position2d<s32>(220,55),
imp2, 0, video::SColor(255,255,255,255), true);
imp2, 0, video::SColor(255,255,255,255), true);
driver->draw2DImage(images, core::rect<s32>(10,10,108,48),
core::rect<s32>(354,87,442,118));
core::rect<s32>(354,87,442,118));
video::SColor colors[] = {0xff00ffff, 0xff00ffff, 0xffffff00, 0xffffff00};
driver->draw2DImage(images, core::recti(10,50,108,88),
core::recti(354,87,442,118), 0, colors, true);
font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,20,300,300),
video::SColor(255,255,255,255) );
font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,20,300,300),
video::SColor(255,255,255,255) );
driver->enableMaterial2D(false);
driver->draw2DImage(images, core::recti(10,90,108,128),
core::recti(354,87,442,118), 0, colors, true);
font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,60,300,400),
video::SColor(255,255,255,255) );
font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,60,300,400),
video::SColor(255,255,255,255) );
driver->endScene();
}
font->drop();
@ -727,7 +735,7 @@ static bool draw2DImage4c(video::E_DRIVER_TYPE type)
device->closeDevice();
device->run();
device->drop();
return result;
return result;
}
// This test renders a 3d scene and a gui on top of it. The GUI is
@ -821,7 +829,7 @@ static bool addBlend2d(video::E_DRIVER_TYPE type)
device->closeDevice();
device->run();
device->drop();
return result;
return result;
}
// This test renders 4 times the same image. Two via IGUIImage, two via draw2DImage
@ -833,8 +841,8 @@ static bool moreFilterTests(video::E_DRIVER_TYPE type)
if (!device)
return true;
video::IVideoDriver* driver = device->getVideoDriver();
gui::IGUIEnvironment* gui = device->getGUIEnvironment();
video::IVideoDriver* driver = device->getVideoDriver();
gui::IGUIEnvironment* gui = device->getGUIEnvironment();
if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER))
{
@ -848,41 +856,41 @@ static bool moreFilterTests(video::E_DRIVER_TYPE type)
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
video::ITexture* tex = driver->getTexture("../media/irrlichtlogo.jpg");
gui::IGUIImage* image = gui->addImage(core::recti(0,0,64,64));
image->setScaleImage(true);
image->setImage(tex);
image->setUseAlphaChannel(true);
gui::IGUIImage* image = gui->addImage(core::recti(0,0,64,64));
image->setScaleImage(true);
image->setImage(tex);
image->setUseAlphaChannel(true);
driver->getMaterial2D().TextureLayer[0].BilinearFilter=true;
driver->getMaterial2D().TextureLayer[0].TrilinearFilter=true;
{
driver->beginScene(true, true, irr::video::SColor(255,255,255,255));
{
driver->beginScene(true, true, irr::video::SColor(255,255,255,255));
// all three logos should be with filtering
driver->enableMaterial2D();
driver->enableMaterial2D();
driver->getMaterial2D().setTexture(0, 0);
driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 64, 128, 128), irr::core::rect<irr::s32>(0, 0, 88, 31));
driver->getMaterial2D().setTexture(0, 0);
driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 64, 128, 128), irr::core::rect<irr::s32>(0, 0, 88, 31));
driver->getMaterial2D().setTexture(0, tex);
driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 0, 128, 64), irr::core::rect<irr::s32>(0, 0, 88, 31));
driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 0, 128, 64), irr::core::rect<irr::s32>(0, 0, 88, 31));
gui->drawAll();
gui->drawAll();
// the next gui image should be without filter
driver->enableMaterial2D(false);
driver->enableMaterial2D(false);
image->setRelativePosition(core::recti(0,64,64,128));
gui->drawAll();
gui->drawAll();
driver->endScene();
}
}
bool result = takeScreenshotAndCompareAgainstReference(driver, "-2dmatFilter.png");
device->closeDevice();
device->run();
device->drop();
return result;
return result;
}
bool twodmaterial()

View File

@ -5,49 +5,43 @@
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
namespace
{
// Tests MD2 animations.
/** At the moment, this just verifies that the last frame of the animation produces the expected bitmap. */
bool md2Animation(void)
bool testLastFrame()
{
// Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions.
IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32);
assert(device);
IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32);
if (!device)
return false;
IVideoDriver* driver = device->getVideoDriver();
ISceneManager * smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager * smgr = device->getSceneManager();
IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
IAnimatedMeshSceneNode* node;
assert(mesh);
scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
bool result = (mesh != 0);
if(mesh)
if (mesh)
{
node = smgr->addAnimatedMeshSceneNode(mesh);
assert(node);
scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if(node)
if (node)
{
node->setPosition(vector3df(20, 0, 30));
node->setMaterialFlag(EMF_LIGHTING, false);
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp"));
node->setLoopMode(false);
(void)smgr->addCameraSceneNode();
// Just jump to the last frame since that's all we're interested in.
node->setMD2Animation(EMAT_DEATH_FALLBACK);
node->setMD2Animation(scene::EMAT_DEATH_FALLBACK);
node->setCurrentFrame((f32)(node->getEndFrame()));
node->setAnimationSpeed(0);
device->run();
driver->beginScene(true, true, SColor(255, 255, 255, 0));
driver->beginScene(true, true, video::SColor(255, 255, 255, 0));
smgr->drawAll();
driver->endScene();
if (mesh->getBoundingBox() != mesh->getMesh(node->getEndFrame())->getBoundingBox())
@ -79,3 +73,56 @@ bool md2Animation(void)
return result;
}
// Tests MD2 normals.
bool testNormals()
{
// Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions.
IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32);
if (!device)
return false;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager * smgr = device->getSceneManager();
scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
bool result = (mesh != 0);
if (mesh)
{
scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if (node)
{
node->setPosition(vector3df(20, 0, 30));
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setDebugDataVisible(scene::EDS_NORMALS);
node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp"));
node->setLoopMode(false);
(void)smgr->addCameraSceneNode();
node->setMD2Animation(scene::EMAT_STAND);
node->setAnimationSpeed(0);
device->run();
driver->beginScene(true, true, video::SColor(255, 255, 255, 0));
smgr->drawAll();
driver->endScene();
}
}
result &= takeScreenshotAndCompareAgainstReference(driver, "-md2Normals.png");
device->closeDevice();
device->run();
device->drop();
return result;
}
}
// test md2 features
bool md2Animation(void)
{
bool result = testLastFrame();
result &= testNormals();
return result;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -41,7 +41,7 @@ bool testShots(video::E_DRIVER_TYPE type)
smgr->drawAll();
driver->endScene();
for (u32 i=0; i<video::ECF_UNKNOWN; ++i)
for (s32 i=0; i<video::ECF_UNKNOWN; ++i)
{
video::IImage* img = driver->createScreenShot((video::ECOLOR_FORMAT)i);
logTestString("Color Format %d %ssupported\n", i, (img && img->getColorFormat() == i)?"":"un");

View File

@ -10,41 +10,41 @@ namespace
// test camera changes with terrain scene node recalculation
bool terrainRecalc(void)
{
IrrlichtDevice *device =
createDevice(video::EDT_BURNINGSVIDEO, dimension2du(160, 120), 32);
IrrlichtDevice *device =
createDevice(video::EDT_BURNINGSVIDEO, dimension2du(160, 120), 32);
if (!device)
return true;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../media/terrain-heightmap.bmp");
terrain->setScale(core::vector3df(40.f, .1f, 40.f));
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../media/terrain-heightmap.bmp");
terrain->setScale(core::vector3df(40.f, .1f, 40.f));
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture("../media/terrain-texture.jpg"));
terrain->setDebugDataVisible(scene::EDS_FULL);
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture("../media/terrain-texture.jpg"));
terrain->setDebugDataVisible(scene::EDS_FULL);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
const core::vector3df center(terrain->getBoundingBox().getCenter());
camera->setTarget(center);
const core::vector3df center(terrain->getBoundingBox().getCenter());
camera->setTarget(center);
// yes, Y is intentionally being set to X here
const core::vector3df above (center.X, center.X, center.Z);
camera->setPosition (above);
// yes, Y is intentionally being set to X here
const core::vector3df above (center.X, center.X, center.Z);
camera->setPosition (above);
camera->setUpVector(vector3df(1.f, 0.f, 0.f));
camera->setFarValue(above.Y);
camera->setFarValue(above.Y);
device->run();
smgr->drawAll();
device->run();
smgr->drawAll();
// This shouldn't cause a recalc
camera->setUpVector(vector3df(1.f, 0.f, .01f).normalize());
device->run();
device->run();
driver->beginScene(true, true, video::SColor(255,100,101,140));
smgr->drawAll();
driver->endScene();
@ -58,7 +58,7 @@ bool terrainRecalc(void)
// This is big enough to cause a recalc
camera->setUpVector(vector3df(1.f, 0.f, .1f).normalize());
device->run();
device->run();
driver->beginScene(true, true, video::SColor(255,100,101,140));
smgr->drawAll();
driver->endScene();
@ -72,7 +72,7 @@ bool terrainRecalc(void)
device->closeDevice();
device->run();
device->drop();
return result;
return result;
}
bool terrainGaps()
@ -114,7 +114,7 @@ bool terrainGaps()
device->closeDevice();
device->run();
device->drop();
return true;
return result;
}
}
@ -124,4 +124,5 @@ bool terrainSceneNode()
bool result = terrainRecalc();
result &= terrainGaps();
return result;
}
}

View File

@ -32,7 +32,7 @@ inline bool compareQ(const core::vector3df& v, const core::vector3df& turn=core:
return true;
}
core::vector3df vals[] = {
const core::vector3df vals[] = {
core::vector3df(0.f, 0.f, 0.f),
core::vector3df(0.f, 0.f, 24.04f),
core::vector3df(0.f, 0.f, 71.f),
@ -100,39 +100,52 @@ bool testEulerConversion()
bool testRotationFromTo()
{
bool result = true;
core::quaternion q1;
core::matrix4 mat;
core::quaternion q4(mat);
core::quaternion q;
q4.rotationFromTo(core::vector3df(1.f,0.f,0.f), core::vector3df(1.f,0.f,0.f));
if (q4 != q1)
q.rotationFromTo(core::vector3df(1.f,0.f,0.f), core::vector3df(1.f,0.f,0.f));
if (q != core::quaternion())
{
logTestString("Quaternion rotationFromTo method did not yield identity.\n");
result = false;
}
q1.set(0.f,0.f,core::PI);
core::quaternion q2(0.f,core::PI,0.f);
q4.rotationFromTo(core::vector3df(1.f,0.f,0.f), core::vector3df(-1.f,0.f,0.f));
if ((q4 != q1)&&(q4 != q2))
core::vector3df from(1.f,0.f,0.f);
q.rotationFromTo(from, core::vector3df(-1.f,0.f,0.f));
from=q*from;
if (from != core::vector3df(-1.f,0.f,0.f))
{
logTestString("Quaternion rotationFromTo method did not yield x flip.\n");
result = false;
}
q4.rotationFromTo(core::vector3df(10.f,20.f,30.f), core::vector3df(-10.f,-20.f,-30.f));
if ((q4 != q1)&&(q4 != q2))
from.set(1.f,2.f,3.f);
q.rotationFromTo(from, core::vector3df(-1.f,-2.f,-3.f));
from=q*from;
if (from != core::vector3df(-1.f,-2.f,-3.f))
{
logTestString("Quaternion rotationFromTo method did not yield x flip for non-axis.\n");
result = false;
}
q1.set(0.f,0.f,core::PI/2);
q4.rotationFromTo(core::vector3df(1.f,0.f,0.f), core::vector3df(0.f,1.f,0.f));
if (!q4.equals(q1))
from.set(1.f,0.f,0.f);
q.rotationFromTo(from, core::vector3df(0.f,1.f,0.f));
from=q*from;
if (from != core::vector3df(0.f,1.f,0.f))
{
logTestString("Quaternion rotationFromTo method did not yield 90 degree rotation.\n");
result = false;
}
for (u32 i=1; i<sizeof(vals)/sizeof(vals[0])-1; ++i)
{
from.set(vals[i]).normalize();
core::vector3df to(vals[i+1]);
to.normalize();
q.rotationFromTo(from, to);
from = q*from;
result &= (from.equals(to, 0.00012f));
}
return result;
}

View File

@ -5,14 +5,14 @@
#include "irrlicht.h"
#include <assert.h>
#define TestWithAllDrivers(X, ...) \
#define TestWithAllDrivers(X) \
logTestString("Running test " #X "\n"); \
for (u32 i=1; i<video::EDT_COUNT; ++i) \
result &= X(video::E_DRIVER_TYPE(i), ##__VA_ARGS__)
#define TestWithAllHWDrivers(X, ...) \
result &= X(video::E_DRIVER_TYPE(i))
#define TestWithAllHWDrivers(X) \
logTestString("Running test " #X "\n"); \
for (u32 i=video::EDT_DIRECT3D8; i<video::EDT_COUNT; ++i) \
result &= X(video::E_DRIVER_TYPE(i), ##__VA_ARGS__)
result &= X(video::E_DRIVER_TYPE(i))
//! Compare two files
/** \param fileName1 The first file for comparison.

View File

@ -59,6 +59,164 @@ static bool testGetIntersectionWithLine(core::triangle3d<T>& triangle, const cor
return allExpected;
}
// modifying the same triangle in diverse ways get some more test-cases automatically
template<class T>
static bool stageModifications(int stage, triangle3d<T>& triangle)
{
switch ( stage )
{
case 0:
return true;
case 1:
swap(triangle.pointB, triangle.pointC);
return true;
case 2:
swap(triangle.pointA, triangle.pointC);
return true;
case 3:
triangle.pointA.Z += 1000;
triangle.pointB.Z += 1000;
triangle.pointC.Z += 1000;
return true;
case 4:
swap(triangle.pointA.Y, triangle.pointA.Z);
swap(triangle.pointB.Y, triangle.pointB.Z);
swap(triangle.pointC.Y, triangle.pointC.Z);
return true;
}
return false;
}
template<class T>
static void stageModifications(int stage, vector3d<T>& point)
{
switch ( stage )
{
case 3:
point.Z += 1000;
break;
case 4:
swap(point.Y, point.Z);
break;
}
}
template<class T>
static bool isPointInside(triangle3d<T> triangleOrig)
{
bool allExpected=true;
array< vector3d<T> > pointsInside;
pointsInside.push_back( vector3d<T>(0,0,0) );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB + triangleOrig.pointC) / 3 );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 + vector3d<T>(0,1,0) );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
pointsInside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsInside.size(); ++i )
{
vector3d<T> point = pointsInside[i];
stageModifications(stage, point);
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsInside test failed in stage %d point %d\n", stage, i);
return false;
}
allExpected &= triangle.isPointInsideFast( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInsideFast pointsInside test failed in stage %d point %d\n", stage, i);
return false;
}
}
}
array< vector3d<T> > pointsOutside;
pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(0,1,0) );
pointsOutside.push_back( triangleOrig.pointB + vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointB - vector3d<T>(0,1,0) );
pointsOutside.push_back( triangleOrig.pointC - vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(0,1,0) );
pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 - vector3d<T>(0,1,0) );
pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
pointsOutside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsOutside.size(); ++i )
{
vector3d<T> point = pointsOutside[i];
stageModifications(stage, point);
allExpected &= !triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsOutside test failed in stage %d point %d\n", stage, i);
return false;
}
allExpected &= !triangle.isPointInsideFast( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInsideFast pointsOutside test failed in stage %d point %d\n", stage, i);
return false;
}
}
}
array< vector3d<T> > pointsBorder;
pointsBorder.push_back( triangleOrig.pointA );
pointsBorder.push_back( triangleOrig.pointB );
pointsBorder.push_back( triangleOrig.pointC );
pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 );
pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 );
pointsBorder.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsBorder.size(); ++i )
{
vector3d<T> point = pointsBorder[i];
stageModifications(stage, point);
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsBorder test failed in stage %d point %d\n", stage, i);
return false;
}
/* results for isPointInsideFast are mixed for border cases, but I guess that's fine.
if ( triangle.isPointInsideFast( point ) )
logTestString("+ triangle3d::isPointInsideFast pointsBorder stage %d point %d is INSIDE\n", stage, i);
else
logTestString("- triangle3d::isPointInsideFast pointsBorder stage %d point %d is NOT inside\n", stage, i);
*/
}
}
return allExpected;
}
// Test the functionality of triangle3d<T>
/** Validation is done with asserts() against expected results. */
@ -89,6 +247,29 @@ bool testTriangle3d(void)
allExpected &= testGetIntersectionWithLine(triangle, ray);
}
bool testEigen = triangle3di(vector3di(250, 0, 0), vector3di(0, 0, 500), vector3di(500, 0, 500)).isPointInside(vector3di(300,0,300));
if ( !testEigen ) // test from Eigen from here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44372&p=254331#p254331
logTestString("Test isPointInside fails with integers\n");
allExpected &= testEigen;
logTestString("Test isPointInside with f32\n");
{
triangle3d<f32> t(vector3d<f32>(-1000,-1000,0), vector3d<f32>(1000,-1000,0), vector3d<f32>(0,1000,0));
allExpected &= isPointInside(t);
}
logTestString("Test isPointInside with f64\n");
{
triangle3d<f64> t(vector3d<f64>(-1000,-1000,0), vector3d<f64>(1000,-1000,0), vector3d<f64>(0,1000,0));
allExpected &= isPointInside(t);
}
logTestString("Test isPointInside with s32\n");
{
triangle3d<s32> t(vector3d<s32>(-1000,-1000,0), vector3d<s32>(1000,-1000,0), vector3d<s32>(0,1000,0));
allExpected &= isPointInside(t);
}
if(allExpected)
logTestString("\nAll tests passed\n");
else

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_layout_file>
<ActiveTarget name="All" />
<File name="main.cpp" open="0" top="0" tabpos="0">
<Cursor position="1821" topLine="63" />
<File name="main.cpp" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor1 position="363" topLine="6" />
</File>
</CodeBlocks_layout_file>