diff --git a/changes.txt b/changes.txt
index 17ce35e0..34eaedae 100644
--- a/changes.txt
+++ b/changes.txt
@@ -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
diff --git a/examples/16.Quake3MapShader/Quake3MapShader.cbp b/examples/16.Quake3MapShader/Quake3MapShader.cbp
index 62a6ce80..0ed9bcb8 100644
--- a/examples/16.Quake3MapShader/Quake3MapShader.cbp
+++ b/examples/16.Quake3MapShader/Quake3MapShader.cbp
@@ -24,8 +24,8 @@
-
+
@@ -33,7 +33,7 @@
-
+
diff --git a/examples/23.SMeshHandling/SMeshHandling.cbp b/examples/23.SMeshHandling/SMeshHandling.cbp
index b8036570..ac304239 100644
--- a/examples/23.SMeshHandling/SMeshHandling.cbp
+++ b/examples/23.SMeshHandling/SMeshHandling.cbp
@@ -18,7 +18,9 @@
-
+
+
+
@@ -27,7 +29,7 @@
-
+
diff --git a/include/ESceneNodeTypes.h b/include/ESceneNodeTypes.h
index b84ce1a5..c9cfef3c 100644
--- a/include/ESceneNodeTypes.h
+++ b/include/ESceneNodeTypes.h
@@ -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'),
diff --git a/include/ICameraSceneNode.h b/include/ICameraSceneNode.h
index 8f955345..7035f37e 100644
--- a/include/ICameraSceneNode.h
+++ b/include/ICameraSceneNode.h
@@ -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;
diff --git a/include/IEventReceiver.h b/include/IEventReceiver.h
index 26e5a8cf..1a19dff7 100644
--- a/include/IEventReceiver.h
+++ b/include/IEventReceiver.h
@@ -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;
diff --git a/include/IGUIButton.h b/include/IGUIButton.h
index 810049c0..9c44ec7d 100644
--- a/include/IGUIButton.h
+++ b/include/IGUIButton.h
@@ -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;
diff --git a/include/IGUIComboBox.h b/include/IGUIComboBox.h
index 3d818d98..b04f35d4 100644
--- a/include/IGUIComboBox.h
+++ b/include/IGUIComboBox.h
@@ -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;
};
diff --git a/include/IGUIEditBox.h b/include/IGUIEditBox.h
index e3bba6eb..cdbf740a 100644
--- a/include/IGUIEditBox.h
+++ b/include/IGUIEditBox.h
@@ -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;
diff --git a/include/IGUISpinBox.h b/include/IGUISpinBox.h
index dbbf4832..77cddd87 100644
--- a/include/IGUISpinBox.h
+++ b/include/IGUISpinBox.h
@@ -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;
diff --git a/include/IGUIStaticText.h b/include/IGUIStaticText.h
index 221bfa21..03b21883 100644
--- a/include/IGUIStaticText.h
+++ b/include/IGUIStaticText.h
@@ -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;
diff --git a/include/IParticleSystemSceneNode.h b/include/IParticleSystemSceneNode.h
index f0693c4d..843dae14 100644
--- a/include/IParticleSystemSceneNode.h
+++ b/include/IParticleSystemSceneNode.h
@@ -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;
diff --git a/include/ISceneManager.h b/include/ISceneManager.h
index f4b700c3..13b2125a 100644
--- a/include/ISceneManager.h
+++ b/include/ISceneManager.h
@@ -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
};
diff --git a/include/ITimer.h b/include/ITimer.h
index aa32895f..b2d78d0f 100644
--- a/include/ITimer.h
+++ b/include/ITimer.h
@@ -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
-
diff --git a/include/IrrlichtDevice.h b/include/IrrlichtDevice.h
index f8ca14a6..e8b5ddb3 100644
--- a/include/IrrlichtDevice.h
+++ b/include/IrrlichtDevice.h
@@ -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;
diff --git a/include/irrMap.h b/include/irrMap.h
index d523c7ef..bb3a2df8 100644
--- a/include/irrMap.h
+++ b/include/irrMap.h
@@ -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;
diff --git a/include/irrlicht.h b/include/irrlicht.h
index feaca631..7b09e602 100644
--- a/include/irrlicht.h
+++ b/include/irrlicht.h
@@ -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
diff --git a/include/quaternion.h b/include/quaternion.h
index e56b7329..ff5f970c 100644
--- a/include/quaternion.h
+++ b/include/quaternion.h
@@ -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();
}
diff --git a/include/triangle3d.h b/include/triangle3d.h
index 289ebd67..e80b53d2 100644
--- a/include/triangle3d.h
+++ b/include/triangle3d.h
@@ -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& p) const
{
- return (isOnSameSide(p, pointA, pointB, pointC) &&
- isOnSameSide(p, pointB, pointA, pointC) &&
- isOnSameSide(p, pointC, pointA, pointB));
+ const vector3d a = pointC - pointA;
+ const vector3d b = pointB - pointA;
+ const vector3d 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. */
diff --git a/include/vector2d.h b/include/vector2d.h
index f0965833..8bd660c2 100644
--- a/include/vector2d.h
+++ b/include/vector2d.h
@@ -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;
}
diff --git a/include/vector3d.h b/include/vector3d.h
index 800cac24..33b8345d 100644
--- a/include/vector3d.h
+++ b/include/vector3d.h
@@ -421,6 +421,26 @@ namespace core
template <>
inline vector3d& vector3d::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;}
+ template <>
+ inline vector3d vector3d::getSphericalCoordinateAngles()
+ {
+ vector3d 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 vector3df;
diff --git a/media/bigfont.png b/media/bigfont.png
index 51049071..ca8d948c 100644
Binary files a/media/bigfont.png and b/media/bigfont.png differ
diff --git a/source/Irrlicht/CAnimatedMeshMD2.cpp b/source/Irrlicht/CAnimatedMeshMD2.cpp
index 16d4b345..cb055dea 100644
--- a/source/Irrlicht/CAnimatedMeshMD2.cpp
+++ b/source/Irrlicht/CAnimatedMeshMD2.cpp
@@ -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<(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; iPos.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& 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;
}
diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp
index f4a59ce9..30ab7c83 100644
--- a/source/Irrlicht/CAnimatedMeshSceneNode.cpp
+++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp
@@ -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
}
/*!
diff --git a/source/Irrlicht/CBillboardSceneNode.cpp b/source/Irrlicht/CBillboardSceneNode.cpp
index 14cf0573..442486ea 100644
--- a/source/Irrlicht/CBillboardSceneNode.cpp
+++ b/source/Irrlicht/CBillboardSceneNode.cpp
@@ -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);
}
diff --git a/source/Irrlicht/CColladaFileLoader.cpp b/source/Irrlicht/CColladaFileLoader.cpp
index f23cd521..b096be11 100644
--- a/source/Irrlicht/CColladaFileLoader.cpp
+++ b/source/Irrlicht/CColladaFileLoader.cpp
@@ -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; idrop();
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
diff --git a/source/Irrlicht/CColladaFileLoader.h b/source/Irrlicht/CColladaFileLoader.h
index 944449d7..86dbeff9 100644
--- a/source/Irrlicht/CColladaFileLoader.h
+++ b/source/Irrlicht/CColladaFileLoader.h
@@ -135,6 +135,8 @@ struct SColladaEffect
f32 Transparency;
core::array 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 MaterialsToBind;
//! Array of buffers for each material binding
core::array< core::array > MeshesToBind;
- io::CAttributes Parameters;
bool CreateInstances;
};
diff --git a/source/Irrlicht/CColladaMeshWriter.cpp b/source/Irrlicht/CColladaMeshWriter.cpp
index 135cedd8..73bbfd15 100644
--- a/source/Irrlicht/CColladaMeshWriter.cpp
+++ b/source/Irrlicht/CColladaMeshWriter.cpp
@@ -2,6 +2,8 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
+// TODO: second UV-coordinates currently ignored in textures
+
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
@@ -13,14 +15,128 @@
#include "IXMLWriter.h"
#include "IMesh.h"
#include "IAttributes.h"
+#include "IAnimatedMeshSceneNode.h"
+#include "IMeshSceneNode.h"
+#include "ITerrainSceneNode.h"
+#include "ILightSceneNode.h"
+#include "ISceneManager.h"
namespace irr
{
namespace scene
{
+//! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
+E_COLLADA_TECHNIQUE_FX CColladaMeshWriterProperties::getTechniqueFx(const video::SMaterial& material) const
+{
+ return ECTF_BLINN;
+}
-CColladaMeshWriter::CColladaMeshWriter(video::IVideoDriver* driver,
+//! Which texture index should be used when writing the texture of the given sampler color.
+s32 CColladaMeshWriterProperties::getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const
+{
+ // So far we just export in a way which is similar to how we import colladas.
+ // There might be better ways to do this, but I suppose it depends a lot for which target
+ // application we export, so in most cases it will have to be done in user-code anyway.
+ switch ( cs )
+ {
+ case ECCS_DIFFUSE:
+ return 2;
+ case ECCS_AMBIENT:
+ return 1;
+ case ECCS_EMISSIVE:
+ return 0;
+ case ECCS_SPECULAR:
+ return 3;
+ case ECCS_TRANSPARENT:
+ return -1;
+ case ECCS_REFLECTIVE:
+ return -1;
+ };
+ return -1;
+}
+
+E_COLLADA_IRR_COLOR CColladaMeshWriterProperties::getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const
+{
+ switch ( cs )
+ {
+ case ECCS_DIFFUSE:
+ return ECIC_DIFFUSE;
+ case ECCS_AMBIENT:
+ return ECIC_AMBIENT;
+ case ECCS_EMISSIVE:
+ return ECIC_EMISSIVE;
+ case ECCS_SPECULAR:
+ return ECIC_SPECULAR;
+ case ECCS_TRANSPARENT:
+ return ECIC_NONE;
+ case ECCS_REFLECTIVE:
+ return ECIC_CUSTOM;
+ };
+
+ return ECIC_NONE;
+}
+
+//! Return custom colors for certain color types requested by collada.
+video::SColor CColladaMeshWriterProperties::getCustomColor(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const
+{
+ return video::SColor(255, 0, 0, 0);
+}
+
+
+//! Return the settings for transparence
+E_COLLADA_TRANSPARENT_FX CColladaMeshWriterProperties::getTransparentFx(const video::SMaterial& material) const
+{
+ // TODO: figure out best default mapping
+ return ECOF_A_ONE;
+}
+
+//! Transparency value for the material.
+f32 CColladaMeshWriterProperties::getTransparency(const video::SMaterial& material) const
+{
+ // TODO: figure out best default mapping
+ return -1.f;
+}
+
+//! Reflectivity value for that material
+f32 CColladaMeshWriterProperties::getReflectivity(const video::SMaterial& material) const
+{
+ // TODO: figure out best default mapping
+ return 0.f;
+}
+
+//! Return index of refraction for that material
+f32 CColladaMeshWriterProperties::getIndexOfRefraction(const video::SMaterial& material) const
+{
+ return -1.f;
+}
+
+bool CColladaMeshWriterProperties::isExportable(const irr::scene::ISceneNode * node) const
+{
+ return node && node->isVisible();
+}
+
+IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node)
+{
+ if ( !node )
+ return 0;
+ if ( node->getType() == ESNT_ANIMATED_MESH )
+ return static_cast(node)->getMesh()->getMesh(0);
+ if ( node->getType() == ESNT_MESH
+ || node->getType() == ESNT_CUBE
+ || node->getType() == ESNT_SPHERE
+ || node->getType() == ESNT_WATER_SURFACE
+ || node->getType() == ESNT_Q3SHADER_SCENE_NODE
+ )
+ return static_cast(node)->getMesh();
+ if ( node->getType() == ESNT_TERRAIN )
+ return static_cast(node)->getMesh();
+ return 0;
+}
+
+
+
+CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDriver* driver,
io::IFileSystem* fs)
: FileSystem(fs), VideoDriver(driver), Writer(0)
{
@@ -34,6 +150,14 @@ CColladaMeshWriter::CColladaMeshWriter(video::IVideoDriver* driver,
if (FileSystem)
FileSystem->grab();
+
+ if ( smgr )
+ setAmbientLight( smgr->getAmbientLight() );
+
+ CColladaMeshWriterProperties * p = new CColladaMeshWriterProperties();
+ setDefaultProperties(p);
+ setProperties(p);
+ p->drop();
}
@@ -53,6 +177,369 @@ EMESH_WRITER_TYPE CColladaMeshWriter::getType() const
return EMWT_COLLADA;
}
+//! writes a scene starting with the given node
+bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* root)
+{
+ if (!file || !root)
+ return false;
+
+ Writer = FileSystem->createXMLWriter(file);
+
+ if (!Writer)
+ {
+ os::Printer::log("Could not write file", file->getFileName());
+ return false;
+ }
+
+ Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() ));
+
+ // make names for all nodes with exportable meshes
+ Meshes.clear();
+ makeMeshNames(root);
+
+ os::Printer::log("Writing scene", file->getFileName());
+
+ // write COLLADA header
+
+ Writer->writeXMLHeader();
+
+ Writer->writeElement(L"COLLADA", false,
+ L"xmlns", L"http://www.collada.org/2005/11/COLLADASchema",
+ L"version", L"1.4.1");
+ Writer->writeLineBreak();
+
+ // write asset data
+ writeAsset();
+
+ // write all materials
+ Writer->writeElement(L"library_materials", false);
+ Writer->writeLineBreak();
+ writeNodeMaterials(root);
+ Writer->writeClosingTag(L"library_materials");
+ Writer->writeLineBreak();
+
+ LibraryImages.clear();
+ Writer->writeElement(L"library_effects", false);
+ Writer->writeLineBreak();
+ writeNodeEffects(root);
+ Writer->writeClosingTag(L"library_effects");
+ Writer->writeLineBreak();
+
+
+ // images
+ writeLibraryImages();
+
+ // lights
+ Writer->writeElement(L"library_lights", false);
+ Writer->writeLineBreak();
+
+ writeAmbientLightElement( getAmbientLight() );
+ writeNodeLights(root);
+
+ Writer->writeClosingTag(L"library_lights");
+ Writer->writeLineBreak();
+
+
+ // write meshes
+ Writer->writeElement(L"library_geometries", false);
+ Writer->writeLineBreak();
+ writeNodeGeometries(root);
+ Writer->writeClosingTag(L"library_geometries");
+ Writer->writeLineBreak();
+
+ // write scene
+ Writer->writeElement(L"library_visual_scenes", false);
+ Writer->writeLineBreak();
+ Writer->writeElement(L"visual_scene", false, L"id", L"default_scene");
+ Writer->writeLineBreak();
+
+ // ambient light
+ Writer->writeElement(L"node", false);
+ Writer->writeLineBreak();
+ Writer->writeElement(L"instance_light", true, L"url", L"#ambientlight");
+ Writer->writeLineBreak();
+
+ // scenegraph
+ writeSceneNode(root);
+
+ Writer->writeClosingTag(L"node");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"visual_scene");
+ Writer->writeLineBreak();
+ Writer->writeClosingTag(L"library_visual_scenes");
+ Writer->writeLineBreak();
+
+
+ // instance scene
+ Writer->writeElement(L"scene", false);
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"scene");
+ Writer->writeLineBreak();
+
+
+ // close everything
+
+ Writer->writeClosingTag(L"COLLADA");
+ Writer->drop();
+
+ return true;
+}
+
+void CColladaMeshWriter::makeMeshNames(irr::scene::ISceneNode * node)
+{
+ if ( !node || !getProperties() || !getProperties()->isExportable(node) )
+ return;
+
+ IMesh* mesh = getProperties()->getMesh(node);
+ if ( mesh )
+ {
+ if ( !Meshes.find(mesh) )
+ {
+ ColladaMesh cm;
+ cm.Name = uniqueNameForMesh(mesh);
+ Meshes.insert(mesh, cm);
+ }
+ }
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ makeMeshNames(*it);
+ }
+}
+
+void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node)
+{
+ if ( !node || !getProperties() || !getProperties()->isExportable(node) )
+ return;
+
+ IMesh* mesh = getProperties()->getMesh(node);
+ if ( mesh )
+ {
+ MeshNode * n = Meshes.find(mesh);
+ if ( n && !n->getValue().MaterialWritten )
+ {
+ writeMeshMaterials(n->getValue().Name, mesh);
+ n->getValue().MaterialWritten = true;
+ }
+ }
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ writeNodeMaterials( *it );
+ }
+}
+
+void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node)
+{
+ if ( !node || !getProperties() || !getProperties()->isExportable(node) )
+ return;
+
+ IMesh* mesh = getProperties()->getMesh(node);
+ if ( mesh )
+ {
+ MeshNode * n = Meshes.find(mesh);
+ if ( n && !n->getValue().EffectWritten )
+ {
+ irr::core::stringw meshname(n->getValue().Name);
+ for (u32 i=0; igetMaterialCount(); ++i)
+ {
+ core::stringw strMat = "mat";
+ strMat += meshname;
+ strMat += i;
+ strMat += L"-fx";
+
+ video::SMaterial & material = node->getMaterial(i);
+ writeMaterialEffect(meshname, strMat, material);
+ }
+ n->getValue().EffectWritten = true;
+ }
+ }
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ writeNodeEffects( *it );
+ }
+}
+
+void CColladaMeshWriter::writeNodeLights(irr::scene::ISceneNode * node)
+{
+ if ( !node )
+ return;
+
+ if ( node->getType() == ESNT_LIGHT )
+ {
+ ILightSceneNode * lightNode = static_cast(node);
+ const video::SLight& lightData = lightNode->getLightData();
+
+ ColladaLight cLight;
+ cLight.Name = uniqueNameForLight(node);
+ LightNodes.insert(node, cLight);
+
+ Writer->writeElement(L"light", false, L"id", cLight.Name.c_str());
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ switch ( lightNode->getLightType() )
+ {
+ case video::ELT_POINT:
+ Writer->writeElement(L"point", false);
+ Writer->writeLineBreak();
+
+ writeColorElement(lightData.DiffuseColor, false);
+
+ Writer->writeElement(L"constant_attenuation ", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.X).c_str() );
+ Writer->writeClosingTag(L"constant_attenuation ");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"linear_attenuation ", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.Y).c_str() );
+ Writer->writeClosingTag(L"linear_attenuation ");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"quadratic_attenuation", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.Z).c_str() );
+ Writer->writeClosingTag(L"quadratic_attenuation");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"point");
+ Writer->writeLineBreak();
+ break;
+
+ case video::ELT_SPOT:
+ Writer->writeElement(L"spot", false);
+ Writer->writeLineBreak();
+
+ writeColorElement(lightData.DiffuseColor, false);
+
+ Writer->writeElement(L"constant_attenuation ", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.X).c_str() );
+ Writer->writeClosingTag(L"constant_attenuation ");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"linear_attenuation ", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.Y).c_str() );
+ Writer->writeClosingTag(L"linear_attenuation ");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"quadratic_attenuation", false);
+ Writer->writeText( irr::core::stringw(lightData.Attenuation.Z).c_str() );
+ Writer->writeClosingTag(L"quadratic_attenuation");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"falloff_angle", false);
+ Writer->writeText( irr::core::stringw(lightData.OuterCone * core::RADTODEG).c_str() );
+ Writer->writeClosingTag(L"falloff_angle");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"falloff_exponent", false);
+ Writer->writeText( irr::core::stringw(lightData.Falloff).c_str() );
+ Writer->writeClosingTag(L"falloff_exponent");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"spot");
+ Writer->writeLineBreak();
+ break;
+
+ case video::ELT_DIRECTIONAL:
+ Writer->writeElement(L"directional", false);
+ Writer->writeLineBreak();
+
+ writeColorElement(lightData.DiffuseColor, false);
+
+ Writer->writeClosingTag(L"directional");
+ Writer->writeLineBreak();
+ break;
+ }
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"light");
+ Writer->writeLineBreak();
+
+ }
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ writeNodeLights( *it );
+ }
+}
+
+void CColladaMeshWriter::writeNodeGeometries(irr::scene::ISceneNode * node)
+{
+ if ( !node || !getProperties() || !getProperties()->isExportable(node) )
+ return;
+
+ IMesh* mesh = getProperties()->getMesh(node);
+ if ( mesh )
+ {
+ MeshNode * n = Meshes.find(mesh);
+ if ( n && !n->getValue().GeometryWritten )
+ {
+ writeMeshGeometry(n->getValue().Name, mesh);
+ n->getValue().GeometryWritten = true;
+ }
+ }
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ writeNodeGeometries( *it );
+ }
+}
+
+void CColladaMeshWriter::writeSceneNode(irr::scene::ISceneNode * node )
+{
+ if ( !node || !getProperties() || !getProperties()->isExportable(node) )
+ return;
+
+ // Collada doesn't require to set the id, but some other tools have problems if none exists, so we just add it).
+ irr::core::stringw nameId(uniqueNameForNode(node));
+ Writer->writeElement(L"node", false, L"id", nameId.c_str());
+ Writer->writeLineBreak();
+
+ irr::core::vector3df rot(node->getRotation());
+ writeTranslateElement( node->getPosition() );
+ writeRotateElement( irr::core::vector3df(1.f, 0.f, 0.f), rot.X );
+ writeRotateElement( irr::core::vector3df(0.f, 1.f, 0.f), rot.Y );
+ writeRotateElement( irr::core::vector3df(0.f, 0.f, 1.f), rot.Z );
+ writeScaleElement( node->getScale() );
+
+ // instance geometry
+ IMesh* mesh = getProperties()->getMesh(node);
+ if ( mesh )
+ {
+ MeshNode * n = Meshes.find(mesh);
+ if ( n )
+ writeMeshInstanceGeometry(n->getValue().Name, mesh);
+ }
+
+ // instance light
+ if ( node->getType() == ESNT_LIGHT )
+ {
+ LightNode * n = LightNodes.find(node);
+ if ( n )
+ writeLightInstance(n->getValue().Name);
+ }
+
+ // TODO instance cameras
+
+ const core::list& children = node->getChildren();
+ for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it )
+ {
+ writeSceneNode( *it );
+ }
+
+ Writer->writeClosingTag(L"node");
+ Writer->writeLineBreak();
+}
//! writes a mesh
bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
@@ -68,6 +555,8 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
return false;
}
+ Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() ));
+
os::Printer::log("Writing mesh", file->getFileName());
// write COLLADA header
@@ -79,8 +568,343 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
L"version", L"1.4.1");
Writer->writeLineBreak();
- // write asset data
+ // write asset data
+ writeAsset();
+ // write all materials
+
+ Writer->writeElement(L"library_materials", false);
+ Writer->writeLineBreak();
+
+ irr::core::stringw meshname(uniqueNameForMesh(mesh));
+ writeMeshMaterials(meshname, mesh);
+
+ Writer->writeClosingTag(L"library_materials");
+ Writer->writeLineBreak();
+
+ LibraryImages.clear();
+ Writer->writeElement(L"library_effects", false);
+ Writer->writeLineBreak();
+
+ writeMeshEffects(meshname, mesh);
+
+ Writer->writeClosingTag(L"library_effects");
+ Writer->writeLineBreak();
+
+ // images
+ writeLibraryImages();
+
+ // write mesh
+
+ Writer->writeElement(L"library_geometries", false);
+ Writer->writeLineBreak();
+
+ writeMeshGeometry(meshname, mesh);
+
+ Writer->writeClosingTag(L"library_geometries");
+ Writer->writeLineBreak();
+
+ // write scene_library
+ if ( getWriteDefaultScene() )
+ {
+ Writer->writeElement(L"library_visual_scenes", false);
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"visual_scene", false, L"id", L"default_scene");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"node", false);
+ Writer->writeLineBreak();
+
+ writeMeshInstanceGeometry(meshname, mesh);
+
+ Writer->writeClosingTag(L"node");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"visual_scene");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"library_visual_scenes");
+ Writer->writeLineBreak();
+
+
+ // write scene
+ Writer->writeElement(L"scene", false);
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"scene");
+ Writer->writeLineBreak();
+ }
+
+
+ // close everything
+
+ Writer->writeClosingTag(L"COLLADA");
+ Writer->drop();
+
+ return true;
+}
+
+void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh)
+{
+ //
+ core::stringw meshId(meshname);
+ Writer->writeElement(L"instance_geometry", false, L"url", toRef(meshId).c_str());
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"bind_material", false);
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ // instance materials
+ //
+ for (u32 i=0; igetMeshBufferCount(); ++i)
+ {
+ core::stringw strMat = "mat";
+ strMat += meshname;
+ strMat += i;
+ core::stringw strMatInst(L"#");
+ strMatInst += strMat;
+ Writer->writeElement(L"instance_material", false, L"symbol", strMat.c_str(), L"target", strMatInst.c_str());
+ Writer->writeLineBreak();
+
+ //
+ core::stringw meshTexCoordId(meshname);
+ meshTexCoordId += L"-TexCoord0"; // TODO: need to handle second UV-set
+ Writer->writeElement(L"bind_vertex_input", true, L"semantic", meshTexCoordId.c_str(), L"input_semantic", L"TEXCOORD", L"input_set", L"0" );
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"instance_material");
+ Writer->writeLineBreak();
+ }
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"bind_material");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"instance_geometry");
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeLightInstance(const irr::core::stringw& lightName)
+{
+ Writer->writeElement(L"instance_light", true, L"url", toRef(lightName).c_str());
+ Writer->writeLineBreak();
+}
+
+bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const
+{
+ return type == video::EVT_2TCOORDS;
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector3df& vec) const
+{
+ c8 tmpbuf[255];
+ snprintf(tmpbuf, 255, "%f %f %f", vec.X, vec.Y, vec.Z);
+ core::stringw str = tmpbuf;
+
+ return str;
+}
+
+irr::core::stringw CColladaMeshWriter::uvToString(const irr::core::vector2df& vec) const
+{
+ // change handedness
+ return toString( core::vector2df(vec.X, 1.f-vec.Y) );
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector2df& vec) const
+{
+ c8 tmpbuf[255];
+ snprintf(tmpbuf, 255, "%f %f", vec.X, vec.Y);
+ core::stringw str = tmpbuf;
+
+ return str;
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::video::SColorf& colorf, bool writeAlpha) const
+{
+ c8 tmpbuf[255];
+ if ( writeAlpha )
+ snprintf(tmpbuf, 255, "%f %f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue(), colorf.getAlpha());
+ else
+ snprintf(tmpbuf, 255, "%f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue());
+ core::stringw str = tmpbuf;
+
+ return str;
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::video::ECOLOR_FORMAT format) const
+{
+ switch ( format )
+ {
+ case video::ECF_A1R5G5B5: return irr::core::stringw(L"A1R5G5B5");
+ case video::ECF_R5G6B5: return irr::core::stringw(L"R5G6B5");
+ case video::ECF_R8G8B8: return irr::core::stringw(L"R8G8B8");
+ case video::ECF_A8R8G8B8: return irr::core::stringw(L"A8R8G8B8");
+ default: return irr::core::stringw(L"");
+ }
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const
+{
+ switch ( clamp )
+ {
+ case video::ETC_REPEAT:
+ return core::stringw(L"WRAP");
+ case video::ETC_CLAMP:
+ case video::ETC_CLAMP_TO_EDGE:
+ return core::stringw(L"CLAMP");
+ case video::ETC_CLAMP_TO_BORDER:
+ return core::stringw(L"BORDER");
+ case video::ETC_MIRROR:
+ case video::ETC_MIRROR_CLAMP:
+ case video::ETC_MIRROR_CLAMP_TO_EDGE:
+ case video::ETC_MIRROR_CLAMP_TO_BORDER:
+ return core::stringw(L"MIRROR");
+ }
+ return core::stringw(L"NONE");
+}
+
+irr::core::stringw CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const
+{
+ if ( transparent & ECOF_RGB_ZERO )
+ return core::stringw(L"RGB_ZERO");
+ else
+ return core::stringw(L"A_ONE");
+}
+
+irr::core::stringw CColladaMeshWriter::toRef(const irr::core::stringw& source) const
+{
+ irr::core::stringw ref(L"#");
+ ref += source;
+ return ref;
+}
+
+irr::core::stringw CColladaMeshWriter::uniqueNameForMesh(const scene::IMesh* mesh) const
+{
+ irr::core::stringw name(L"mesh");
+ name += irr::core::stringw((long)mesh);
+ return name;
+}
+
+irr::core::stringw CColladaMeshWriter::uniqueNameForLight(const scene::ISceneNode* lightNode) const
+{
+ irr::core::stringw name(L"light"); // (prefix, because xs::ID can't start with a number)
+ name += irr::core::stringw((long)lightNode);
+ return name;
+}
+
+irr::core::stringw CColladaMeshWriter::uniqueNameForNode(const scene::ISceneNode* node) const
+{
+ irr::core::stringw name(L"node"); // (prefix, because xs::ID can't start with a number)
+ name += irr::core::stringw((long)node);
+ if ( node )
+ name += irr::core::stringw(node->getName());
+ return name;
+}
+
+irr::core::stringw CColladaMeshWriter::minTexfilterToString(bool bilinear, bool trilinear) const
+{
+ if ( trilinear )
+ return core::stringw(L"LINEAR_MIPMAP_LINEAR");
+ else if ( bilinear )
+ return core::stringw(L"LINEAR_MIPMAP_NEAREST");
+
+ return core::stringw(L"NONE");
+}
+
+inline irr::core::stringw CColladaMeshWriter::magTexfilterToString(bool bilinear, bool trilinear) const
+{
+ if ( bilinear || trilinear )
+ return core::stringw(L"LINEAR");
+
+ return core::stringw(L"NONE");
+}
+
+bool CColladaMeshWriter::isXmlNameStartChar(wchar_t c) const
+{
+ return (c >= 'A' && c <= 'Z')
+ || c == L'_'
+ || (c >= 'a' && c <= 'z')
+ || (c >= 0xC0 && c <= 0xD6)
+ || (c >= 0xD8 && c <= 0xF6)
+ || (c >= 0xF8 && c <= 0x2FF)
+ || (c >= 0x370 && c <= 0x37D)
+ || (c >= 0x37F && c <= 0x1FFF)
+ || (c >= 0x200C && c <= 0x200D)
+ || (c >= 0x2070 && c <= 0x218F)
+ || (c >= 0x2C00 && c <= 0x2FEF)
+ || (c >= 0x3001 && c <= 0xD7FF)
+ || (c >= 0xF900 && c <= 0xFDCF)
+ || (c >= 0xFDF0 && c <= 0xFFFD)
+ || (c >= 0x10000 && c <= 0xEFFFF);
+}
+
+bool CColladaMeshWriter::isXmlNameChar(wchar_t c) const
+{
+ return isXmlNameStartChar(c)
+ || c == L'-'
+ || c == L'.'
+ || (c >= '0' && c <= '9')
+ || c == 0xB7
+ || (c >= 0x0300 && c <= 0x036F)
+ || (c >= 0x203F && c <= 0x2040);
+}
+
+// Restrict the characters to a set of allowed characters in xs::NCName.
+irr::core::stringw CColladaMeshWriter::pathToNCName(const irr::io::path& path) const
+{
+ irr::core::stringw result(L"_NCNAME_"); // ensure id starts with a valid char and reduce chance of name-conflicts
+ if ( path.empty() )
+ return result;
+
+ result.append( irr::core::stringw(path) );
+
+ // We replace all characters not allowed by a replacement char
+ const wchar_t REPLACMENT = L'-';
+ for ( irr::u32 i=1; i < result.size(); ++i )
+ {
+ if ( result[i] == L':' || !isXmlNameChar(result[i]) )
+ {
+ result[i] = REPLACMENT;
+ }
+ }
+ return result;
+}
+
+irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) const
+{
+ irr::core::stringw result;
+
+ // is this a relative path?
+ if ( path.size() > 1
+ && path[0] != _IRR_TEXT('/')
+ && path[0] != _IRR_TEXT('\\')
+ && path[1] != _IRR_TEXT(':') )
+ {
+ // not already starting with "./" ?
+ if ( path[0] != _IRR_TEXT('.')
+ || path[1] != _IRR_TEXT('/') )
+ {
+ result.append(L"./");
+ }
+ }
+ result.append(path);
+
+ // TODO: make correct URI (without whitespaces)
+
+ return result;
+}
+
+void CColladaMeshWriter::writeAsset()
+{
Writer->writeElement(L"asset", false);
Writer->writeLineBreak();
@@ -111,16 +935,15 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeClosingTag(L"asset");
Writer->writeLineBreak();
+}
- // write all materials
-
- Writer->writeElement(L"library_materials", false);
- Writer->writeLineBreak();
-
+void CColladaMeshWriter::writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh)
+{
u32 i;
for (i=0; igetMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
+ strMat += meshname;
strMat += i;
Writer->writeElement(L"material", false,
@@ -136,93 +959,157 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeClosingTag(L"material");
Writer->writeLineBreak();
}
+}
- Writer->writeClosingTag(L"library_materials");
+void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material)
+{
+ Writer->writeElement(L"effect", false,
+ L"id", materialname.c_str(),
+ L"name", materialname.c_str());
+ Writer->writeLineBreak();
+ Writer->writeElement(L"profile_COMMON", false);
Writer->writeLineBreak();
- Writer->writeElement(L"library_effects", false);
+ int numTextures = 0;
+ if ( getWriteTextures() )
+ {
+ // write texture surfaces and samplers and buffer all used imagess
+ for ( int t=0; t<4; ++t )
+ {
+ const video::SMaterialLayer& layer = material.TextureLayer[t];
+ if ( !layer.Texture )
+ break;
+ ++numTextures;
+
+ if ( LibraryImages.linear_search(layer.Texture) < 0 )
+ LibraryImages.push_back( layer.Texture );
+
+ irr::core::stringw texName("tex");
+ texName += irr::core::stringw(t);
+
+ // write texture surface
+ //
+ irr::core::stringw texSurface(texName);
+ texSurface += L"-surface";
+ Writer->writeElement(L"newparam", false, L"sid", texSurface.c_str());
+ Writer->writeLineBreak();
+ //
+ Writer->writeElement(L"surface", false, L"type", L"2D");
+ Writer->writeLineBreak();
+
+ // internal_texturename
+ Writer->writeElement(L"init_from", false);
+ irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory));
+ Writer->writeText(pathToNCName(p).c_str());
+ Writer->writeClosingTag(L"init_from");
+ Writer->writeLineBreak();
+
+ // A8R8G8B8
+ Writer->writeElement(L"format", false);
+ video::ECOLOR_FORMAT format = layer.Texture->getColorFormat();
+ Writer->writeText(toString(format).c_str());
+ Writer->writeClosingTag(L"format");
+ Writer->writeLineBreak();
+ //
+ Writer->writeClosingTag(L"surface");
+ Writer->writeLineBreak();
+ //
+ Writer->writeClosingTag(L"newparam");
+ Writer->writeLineBreak();
+
+ // write texture sampler
+ //
+ irr::core::stringw texSampler(texName);
+ texSampler += L"-sampler";
+ Writer->writeElement(L"newparam", false, L"sid", texSampler.c_str());
+ Writer->writeLineBreak();
+ //
+ Writer->writeElement(L"sampler2D", false);
+ Writer->writeLineBreak();
+
+ //
+ Writer->writeElement(L"source", false);
+ Writer->writeText(texSurface.c_str());
+ Writer->writeClosingTag(L"source");
+ Writer->writeLineBreak();
+
+ // WRAP
+ Writer->writeElement(L"wrap_s", false);
+ Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapU).c_str());
+ Writer->writeClosingTag(L"wrap_s");
+ Writer->writeLineBreak();
+
+ // WRAP
+ Writer->writeElement(L"wrap_t", false);
+ Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapV).c_str());
+ Writer->writeClosingTag(L"wrap_t");
+ Writer->writeLineBreak();
+
+ // LINEAR_MIPMAP_LINEAR
+ Writer->writeElement(L"minfilter", false);
+ Writer->writeText(minTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
+ Writer->writeClosingTag(L"minfilter");
+ Writer->writeLineBreak();
+
+ // LINEAR
+ Writer->writeElement(L"magfilter", false);
+ Writer->writeText(magTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
+ Writer->writeClosingTag(L"magfilter");
+ Writer->writeLineBreak();
+
+ // TBD - actually not sure how anisotropic should be written, so for now it writes in a way
+ // that works with the way the loader reads it again.
+ if ( layer.AnisotropicFilter )
+ {
+ // LINEAR_MIPMAP_LINEAR
+ Writer->writeElement(L"mipfilter", false);
+ Writer->writeText(L"LINEAR_MIPMAP_LINEAR");
+ Writer->writeClosingTag(L"mipfilter");
+ Writer->writeLineBreak();
+ }
+
+ //
+ Writer->writeClosingTag(L"sampler2D");
+ Writer->writeLineBreak();
+ //
+ Writer->writeClosingTag(L"newparam");
+ Writer->writeLineBreak();
+ }
+ }
+
+ Writer->writeElement(L"technique", false, L"sid", L"common");
Writer->writeLineBreak();
- for (i=0; igetMeshBufferCount(); ++i)
+ E_COLLADA_TECHNIQUE_FX techFx = getProperties() ? getProperties()->getTechniqueFx(material) : ECTF_BLINN;
+ writeFxElement(meshname, material, techFx);
+
+ Writer->writeClosingTag(L"technique");
+ Writer->writeLineBreak();
+ Writer->writeClosingTag(L"profile_COMMON");
+ Writer->writeLineBreak();
+ Writer->writeClosingTag(L"effect");
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh)
+{
+ for (u32 i=0; igetMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
+ strMat += meshname;
strMat += i;
strMat += L"-fx";
- Writer->writeElement(L"effect", false,
- L"id", strMat.c_str(),
- L"name", strMat.c_str());
- Writer->writeLineBreak();
- Writer->writeElement(L"profile_COMMON", false);
- Writer->writeLineBreak();
- Writer->writeElement(L"technique", false, L"sid", L"common");
- Writer->writeLineBreak();
- Writer->writeElement(L"blinn", false);
- Writer->writeLineBreak();
-
- // write all interesting material parameters as parameter
-
- io::IAttributes* attributes = VideoDriver->createAttributesFromMaterial(
- mesh->getMeshBuffer(i)->getMaterial());
-
- // attributes must be written in fixed order
- core::stringc str;
- s32 attridx = attributes->findAttribute("Emissive");
- if ( attridx >= 0 )
- {
- writeColorAttribute(L"emission", attributes, attridx);
- }
- attridx = attributes->findAttribute("Ambient");
- if ( attridx >= 0 )
- {
- writeColorAttribute(L"ambient", attributes, attridx);
- }
- attridx = attributes->findAttribute("Diffuse");
- if ( attridx >= 0 )
- {
- writeColorAttribute(L"diffuse", attributes, attridx);
- }
- attridx = attributes->findAttribute("Specular");
- if ( attridx >= 0 )
- {
- writeColorAttribute(L"specular", attributes, attridx);
- }
- attridx = attributes->findAttribute("Shininess");
- if ( attridx >= 0 )
- {
- Writer->writeElement(L"shininess", false);
- Writer->writeLineBreak();
- Writer->writeElement(L"float", false);
-
- Writer->writeText(core::stringw(attributes->getAttributeAsString(attridx).c_str()).c_str());
-
- Writer->writeClosingTag(L"float");
- Writer->writeLineBreak();
- Writer->writeClosingTag(L"shininess");
- Writer->writeLineBreak();
- }
-
- attributes->drop();
-
- Writer->writeClosingTag(L"blinn");
- Writer->writeLineBreak();
- Writer->writeClosingTag(L"technique");
- Writer->writeLineBreak();
- Writer->writeClosingTag(L"profile_COMMON");
- Writer->writeLineBreak();
- Writer->writeClosingTag(L"effect");
- Writer->writeLineBreak();
+ video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial();
+ writeMaterialEffect(meshname, strMat, material);
}
+}
- Writer->writeClosingTag(L"library_effects");
- Writer->writeLineBreak();
+void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh)
+{
+ core::stringw meshId(meshname);
- // write mesh
-
- Writer->writeElement(L"library_geometries", false);
- Writer->writeLineBreak();
-
- Writer->writeElement(L"geometry", false, L"id", L"mesh", L"name", L"mesh");
+ Writer->writeElement(L"geometry", false, L"id", meshId.c_str(), L"name", meshId.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"mesh");
Writer->writeLineBreak();
@@ -237,7 +1124,7 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
u32 totalVertexCount = 0;
u32 totalTCoords2Count = 0;
bool needsTangents = false; // TODO: tangents not supported here yet
-
+ u32 i=0;
for (i=0; igetMeshBufferCount(); ++i)
{
totalVertexCount += mesh->getMeshBuffer(i)->getVertexCount();
@@ -252,271 +1139,16 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mesh->getMeshBufferCount()];
// write positions
-
- Writer->writeElement(L"source", false, L"id", L"mesh-Pos");
+ core::stringw meshPosId(meshId);
+ meshPosId += L"-Pos";
+ Writer->writeElement(L"source", false, L"id", meshPosId.c_str());
Writer->writeLineBreak();
- core::stringw vertexCountStr(totalVertexCount*3);
- Writer->writeElement(L"float_array", false, L"id", L"mesh-Pos-array",
- L"count", vertexCountStr.c_str());
- Writer->writeLineBreak();
-
- for (i=0; igetMeshBufferCount(); ++i)
- {
- scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
- video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
- u32 vertexCount = buffer->getVertexCount();
-
- globalIndices[i].PosStartIndex = 0;
-
- if (i!=0)
- globalIndices[i].PosStartIndex = globalIndices[i-1].PosLastIndex + 1;
-
- globalIndices[i].PosLastIndex = globalIndices[i].PosStartIndex + vertexCount - 1;
-
- switch(vtxType)
- {
- case video::EVT_STANDARD:
- {
- video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Pos).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_2TCOORDS:
- {
- video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Pos).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_TANGENTS:
- {
- video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Pos).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- }
- }
-
- Writer->writeClosingTag(L"float_array");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"technique_common", false);
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalVertexCount);
-
- Writer->writeElement(L"accessor", false, L"source", L"#mesh-Pos-array",
- L"count", vertexCountStr.c_str(), L"stride", L"3");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
- Writer->writeLineBreak();
- Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
- Writer->writeLineBreak();
- Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"accessor");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"technique_common");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"source");
- Writer->writeLineBreak();
-
- // write texture coordinates
-
- Writer->writeElement(L"source", false, L"id", L"mesh-TexCoord0");
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalVertexCount*2);
- Writer->writeElement(L"float_array", false, L"id", L"mesh-TexCoord0-array",
- L"count", vertexCountStr.c_str());
- Writer->writeLineBreak();
-
- for (i=0; igetMeshBufferCount(); ++i)
- {
- scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
- video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
- u32 vertexCount = buffer->getVertexCount();
-
- globalIndices[i].TCoord0StartIndex = 0;
-
- if (i!=0)
- globalIndices[i].TCoord0StartIndex = globalIndices[i-1].TCoord0LastIndex + 1;
-
- globalIndices[i].TCoord0LastIndex = globalIndices[i].TCoord0StartIndex + vertexCount - 1;
-
- switch(vtxType)
- {
- case video::EVT_STANDARD:
- {
- video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].TCoords).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_2TCOORDS:
- {
- video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].TCoords).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_TANGENTS:
- {
- video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].TCoords).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- }
- }
-
- Writer->writeClosingTag(L"float_array");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"technique_common", false);
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalVertexCount);
-
- Writer->writeElement(L"accessor", false, L"source", L"#mesh-TexCoord0-array",
- L"count", vertexCountStr.c_str(), L"stride", L"2");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
- Writer->writeLineBreak();
- Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"accessor");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"technique_common");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"source");
- Writer->writeLineBreak();
-
- // write normals
-
- Writer->writeElement(L"source", false, L"id", L"mesh-Normal");
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalVertexCount*3);
- Writer->writeElement(L"float_array", false, L"id", L"mesh-Normal-array",
- L"count", vertexCountStr.c_str());
- Writer->writeLineBreak();
-
- for (i=0; igetMeshBufferCount(); ++i)
- {
- scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
- video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
- u32 vertexCount = buffer->getVertexCount();
-
- globalIndices[i].NormalStartIndex = 0;
-
- if (i!=0)
- globalIndices[i].NormalStartIndex = globalIndices[i-1].NormalLastIndex + 1;
-
- globalIndices[i].NormalLastIndex = globalIndices[i].NormalStartIndex + vertexCount - 1;
-
- switch(vtxType)
- {
- case video::EVT_STANDARD:
- {
- video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_2TCOORDS:
- {
- video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- case video::EVT_TANGENTS:
- {
- video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
- Writer->writeLineBreak();
- }
- }
- break;
- }
- }
-
- Writer->writeClosingTag(L"float_array");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"technique_common", false);
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalVertexCount);
-
- Writer->writeElement(L"accessor", false, L"source", L"#mesh-Normal-array",
- L"count", vertexCountStr.c_str(), L"stride", L"3");
- Writer->writeLineBreak();
-
- Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
- Writer->writeLineBreak();
- Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
- Writer->writeLineBreak();
- Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"accessor");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"technique_common");
- Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"source");
- Writer->writeLineBreak();
-
- // write second set of texture coordinates
-
- if (totalTCoords2Count)
- {
- Writer->writeElement(L"source", false, L"id", L"mesh-TexCoord1");
- Writer->writeLineBreak();
-
- vertexCountStr = core::stringw(totalTCoords2Count*2);
- Writer->writeElement(L"float_array", false, L"id", L"mesh-TexCoord1-array",
- L"count", vertexCountStr.c_str());
+ core::stringw vertexCountStr(totalVertexCount*3);
+ core::stringw meshPosArrayId(meshPosId);
+ meshPosArrayId += L"-array";
+ Writer->writeElement(L"float_array", false, L"id", meshPosArrayId.c_str(),
+ L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
for (i=0; igetMeshBufferCount(); ++i)
@@ -525,31 +1157,46 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
- if (hasSecondTextureCoordinates(vtxType))
+ globalIndices[i].PosStartIndex = 0;
+
+ if (i!=0)
+ globalIndices[i].PosStartIndex = globalIndices[i-1].PosLastIndex + 1;
+
+ globalIndices[i].PosLastIndex = globalIndices[i].PosStartIndex + vertexCount - 1;
+
+ switch(vtxType)
{
- globalIndices[i].TCoord1StartIndex = 0;
-
- if (i!=0 && globalIndices[i-1].TCoord1LastIndex != -1)
- globalIndices[i].TCoord1StartIndex = globalIndices[i-1].TCoord1LastIndex + 1;
-
- globalIndices[i].TCoord1LastIndex = globalIndices[i].TCoord1StartIndex + vertexCount - 1;
-
- switch(vtxType)
+ case video::EVT_STANDARD:
{
- case video::EVT_2TCOORDS:
+ video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
+ for (u32 j=0; jgetVertices();
- for (u32 j=0; jwriteText(toString(vtx[j].TCoords2).c_str());
- Writer->writeLineBreak();
- }
+ Writer->writeText(toString(vtx[j].Pos).c_str());
+ Writer->writeLineBreak();
}
- break;
- default:
- break;
}
- } // end this buffer has 2 texture coordinates
+ break;
+ case video::EVT_2TCOORDS:
+ {
+ video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].Pos).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ case video::EVT_TANGENTS:
+ {
+ video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].Pos).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ }
}
Writer->writeClosingTag(L"float_array");
@@ -558,10 +1205,100 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
- vertexCountStr = core::stringw(totalTCoords2Count);
+ vertexCountStr = core::stringw(totalVertexCount);
- Writer->writeElement(L"accessor", false, L"source", L"#mesh-TexCoord1-array",
- L"count", vertexCountStr.c_str(), L"stride", L"2");
+ Writer->writeElement(L"accessor", false, L"source", toRef(meshPosArrayId).c_str(),
+ L"count", vertexCountStr.c_str(), L"stride", L"3");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"accessor");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"source");
+ Writer->writeLineBreak();
+
+ // write texture coordinates
+
+ core::stringw meshTexCoord0Id(meshId);
+ meshTexCoord0Id += L"-TexCoord0";
+ Writer->writeElement(L"source", false, L"id", meshTexCoord0Id.c_str());
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalVertexCount*2);
+ core::stringw meshTexCoordArrayId(meshTexCoord0Id);
+ meshTexCoordArrayId += L"-array";
+ Writer->writeElement(L"float_array", false, L"id", meshTexCoordArrayId.c_str(),
+ L"count", vertexCountStr.c_str());
+ Writer->writeLineBreak();
+
+ for (i=0; igetMeshBufferCount(); ++i)
+ {
+ scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
+ video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
+ u32 vertexCount = buffer->getVertexCount();
+
+ globalIndices[i].TCoord0StartIndex = 0;
+
+ if (i!=0)
+ globalIndices[i].TCoord0StartIndex = globalIndices[i-1].TCoord0LastIndex + 1;
+
+ globalIndices[i].TCoord0LastIndex = globalIndices[i].TCoord0StartIndex + vertexCount - 1;
+
+ switch(vtxType)
+ {
+ case video::EVT_STANDARD:
+ {
+ video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
+ for (u32 j=0; jwriteText(uvToString(vtx[j].TCoords).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ case video::EVT_2TCOORDS:
+ {
+ video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
+ for (u32 j=0; jwriteText(uvToString(vtx[j].TCoords).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ case video::EVT_TANGENTS:
+ {
+ video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
+ for (u32 j=0; jwriteText(uvToString(vtx[j].TCoords).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ }
+ }
+
+ Writer->writeClosingTag(L"float_array");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalVertexCount);
+
+ Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoordArrayId).c_str(),
+ L"count", vertexCountStr.c_str(), L"stride", L"2");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
@@ -575,6 +1312,169 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
+ Writer->writeClosingTag(L"source");
+ Writer->writeLineBreak();
+
+ // write normals
+ core::stringw meshNormalId(meshId);
+ meshNormalId += L"-Normal";
+ Writer->writeElement(L"source", false, L"id", meshNormalId.c_str());
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalVertexCount*3);
+ core::stringw meshNormalArrayId(meshNormalId);
+ meshNormalArrayId += L"-array";
+ Writer->writeElement(L"float_array", false, L"id", meshNormalArrayId.c_str(),
+ L"count", vertexCountStr.c_str());
+ Writer->writeLineBreak();
+
+ for (i=0; igetMeshBufferCount(); ++i)
+ {
+ scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
+ video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
+ u32 vertexCount = buffer->getVertexCount();
+
+ globalIndices[i].NormalStartIndex = 0;
+
+ if (i!=0)
+ globalIndices[i].NormalStartIndex = globalIndices[i-1].NormalLastIndex + 1;
+
+ globalIndices[i].NormalLastIndex = globalIndices[i].NormalStartIndex + vertexCount - 1;
+
+ switch(vtxType)
+ {
+ case video::EVT_STANDARD:
+ {
+ video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ case video::EVT_2TCOORDS:
+ {
+ video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ case video::EVT_TANGENTS:
+ {
+ video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].Normal).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ }
+ }
+
+ Writer->writeClosingTag(L"float_array");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalVertexCount);
+
+ Writer->writeElement(L"accessor", false, L"source", toRef(meshNormalArrayId).c_str(),
+ L"count", vertexCountStr.c_str(), L"stride", L"3");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"accessor");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"source");
+ Writer->writeLineBreak();
+
+ // write second set of texture coordinates
+ core::stringw meshTexCoord1Id(meshId);
+ meshTexCoord1Id += L"-TexCoord1";
+ if (totalTCoords2Count)
+ {
+ Writer->writeElement(L"source", false, L"id", meshTexCoord1Id.c_str());
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalTCoords2Count*2);
+ core::stringw meshTexCoord1ArrayId(meshTexCoord1Id);
+ meshTexCoord1ArrayId += L"-array";
+ Writer->writeElement(L"float_array", false, L"id", meshTexCoord1ArrayId.c_str(),
+ L"count", vertexCountStr.c_str());
+ Writer->writeLineBreak();
+
+ for (i=0; igetMeshBufferCount(); ++i)
+ {
+ scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
+ video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
+ u32 vertexCount = buffer->getVertexCount();
+
+ if (hasSecondTextureCoordinates(vtxType))
+ {
+ globalIndices[i].TCoord1StartIndex = 0;
+
+ if (i!=0 && globalIndices[i-1].TCoord1LastIndex != -1)
+ globalIndices[i].TCoord1StartIndex = globalIndices[i-1].TCoord1LastIndex + 1;
+
+ globalIndices[i].TCoord1LastIndex = globalIndices[i].TCoord1StartIndex + vertexCount - 1;
+
+ switch(vtxType)
+ {
+ case video::EVT_2TCOORDS:
+ {
+ video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
+ for (u32 j=0; jwriteText(toString(vtx[j].TCoords2).c_str());
+ Writer->writeLineBreak();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } // end this buffer has 2 texture coordinates
+ }
+
+ Writer->writeClosingTag(L"float_array");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ vertexCountStr = core::stringw(totalTCoords2Count);
+
+ Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoord1ArrayId).c_str(),
+ L"count", vertexCountStr.c_str(), L"stride", L"2");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
+ Writer->writeLineBreak();
+ Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"accessor");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
}
@@ -584,12 +1484,13 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
// TODO
// write vertices
-
- Writer->writeElement(L"vertices", false, L"id", L"mesh-Vtx");
+ core::stringw meshVtxId(meshId);
+ meshVtxId += L"-Vtx";
+ Writer->writeElement(L"vertices", false, L"id", meshVtxId.c_str());
Writer->writeLineBreak();
- Writer->writeElement(L"input", true, L"semantic", L"POSITION", L"source", L"#mesh-Pos");
- Writer->writeLineBreak();
+ Writer->writeElement(L"input", true, L"semantic", L"POSITION", L"source", toRef(meshPosId).c_str());
+ Writer->writeLineBreak();
Writer->writeClosingTag(L"vertices");
Writer->writeLineBreak();
@@ -603,23 +1504,24 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
const u32 polyCount = buffer->getIndexCount() / 3;
core::stringw strPolyCount(polyCount);
core::stringw strMat = "mat";
+ strMat += meshname;
strMat += i;
Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(),
L"material", strMat.c_str());
Writer->writeLineBreak();
- Writer->writeElement(L"input", true, L"semantic", L"VERTEX", L"source", L"#mesh-Vtx", L"offset", L"0");
+ Writer->writeElement(L"input", true, L"semantic", L"VERTEX", L"source", toRef(meshVtxId).c_str(), L"offset", L"0");
Writer->writeLineBreak();
- Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", L"#mesh-TexCoord0", L"offset", L"1");
+ Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord0Id).c_str(), L"offset", L"1", L"set", L"0");
Writer->writeLineBreak();
- Writer->writeElement(L"input", true, L"semantic", L"NORMAL", L"source", L"#mesh-Normal", L"offset", L"2");
+ Writer->writeElement(L"input", true, L"semantic", L"NORMAL", L"source", toRef(meshNormalId).c_str(), L"offset", L"2");
Writer->writeLineBreak();
bool has2ndTexCoords = hasSecondTextureCoordinates(buffer->getVertexType());
if (has2ndTexCoords)
{
- Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", L"#mesh-TexCoord1", L"idx", L"3");
+ Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord1Id).c_str(), L"idx", L"3");
Writer->writeLineBreak();
}
@@ -685,72 +1587,324 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
}
// close mesh and geometry
-
+ delete [] globalIndices;
Writer->writeClosingTag(L"mesh");
Writer->writeLineBreak();
Writer->writeClosingTag(L"geometry");
Writer->writeLineBreak();
-
- Writer->writeClosingTag(L"library_geometries");
- Writer->writeLineBreak();
-
- // close everything
-
- Writer->writeClosingTag(L"COLLADA");
- Writer->drop();
-
- delete [] globalIndices;
-
- return true;
}
-
-bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const
+void CColladaMeshWriter::writeLibraryImages()
{
- return type == video::EVT_2TCOORDS;
+ if ( getWriteTextures() && !LibraryImages.empty() )
+ {
+ Writer->writeElement(L"library_images", false);
+ Writer->writeLineBreak();
+
+ for ( irr::u32 i=0; igetRelativeFilename(LibraryImages[i]->getName().getPath(), Directory));
+ //
+ irr::core::stringw ncname(pathToNCName(p));
+ Writer->writeElement(L"image", false, L"id", ncname.c_str(), L"name", ncname.c_str());
+ Writer->writeLineBreak();
+ // ../flowers/rose01.jpg
+ Writer->writeElement(L"init_from", false);
+ Writer->writeText(pathToURI(p).c_str());
+ Writer->writeClosingTag(L"init_from");
+ Writer->writeLineBreak();
+ //
+ Writer->writeClosingTag(L"image");
+ Writer->writeLineBreak();
+ }
+
+ Writer->writeClosingTag(L"library_images");
+ Writer->writeLineBreak();
+ }
}
-irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector3df& vec) const
+void CColladaMeshWriter::writeColorElement(const video::SColorf & col, bool writeAlpha)
{
- c8 tmpbuf[255];
- snprintf(tmpbuf, 255, "%f %f %f", vec.X, vec.Y, vec.Z);
- core::stringw str = tmpbuf;
-
- return str;
-}
-
-irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector2df& vec) const
-{
- c8 tmpbuf[255];
- snprintf(tmpbuf, 255, "%f %f", vec.X, vec.Y);
- core::stringw str = tmpbuf;
-
- return str;
-}
-
-inline irr::core::stringw CColladaMeshWriter::toString(const irr::video::SColorf& colorf) const
-{
- c8 tmpbuf[255];
- snprintf(tmpbuf, 255, "%f %f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue(), colorf.getAlpha());
- core::stringw str = tmpbuf;
-
- return str;
-}
-
-void CColladaMeshWriter::writeColorAttribute(wchar_t * parentTag, io::IAttributes* attributes, s32 attridx)
-{
- Writer->writeElement(parentTag, false);
- Writer->writeLineBreak();
-
Writer->writeElement(L"color", false);
- irr::core::stringw str( toString(attributes->getAttributeAsColorf(attridx)) );
+ irr::core::stringw str( toString(col, writeAlpha) );
Writer->writeText(str.c_str());
Writer->writeClosingTag(L"color");
Writer->writeLineBreak();
+}
- Writer->writeClosingTag(parentTag);
+void CColladaMeshWriter::writeColorElement(const video::SColor & col, bool writeAlpha)
+{
+ writeColorElement( video::SColorf(col), writeAlpha );
+}
+
+void CColladaMeshWriter::writeAmbientLightElement(const video::SColorf & col)
+{
+ Writer->writeElement(L"light", false, L"id", L"ambientlight");
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"technique_common", false);
+ Writer->writeLineBreak();
+
+ Writer->writeElement(L"ambient", false);
+ Writer->writeLineBreak();
+
+ writeColorElement(col, false);
+
+ Writer->writeClosingTag(L"ambient");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"technique_common");
+ Writer->writeLineBreak();
+
+ Writer->writeClosingTag(L"light");
+ Writer->writeLineBreak();
+}
+
+s32 CColladaMeshWriter::getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs)
+{
+ if ( !getWriteTextures()
+ || !getProperties() )
+ return -1;
+
+ s32 idx = getProperties()->getTextureIdx(material, cs);
+ if ( idx >= 0 && !material.TextureLayer[idx].Texture )
+ return -1;
+
+ return idx;
+}
+
+video::SColor CColladaMeshWriter::getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType)
+{
+ switch ( colType )
+ {
+ case ECIC_NONE:
+ return video::SColor(255, 0, 0, 0);
+
+ case ECIC_CUSTOM:
+ return getProperties()->getCustomColor(material, cs);
+
+ case ECIC_DIFFUSE:
+ return material.DiffuseColor;
+
+ case ECIC_AMBIENT:
+ return material.AmbientColor;
+
+ case ECIC_EMISSIVE:
+ return material.EmissiveColor;
+
+ case ECIC_SPECULAR:
+ return material.SpecularColor;
+ }
+ return video::SColor(255, 0, 0, 0);
+}
+
+void CColladaMeshWriter::writeTextureSampler(const irr::core::stringw& meshname, s32 textureIdx)
+{
+ irr::core::stringw sampler(L"tex");
+ sampler += irr::core::stringw(textureIdx);
+ sampler += L"-sampler";
+
+ //
+ core::stringw meshTexCoordId(meshname);
+ meshTexCoordId += L"-TexCoord0"; // TODO: need to handle second UV-set
+ Writer->writeElement(L"texture", true, L"texture", sampler.c_str(), L"texcoord", meshTexCoordId.c_str() );
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeFxElement(const irr::core::stringw& meshname, const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx)
+{
+ core::stringw fxLabel;
+ bool writeEmission = true;
+ bool writeAmbient = true;
+ bool writeDiffuse = true;
+ bool writeSpecular = true;
+ bool writeShininess = true;
+ bool writeReflective = true;
+ bool writeReflectivity = true;
+ bool writeTransparent = true;
+ bool writeTransparency = true;
+ bool writeIndexOfRefraction = true;
+ switch ( techFx )
+ {
+ case ECTF_BLINN:
+ fxLabel = L"blinn";
+ break;
+ case ECTF_PHONG:
+ fxLabel = L"phong";
+ break;
+ case ECTF_LAMBERT:
+ fxLabel = L"lambert";
+ writeSpecular = false;
+ writeShininess = false;
+ break;
+ case ECTF_CONSTANT:
+ fxLabel = L"constant";
+ writeAmbient = false;
+ writeDiffuse = false;
+ writeSpecular = false;
+ writeShininess = false;
+ break;
+ }
+
+ Writer->writeElement(fxLabel.c_str(), false);
+ Writer->writeLineBreak();
+
+ // write all interesting material parameters
+ // attributes must be written in fixed order
+ if ( getProperties() )
+ {
+ if ( writeEmission )
+ {
+ writeColorFx(meshname, material, L"emission", ECCS_EMISSIVE);
+ }
+
+ if ( writeAmbient )
+ {
+ writeColorFx(meshname, material, L"ambient", ECCS_AMBIENT);
+ }
+
+ if ( writeDiffuse )
+ {
+ writeColorFx(meshname, material, L"diffuse", ECCS_DIFFUSE);
+ }
+
+ if ( writeSpecular )
+ {
+ writeColorFx(meshname, material, L"specular", ECCS_SPECULAR);
+ }
+
+ if ( writeShininess )
+ {
+ Writer->writeElement(L"shininess", false);
+ Writer->writeLineBreak();
+ writeFloatElement(material.Shininess);
+ Writer->writeClosingTag(L"shininess");
+ Writer->writeLineBreak();
+ }
+
+ if ( writeReflective )
+ {
+ writeColorFx(meshname, material, L"reflective", ECCS_REFLECTIVE);
+ }
+
+ if ( writeReflectivity )
+ {
+ f32 t = getProperties()->getReflectivity(material);
+ if ( t >= 0.f )
+ {
+ // 1.000000
+ Writer->writeElement(L"reflectivity", false);
+ Writer->writeLineBreak();
+ writeFloatElement(t);
+ Writer->writeClosingTag(L"reflectivity");
+ Writer->writeLineBreak();
+ }
+ }
+
+ if ( writeTransparent )
+ {
+ E_COLLADA_TRANSPARENT_FX transparentFx = getProperties()->getTransparentFx(material);
+ writeColorFx(meshname, material, L"transparent", ECCS_TRANSPARENT, L"opaque", toString(transparentFx).c_str());
+ }
+
+ if ( writeTransparency )
+ {
+ f32 t = getProperties()->getTransparency(material);
+ if ( t >= 0.f )
+ {
+ // 1.000000
+ Writer->writeElement(L"transparency", false);
+ Writer->writeLineBreak();
+ writeFloatElement(t);
+ Writer->writeClosingTag(L"transparency");
+ Writer->writeLineBreak();
+ }
+ }
+
+ if ( writeIndexOfRefraction )
+ {
+ f32 t = getProperties()->getIndexOfRefraction(material);
+ if ( t >= 0.f )
+ {
+ Writer->writeElement(L"index_of_refraction", false);
+ Writer->writeLineBreak();
+ writeFloatElement(t);
+ Writer->writeClosingTag(L"index_of_refraction");
+ Writer->writeLineBreak();
+ }
+ }
+ }
+
+
+ Writer->writeClosingTag(fxLabel.c_str());
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeColorFx(const irr::core::stringw& meshname, const video::SMaterial & material, const wchar_t * colorname, E_COLLADA_COLOR_SAMPLER cs, const wchar_t* attr1Name, const wchar_t* attr1Value)
+{
+ irr::s32 idx = getCheckedTextureIdx(material, cs);
+ E_COLLADA_IRR_COLOR colType = idx < 0 ? getProperties()->getColorMapping(material, cs) : ECIC_NONE;
+ if ( idx >= 0 || colType != ECIC_NONE )
+ {
+ Writer->writeElement(colorname, false, attr1Name, attr1Value);
+ Writer->writeLineBreak();
+ if ( idx >= 0 )
+ writeTextureSampler( meshname, idx);
+ else
+ writeColorElement(getColorMapping(material, cs, colType));
+ Writer->writeClosingTag(colorname);
+ Writer->writeLineBreak();
+ }
+}
+
+void CColladaMeshWriter::writeFloatElement(irr::f32 value)
+{
+ Writer->writeElement(L"float", false);
+ Writer->writeText(core::stringw(value).c_str());
+ Writer->writeClosingTag(L"float");
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle)
+{
+ Writer->writeElement(L"rotate", false);
+ irr::core::stringw txt(axis.X);
+ txt += L" ";
+ txt += irr::core::stringw(axis.Y);
+ txt += L" ";
+ txt += irr::core::stringw(axis.Z);
+ txt += L" ";
+ txt += irr::core::stringw(angle);
+ Writer->writeText(txt.c_str());
+ Writer->writeClosingTag(L"rotate");
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeScaleElement(const irr::core::vector3df& scale)
+{
+ Writer->writeElement(L"scale", false);
+ irr::core::stringw txt(scale.X);
+ txt += L" ";
+ txt += irr::core::stringw(scale.Y);
+ txt += L" ";
+ txt += irr::core::stringw(scale.Z);
+ Writer->writeText(txt.c_str());
+ Writer->writeClosingTag(L"scale");
+ Writer->writeLineBreak();
+}
+
+void CColladaMeshWriter::writeTranslateElement(const irr::core::vector3df& translate)
+{
+ Writer->writeElement(L"translate", false);
+ irr::core::stringw txt(translate.X);
+ txt += L" ";
+ txt += irr::core::stringw(translate.Y);
+ txt += L" ";
+ txt += irr::core::stringw(translate.Z);
+ Writer->writeText(txt.c_str());
+ Writer->writeClosingTag(L"translate");
Writer->writeLineBreak();
}
diff --git a/source/Irrlicht/CColladaMeshWriter.h b/source/Irrlicht/CColladaMeshWriter.h
index fe7619a1..698d75be 100644
--- a/source/Irrlicht/CColladaMeshWriter.h
+++ b/source/Irrlicht/CColladaMeshWriter.h
@@ -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 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::Node MeshNode;
+ core::map Meshes;
+
+ struct ColladaLight
+ {
+ ColladaLight() {}
+ irr::core::stringw Name;
+ };
+ typedef core::map::Node LightNode;
+ core::map LightNodes;
};
@@ -76,3 +180,4 @@ protected:
#endif
+
diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp
index 788a3b6b..abdc2ad1 100644
--- a/source/Irrlicht/CD3D9Driver.cpp
+++ b/source/Irrlicht/CD3D9Driver.cpp
@@ -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;
diff --git a/source/Irrlicht/CDummyTransformationSceneNode.cpp b/source/Irrlicht/CDummyTransformationSceneNode.cpp
index d279a783..ddc0d7fb 100644
--- a/source/Irrlicht/CDummyTransformationSceneNode.cpp
+++ b/source/Irrlicht/CDummyTransformationSceneNode.cpp
@@ -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
diff --git a/source/Irrlicht/CDummyTransformationSceneNode.h b/source/Irrlicht/CDummyTransformationSceneNode.h
index 94650bc5..607fcd51 100644
--- a/source/Irrlicht/CDummyTransformationSceneNode.h
+++ b/source/Irrlicht/CDummyTransformationSceneNode.h
@@ -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;
diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp
index 8bdb8a0b..afa4e564 100644
--- a/source/Irrlicht/CFileSystem.cpp
+++ b/source/Irrlicht/CFileSystem.cpp
@@ -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 list1, list2;
- path1.split(list1, _IRR_TEXT("/\\"), 2);
- path2.split(list2, _IRR_TEXT("/\\"), 2);
- u32 i=0;
- core::list::ConstIterator it1,it2;
- it1=list1.begin();
- it2=list2.begin();
- for (; i list1, list2;
+ path1.split(list1, _IRR_TEXT("/\\"), 2);
+ path2.split(list2, _IRR_TEXT("/\\"), 2);
+ u32 i=0;
+ core::list::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 (; igetFont(EGDF_BUTTON);
+ IGUIFont* font = getActiveFont();
core::rect 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)
diff --git a/source/Irrlicht/CGUIButton.h b/source/Irrlicht/CGUIButton.h
index c3a3336e..23a84250 100644
--- a/source/Irrlicht/CGUIButton.h
+++ b/source/Irrlicht/CGUIButton.h
@@ -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);
diff --git a/source/Irrlicht/CGUIComboBox.cpp b/source/Irrlicht/CGUIComboBox.cpp
index 3ab01eca..50470e25 100644
--- a/source/Irrlicht/CGUIComboBox.cpp
+++ b/source/Irrlicht/CGUIComboBox.cpp
@@ -24,7 +24,7 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect 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();
diff --git a/source/Irrlicht/CGUIComboBox.h b/source/Irrlicht/CGUIComboBox.h
index 1c656d8d..77e8a0ff 100644
--- a/source/Irrlicht/CGUIComboBox.h
+++ b/source/Irrlicht/CGUIComboBox.h
@@ -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;
};
diff --git a/source/Irrlicht/CGUIEditBox.cpp b/source/Irrlicht/CGUIEditBox.cpp
index 756100c3..9c8eea7c 100644
--- a/source/Irrlicht/CGUIEditBox.cpp
+++ b/source/Irrlicht/CGUIEditBox.cpp
@@ -32,7 +32,7 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect& 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 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"));
diff --git a/source/Irrlicht/CGUIEditBox.h b/source/Irrlicht/CGUIEditBox.h
index 39ae7498..88fb0f28 100644
--- a/source/Irrlicht/CGUIEditBox.h
+++ b/source/Irrlicht/CGUIEditBox.h
@@ -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;
diff --git a/source/Irrlicht/CGUIListBox.cpp b/source/Irrlicht/CGUIListBox.cpp
index bb7c25ec..c300233b 100644
--- a/source/Irrlicht/CGUIListBox.cpp
+++ b/source/Irrlicht/CGUIListBox.cpp
@@ -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:
diff --git a/source/Irrlicht/CGUIModalScreen.cpp b/source/Irrlicht/CGUIModalScreen.cpp
index 895471ed..ca352277 100644
--- a/source/Irrlicht/CGUIModalScreen.cpp
+++ b/source/Irrlicht/CGUIModalScreen.cpp
@@ -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() )
diff --git a/source/Irrlicht/CGUIScrollBar.cpp b/source/Irrlicht/CGUIScrollBar.cpp
index 628ac7e8..4629144d 100644
--- a/source/Irrlicht/CGUIScrollBar.cpp
+++ b/source/Irrlicht/CGUIScrollBar.cpp
@@ -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;
diff --git a/source/Irrlicht/CGUISkin.cpp b/source/Irrlicht/CGUISkin.cpp
index db827eea..8f595176 100644
--- a/source/Irrlicht/CGUISkin.cpp
+++ b/source/Irrlicht/CGUISkin.cpp
@@ -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 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);
}
}
diff --git a/source/Irrlicht/CGUISpinBox.cpp b/source/Irrlicht/CGUISpinBox.cpp
index 83b63c98..4042391b 100644
--- a/source/Irrlicht/CGUISpinBox.cpp
+++ b/source/Irrlicht/CGUISpinBox.cpp
@@ -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;
}
diff --git a/source/Irrlicht/CGUISpinBox.h b/source/Irrlicht/CGUISpinBox.h
index 50d98ecd..cf20aa10 100644
--- a/source/Irrlicht/CGUISpinBox.h
+++ b/source/Irrlicht/CGUISpinBox.h
@@ -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);
diff --git a/source/Irrlicht/CGUIStaticText.cpp b/source/Irrlicht/CGUIStaticText.cpp
index 4ae7b6a3..42445ecd 100644
--- a/source/Irrlicht/CGUIStaticText.cpp
+++ b/source/Irrlicht/CGUIStaticText.cpp
@@ -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; igetDimension(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;
diff --git a/source/Irrlicht/CGUIStaticText.h b/source/Irrlicht/CGUIStaticText.h
index 077dec6a..7cd50e93 100644
--- a/source/Irrlicht/CGUIStaticText.h
+++ b/source/Irrlicht/CGUIStaticText.h
@@ -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;
diff --git a/source/Irrlicht/CGUITable.cpp b/source/Irrlicht/CGUITable.cpp
index a1718d17..3c416a76 100644
--- a/source/Irrlicht/CGUITable.cpp
+++ b/source/Irrlicht/CGUITable.cpp
@@ -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:
diff --git a/source/Irrlicht/CGUITreeView.cpp b/source/Irrlicht/CGUITreeView.cpp
index ef609e81..b5b8a838 100644
--- a/source/Irrlicht/CGUITreeView.cpp
+++ b/source/Irrlicht/CGUITreeView.cpp
@@ -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;
diff --git a/source/Irrlicht/CIrrDeviceStub.cpp b/source/Irrlicht/CIrrDeviceStub.cpp
index f074ae21..d2274696 100644
--- a/source/Irrlicht/CIrrDeviceStub.cpp
+++ b/source/Irrlicht/CIrrDeviceStub.cpp
@@ -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)
{
diff --git a/source/Irrlicht/CIrrDeviceStub.h b/source/Irrlicht/CIrrDeviceStub.h
index 7814ccc6..c4da62c5 100644
--- a/source/Irrlicht/CIrrDeviceStub.h
+++ b/source/Irrlicht/CIrrDeviceStub.h
@@ -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;
diff --git a/source/Irrlicht/COctreeSceneNode.cpp b/source/Irrlicht/COctreeSceneNode.cpp
index 940c16ae..30072465 100644
--- a/source/Irrlicht/COctreeSceneNode.cpp
+++ b/source/Irrlicht/COctreeSceneNode.cpp
@@ -289,6 +289,8 @@ const core::aabbox3d& 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; igetMeshBufferCount(); ++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; igetMeshBufferCount(); ++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; vgetVertexCount(); ++v)
- nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
+ switch (b->getVertexType())
+ {
+ case video::EVT_STANDARD:
+ for (v=0; vgetVertexCount(); ++v)
+ nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
+ break;
+ case video::EVT_2TCOORDS:
+ for (v=0; vgetVertexCount(); ++v)
+ nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
+ break;
+ case video::EVT_TANGENTS:
+ for (v=0; vgetVertexCount(); ++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; vgetVertexCount(); ++v)
- nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
+ switch (b->getVertexType())
+ {
+ case video::EVT_STANDARD:
+ for (v=0; vgetVertexCount(); ++v)
+ nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
+ break;
+ case video::EVT_2TCOORDS:
+ for (v=0; vgetVertexCount(); ++v)
+ nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
+ break;
+ case video::EVT_TANGENTS:
+ for (v=0; vgetVertexCount(); ++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; igetMeshBufferCount(); ++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; vgetVertexCount(); ++v)
- nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
+ switch (b->getVertexType())
+ {
+ case video::EVT_STANDARD:
+ for (v=0; vgetVertexCount(); ++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; vgetVertexCount(); ++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; vgetVertexCount(); ++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);
diff --git a/source/Irrlicht/CParticleSystemSceneNode.h b/source/Irrlicht/CParticleSystemSceneNode.h
index 74f0bfc7..ffecefd3 100644
--- a/source/Irrlicht/CParticleSystemSceneNode.h
+++ b/source/Irrlicht/CParticleSystemSceneNode.h
@@ -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 AffectorList;
diff --git a/source/Irrlicht/CSceneCollisionManager.cpp b/source/Irrlicht/CSceneCollisionManager.cpp
index 98c080f2..a5825174 100644
--- a/source/Irrlicht/CSceneCollisionManager.cpp
+++ b/source/Irrlicht/CSceneCollisionManager.cpp
@@ -358,6 +358,9 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray,
}
s32 totalcnt = selector->getTriangleCount();
+ if ( totalcnt <= 0 )
+ return false;
+
Triangles.set_used(totalcnt);
s32 cnt = 0;
@@ -889,7 +892,7 @@ core::position2d 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;
diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp
index a2adb1e0..aedc5f5b 100644
--- a/source/Irrlicht/CSceneManager.cpp
+++ b/source/Irrlicht/CSceneManager.cpp
@@ -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
diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h
index 7d34ada8..ea939886 100644
--- a/source/Irrlicht/CSceneManager.h
+++ b/source/Irrlicht/CSceneManager.h
@@ -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();
diff --git a/source/Irrlicht/CWaterSurfaceSceneNode.cpp b/source/Irrlicht/CWaterSurfaceSceneNode.cpp
index c20a3fb9..99d23945 100644
--- a/source/Irrlicht/CWaterSurfaceSceneNode.cpp
+++ b/source/Irrlicht/CWaterSurfaceSceneNode.cpp
@@ -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);
}
diff --git a/source/Irrlicht/CZipReader.cpp b/source/Irrlicht/CZipReader.cpp
index 676edf51..2e096648 100644
--- a/source/Irrlicht/CZipReader.cpp
+++ b/source/Irrlicht/CZipReader.cpp
@@ -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
diff --git a/source/Irrlicht/Irrlicht-gcc.cbp b/source/Irrlicht/Irrlicht-gcc.cbp
index 30dad9ae..6e4056e7 100644
--- a/source/Irrlicht/Irrlicht-gcc.cbp
+++ b/source/Irrlicht/Irrlicht-gcc.cbp
@@ -8,7 +8,7 @@
-
+
@@ -52,7 +52,7 @@
-
+
@@ -94,7 +94,7 @@
-
+
@@ -455,6 +455,7 @@
+
diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj b/source/Irrlicht/Irrlicht10.0.vcxproj
index aed1bad6..bbc2205b 100644
--- a/source/Irrlicht/Irrlicht10.0.vcxproj
+++ b/source/Irrlicht/Irrlicht10.0.vcxproj
@@ -827,6 +827,7 @@
+
diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj.filters b/source/Irrlicht/Irrlicht10.0.vcxproj.filters
index 0a8f6e05..b95eca19 100644
--- a/source/Irrlicht/Irrlicht10.0.vcxproj.filters
+++ b/source/Irrlicht/Irrlicht10.0.vcxproj.filters
@@ -1339,6 +1339,9 @@
include\video
+
+ include
+
diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile
index e4dab7c2..d75b838d 100644
--- a/source/Irrlicht/Makefile
+++ b/source/Irrlicht/Makefile
@@ -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
diff --git a/source/Irrlicht/os.cpp b/source/Irrlicht/os.cpp
index ed347779..18e15cd9 100644
--- a/source/Irrlicht/os.cpp
+++ b/source/Irrlicht/os.cpp
@@ -222,9 +222,9 @@ namespace os
}
//! resets the randomizer
- void Randomizer::reset()
+ void Randomizer::reset(s32 value)
{
- seed = 0x0f0f0f0f;
+ seed = value;
}
diff --git a/source/Irrlicht/os.h b/source/Irrlicht/os.h
index 79a0ce01..fa7fb797 100644
--- a/source/Irrlicht/os.h
+++ b/source/Irrlicht/os.h
@@ -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();
diff --git a/tests/2dmaterial.cpp b/tests/2dmaterial.cpp
index eac04cd3..d51351cc 100644
--- a/tests/2dmaterial.cpp
+++ b/tests/2dmaterial.cpp
@@ -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 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 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 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& position,
- video::SColor color, bool hcenter=false,
- bool vcenter=false, const core::rect* clip=0)
+ //! draws an text and clips it to the specified rectangle if wanted
+ virtual void draw(const core::stringw& text, const core::rect& position,
+ video::SColor color, bool hcenter=false,
+ bool vcenter=false, const core::rect* clip=0)
{
if (!Driver) return;
-
+
core::position2d offset = position.UpperLeftCorner;
core::dimension2d 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 indices(text_size);
+ core::array indices(text_size);
core::array offsets(text_size);
- core::array fallback;
+ core::array fallback;
fallback.set_used(text_size);
-
+
for (u32 i = 0; i& sprites = SpriteBank->getSprites();
- core::array< core::rect >& positions = SpriteBank->getPositions();
+ const int indiceAmount = indices.size();
+ core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
+ core::array< core::rect >& positions = SpriteBank->getPositions();
core::array< gui::SGUISprite >* fallback_sprites;
core::array< core::rect >* 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= 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 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 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 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 getDimension(const wchar_t* text) const
+ //! returns the dimension of a text
+ virtual core::dimension2d getDimension(const wchar_t* text) const
{
assert(Areas.size() > 0);
-
+
core::dimension2d dim(0, 0);
core::dimension2d 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::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 Areas;
- /** The maximum values of all digits, used in monospace_digits. */
- mutable SFontArea m_max_digit_area;
- std::map CharacterMap;
- video::IVideoDriver* Driver;
- gui::IGUISpriteBank* SpriteBank;
- gui::IGUIEnvironment* Environment;
- u32 WrongCharacter;
- s32 MaxHeight;
- s32 GlobalKerningWidth, GlobalKerningHeight;
+ core::array Areas;
+ /** The maximum values of all digits, used in monospace_digits. */
+ mutable SFontArea m_max_digit_area;
+ std::map 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(0,0));
-
+
core::rect imp1(349,15,385,78);
core::rect 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(0,0,342,224), 0,
- video::SColor(255,255,255,255), true);
-
+ core::rect(0,0,342,224), 0,
+ video::SColor(255,255,255,255), true);
+
// draw flying imp
driver->draw2DImage(images, core::position2d(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(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(10,10,108,48),
- core::rect(354,87,442,118));
+ core::rect(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(30,20,300,300),
- video::SColor(255,255,255,255) );
-
+ font->draw( L"WXYZsSdDrRjJbB", core::rect(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(30,60,300,400),
- video::SColor(255,255,255,255) );
-
+ font->draw( L"WXYZsSdDrRjJbB", core::rect(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(64, 64, 128, 128), irr::core::rect(0, 0, 88, 31));
+ driver->getMaterial2D().setTexture(0, 0);
+ driver->draw2DImage(tex, irr::core::rect(64, 64, 128, 128), irr::core::rect(0, 0, 88, 31));
driver->getMaterial2D().setTexture(0, tex);
- driver->draw2DImage(tex, irr::core::rect(64, 0, 128, 64), irr::core::rect(0, 0, 88, 31));
+ driver->draw2DImage(tex, irr::core::rect(64, 0, 128, 64), irr::core::rect(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()
diff --git a/tests/md2Animation.cpp b/tests/md2Animation.cpp
index 3f858bac..3fac32bc 100644
--- a/tests/md2Animation.cpp
+++ b/tests/md2Animation.cpp
@@ -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(160, 120), 32);
- assert(device);
+ IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(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(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;
+}
diff --git a/tests/media/Burning's Video-md2Normals.png b/tests/media/Burning's Video-md2Normals.png
new file mode 100644
index 00000000..709b97e9
Binary files /dev/null and b/tests/media/Burning's Video-md2Normals.png differ
diff --git a/tests/screenshot.cpp b/tests/screenshot.cpp
index 6c701f15..d8f7b40c 100644
--- a/tests/screenshot.cpp
+++ b/tests/screenshot.cpp
@@ -41,7 +41,7 @@ bool testShots(video::E_DRIVER_TYPE type)
smgr->drawAll();
driver->endScene();
- for (u32 i=0; icreateScreenShot((video::ECOLOR_FORMAT)i);
logTestString("Color Format %d %ssupported\n", i, (img && img->getColorFormat() == i)?"":"un");
diff --git a/tests/terrainSceneNode.cpp b/tests/terrainSceneNode.cpp
index 1056c4b3..181dc68d 100644
--- a/tests/terrainSceneNode.cpp
+++ b/tests/terrainSceneNode.cpp
@@ -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;
-}
\ No newline at end of file
+}
+
diff --git a/tests/testQuaternion.cpp b/tests/testQuaternion.cpp
index 6e3cd47b..f6d976ce 100644
--- a/tests/testQuaternion.cpp
+++ b/tests/testQuaternion.cpp
@@ -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
-#define TestWithAllDrivers(X, ...) \
+#define TestWithAllDrivers(X) \
logTestString("Running test " #X "\n"); \
for (u32 i=1; i& triangle, const cor
return allExpected;
}
+// modifying the same triangle in diverse ways get some more test-cases automatically
+template
+static bool stageModifications(int stage, triangle3d& 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
+static void stageModifications(int stage, vector3d& point)
+{
+ switch ( stage )
+ {
+ case 3:
+ point.Z += 1000;
+ break;
+ case 4:
+ swap(point.Y, point.Z);
+ break;
+ }
+}
+
+template
+static bool isPointInside(triangle3d triangleOrig)
+{
+ bool allExpected=true;
+
+ array< vector3d > pointsInside;
+ pointsInside.push_back( vector3d(0,0,0) );
+ pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB + triangleOrig.pointC) / 3 );
+ pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 + vector3d(0,1,0) );
+ pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 + vector3d(1,0,0) );
+ pointsInside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 - vector3d(1,0,0) );
+
+ for (u32 stage=0; ; ++stage)
+ {
+ triangle3d triangle = triangleOrig;
+ if ( !stageModifications(stage, triangle) )
+ break;
+
+ for ( u32 i=0; i < pointsInside.size(); ++i )
+ {
+ vector3d 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 > pointsOutside;
+ pointsOutside.push_back( triangleOrig.pointA - vector3d(1,0,0) );
+ pointsOutside.push_back( triangleOrig.pointA - vector3d(0,1,0) );
+ pointsOutside.push_back( triangleOrig.pointB + vector3d(1,0,0) );
+ pointsOutside.push_back( triangleOrig.pointB - vector3d(0,1,0) );
+ pointsOutside.push_back( triangleOrig.pointC - vector3d(1,0,0) );
+ pointsOutside.push_back( triangleOrig.pointC + vector3d(1,0,0) );
+ pointsOutside.push_back( triangleOrig.pointC + vector3d(0,1,0) );
+ pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 - vector3d(0,1,0) );
+ pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 - vector3d(1,0,0) );
+ pointsOutside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 + vector3d(1,0,0) );
+
+ for (u32 stage=0; ; ++stage)
+ {
+ triangle3d triangle = triangleOrig;
+ if ( !stageModifications(stage, triangle) )
+ break;
+
+ for ( u32 i=0; i < pointsOutside.size(); ++i )
+ {
+ vector3d 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 > 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 triangle = triangleOrig;
+ if ( !stageModifications(stage, triangle) )
+ break;
+
+ for ( u32 i=0; i < pointsBorder.size(); ++i )
+ {
+ vector3d 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
/** 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 t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0));
+ allExpected &= isPointInside(t);
+ }
+
+ logTestString("Test isPointInside with f64\n");
+ {
+ triangle3d t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0));
+ allExpected &= isPointInside(t);
+ }
+
+ logTestString("Test isPointInside with s32\n");
+ {
+ triangle3d t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0));
+ allExpected &= isPointInside(t);
+ }
+
if(allExpected)
logTestString("\nAll tests passed\n");
else
diff --git a/tools/FileToHeader/FileToHeader.layout b/tools/FileToHeader/FileToHeader.layout
index 59193d00..97e1eeed 100644
--- a/tools/FileToHeader/FileToHeader.layout
+++ b/tools/FileToHeader/FileToHeader.layout
@@ -1,7 +1,7 @@
-
-
+
+