Make irrArray backed by std::vector (#101)

This commit is contained in:
paradust7 2022-05-21 14:56:36 -07:00 committed by GitHub
parent 593103a261
commit 3e81f38098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 147 additions and 426 deletions

@ -100,7 +100,7 @@ namespace scene
private: private:
//! Internal members used by CSkinnedMesh //! Internal members used by CSkinnedMesh
friend class CSkinnedMesh; friend class CSkinnedMesh;
bool *Moved; char *Moved;
core::vector3df StaticPos; core::vector3df StaticPos;
core::vector3df StaticNormal; core::vector3df StaticNormal;
}; };

@ -1,70 +0,0 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_HEAPSORT_H_INCLUDED__
#define __IRR_HEAPSORT_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace core
{
//! Sinks an element into the heap.
template<class T>
inline void heapsink(T*array, s32 element, s32 max)
{
while ((element<<1) < max) // there is a left child
{
s32 j = (element<<1);
if (j+1 < max && array[j] < array[j+1])
j = j+1; // take right child
if (array[element] < array[j])
{
T t = array[j]; // swap elements
array[j] = array[element];
array[element] = t;
element = j;
}
else
return;
}
}
//! Sorts an array with size 'size' using heapsort.
template<class T>
inline void heapsort(T* array_, s32 size)
{
// for heapsink we pretend this is not c++, where
// arrays start with index 0. So we decrease the array pointer,
// the maximum always +2 and the element always +1
T* virtualArray = array_ - 1;
s32 virtualSize = size + 2;
s32 i;
// build heap
for (i=((size-1)/2); i>=0; --i)
heapsink(virtualArray, i+1, virtualSize-1);
// sort array, leave out the last element (0)
for (i=size-1; i>0; --i)
{
T t = array_[0];
array_[0] = array_[i];
array_[i] = t;
heapsink(virtualArray, 1, i + 1);
}
}
} // end namespace core
} // end namespace irr
#endif

@ -5,9 +5,11 @@
#ifndef __IRR_ARRAY_H_INCLUDED__ #ifndef __IRR_ARRAY_H_INCLUDED__
#define __IRR_ARRAY_H_INCLUDED__ #define __IRR_ARRAY_H_INCLUDED__
#include <algorithm>
#include <iterator>
#include <vector>
#include "irrTypes.h" #include "irrTypes.h"
#include "heapsort.h"
#include "irrAllocator.h"
#include "irrMath.h" #include "irrMath.h"
namespace irr namespace irr
@ -18,44 +20,27 @@ namespace core
//! Self reallocating template array (like stl vector) with additional features. //! Self reallocating template array (like stl vector) with additional features.
/** Some features are: Heap sorting, binary search methods, easier debugging. /** Some features are: Heap sorting, binary search methods, easier debugging.
*/ */
template <class T, typename TAlloc = irrAllocator<T> > template <class T>
class array class array
{ {
public: public:
static_assert(!std::is_same<T, bool>::value,
"irr::core::array<T> with T = bool not supported. Use std::vector instead.");
//! Default constructor for empty array. //! Default constructor for empty array.
array() : data(0), allocated(0), used(0), array() : m_data(), is_sorted(true)
strategy(ALLOC_STRATEGY_DOUBLE), free_when_destroyed(true), is_sorted(true) { }
{
}
//! Constructs an array and allocates an initial chunk of memory. //! Constructs an array and allocates an initial chunk of memory.
/** \param start_count Amount of elements to pre-allocate. */ /** \param start_count Amount of elements to pre-allocate. */
explicit array(u32 start_count) : data(0), allocated(0), used(0), explicit array(u32 start_count) : m_data(), is_sorted(true)
strategy(ALLOC_STRATEGY_DOUBLE),
free_when_destroyed(true), is_sorted(true)
{ {
reallocate(start_count); m_data.reserve(start_count);
} }
//! Copy constructor //! Copy constructor
array(const array<T, TAlloc>& other) : data(0) array(const array<T>& other) : m_data(other.m_data), is_sorted(other.is_sorted)
{ { }
*this = other;
}
//! Destructor.
/** Frees allocated memory, if set_free_when_destroyed was not set to
false by the user before. */
~array()
{
clear();
}
//! Reallocates the array, make it bigger or smaller. //! Reallocates the array, make it bigger or smaller.
/** \param new_size New size of array. /** \param new_size New size of array.
@ -65,52 +50,28 @@ public:
*/ */
void reallocate(u32 new_size, bool canShrink=true) void reallocate(u32 new_size, bool canShrink=true)
{ {
if (allocated==new_size) size_t allocated = m_data.capacity();
return; if (new_size < allocated) {
if (!canShrink && (new_size < allocated)) if (canShrink)
return; m_data.resize(new_size);
} else {
T* old_data = data; m_data.reserve(new_size);
data = allocator.allocate(new_size); //new T[new_size];
allocated = new_size;
// copy old data
const s32 end = used < new_size ? used : new_size;
for (s32 i=0; i<end; ++i)
{
// data[i] = old_data[i];
allocator.construct(&data[i], old_data[i]);
} }
// destruct old data
for (u32 j=0; j<used; ++j)
allocator.destruct(&old_data[j]);
if (allocated < used)
used = allocated;
allocator.deallocate(old_data); //delete [] old_data;
} }
//! set a new allocation strategy
/** if the maximum size of the array is unknown, you can define how big the
allocation should happen.
\param newStrategy New strategy to apply to this array. */
void setAllocStrategy ( eAllocStrategy newStrategy = ALLOC_STRATEGY_DOUBLE )
{
strategy = newStrategy;
}
//! Adds an element at back of array. //! Adds an element at back of array.
/** If the array is too small to add this new element it is made bigger. /** If the array is too small to add this new element it is made bigger.
\param element: Element to add at the back of the array. */ \param element: Element to add at the back of the array. */
void push_back(const T& element) void push_back(const T& element)
{ {
insert(element, used); m_data.push_back(element);
is_sorted = false;
}
void push_back(T&& element)
{
m_data.push_back(std::move(element));
is_sorted = false;
} }
@ -121,7 +82,14 @@ public:
\param element Element to add at the back of the array. */ \param element Element to add at the back of the array. */
void push_front(const T& element) void push_front(const T& element)
{ {
insert(element); m_data.insert(m_data.begin(), element);
is_sorted = false;
}
void push_front(T&& element)
{
m_data.insert(m_data.begin(), std::move(element));
is_sorted = false;
} }
@ -131,106 +99,21 @@ public:
\param index: Where position to insert the new element. */ \param index: Where position to insert the new element. */
void insert(const T& element, u32 index=0) void insert(const T& element, u32 index=0)
{ {
_IRR_DEBUG_BREAK_IF(index>used) // access violation _IRR_DEBUG_BREAK_IF(index > m_data.size()) // access violation
auto pos = std::next(m_data.begin(), index);
if (used + 1 > allocated) m_data.insert(pos, element);
{
// this doesn't work if the element is in the same
// array. So we'll copy the element first to be sure
// we'll get no data corruption
const T e(element);
// increase data block
u32 newAlloc;
switch ( strategy )
{
case ALLOC_STRATEGY_DOUBLE:
newAlloc = used + 5 + (allocated < 500 ? used : used >> 2);
break;
default:
case ALLOC_STRATEGY_SAFE:
newAlloc = used + 1;
break;
}
reallocate( newAlloc);
// move array content and construct new element
// first move end one up
for (u32 i=used; i>index; --i)
{
if (i<used)
allocator.destruct(&data[i]);
allocator.construct(&data[i], data[i-1]); // data[i] = data[i-1];
}
// then add new element
if (used > index)
allocator.destruct(&data[index]);
allocator.construct(&data[index], e); // data[index] = e;
}
else
{
// element inserted not at end
if ( used > index )
{
// create one new element at the end
allocator.construct(&data[used], data[used-1]);
// move the rest of the array content
for (u32 i=used-1; i>index; --i)
{
data[i] = data[i-1];
}
// insert the new element
data[index] = element;
}
else
{
// insert the new element to the end
allocator.construct(&data[index], element);
}
}
// set to false as we don't know if we have the comparison operators
is_sorted = false; is_sorted = false;
++used;
} }
//! Clears the array and deletes all allocated memory. //! Clears the array and deletes all allocated memory.
void clear() void clear()
{ {
if (free_when_destroyed) // vector::clear() reduces the size to 0, but doesn't free memory.
{ // This swap is guaranteed to delete the allocated memory.
for (u32 i=0; i<used; ++i) std::vector<T>().swap(m_data);
allocator.destruct(&data[i]);
allocator.deallocate(data); // delete [] data;
}
data = 0;
used = 0;
allocated = 0;
is_sorted = true; is_sorted = true;
} }
//! Sets pointer to new array, using this as new workspace.
/** Make sure that set_free_when_destroyed is used properly.
\param newPointer: Pointer to new array of elements.
\param size: Size of the new array.
\param _is_sorted Flag which tells whether the new array is already
sorted.
\param _free_when_destroyed Sets whether the new memory area shall be
freed by the array upon destruction, or if this will be up to the user
application. */
void set_pointer(T* newPointer, u32 size, bool _is_sorted=false, bool _free_when_destroyed=true)
{
clear();
data = newPointer;
allocated = size;
used = size;
is_sorted = _is_sorted;
free_when_destroyed=_free_when_destroyed;
}
//! Set (copy) data from given memory block //! Set (copy) data from given memory block
/** \param newData data to set, must have newSize elements /** \param newData data to set, must have newSize elements
\param newSize Amount of elements in newData \param newSize Amount of elements in newData
@ -240,12 +123,11 @@ public:
*/ */
void set_data(const T* newData, u32 newSize, bool newDataIsSorted=false, bool canShrink=false) void set_data(const T* newData, u32 newSize, bool newDataIsSorted=false, bool canShrink=false)
{ {
reallocate(newSize, canShrink); m_data.resize(newSize);
set_used(newSize); if (canShrink) {
for ( u32 i=0; i<newSize; ++i) m_data.shrink_to_fit();
{
data[i] = newData[i];
} }
std::copy(newData, newData + newSize, m_data.begin());
is_sorted = newDataIsSorted; is_sorted = newDataIsSorted;
} }
@ -255,85 +137,51 @@ public:
\param size Amount of elements in otherData */ \param size Amount of elements in otherData */
bool equals(const T* otherData, u32 size) const bool equals(const T* otherData, u32 size) const
{ {
if (used != size) if (m_data.size() != size)
return false; return false;
return std::equal(m_data.begin(), m_data.end(), otherData);
for (u32 i=0; i<size; ++i)
if (data[i] != otherData[i])
return false;
return true;
} }
//! Sets if the array should delete the memory it uses upon destruction.
/** Also clear and set_pointer will only delete the (original) memory
area if this flag is set to true, which is also the default. The
methods reallocate, set_used, push_back, push_front, insert, and erase
will still try to deallocate the original memory, which might cause
troubles depending on the intended use of the memory area.
\param f If true, the array frees the allocated memory in its
destructor, otherwise not. The default is true. */
void set_free_when_destroyed(bool f)
{
free_when_destroyed = f;
}
//! Sets the size of the array and allocates new elements if necessary. //! Sets the size of the array and allocates new elements if necessary.
/** Please note: This is only secure when using it with simple types, /** \param usedNow Amount of elements now used. */
because no default constructor will be called for the added elements.
\param usedNow Amount of elements now used. */
void set_used(u32 usedNow) void set_used(u32 usedNow)
{ {
if (allocated < usedNow) m_data.resize(usedNow);
reallocate(usedNow);
used = usedNow;
} }
//! Assignment operator //! Assignment operator
const array<T, TAlloc>& operator=(const array<T, TAlloc>& other) const array<T>& operator=(const array<T>& other)
{ {
if (this == &other) if (this == &other)
return *this; return *this;
strategy = other.strategy; m_data = other.m_data;
// (TODO: we could probably avoid re-allocations of data when (allocated < other.allocated)
if (data)
clear();
used = other.used;
free_when_destroyed = true;
is_sorted = other.is_sorted; is_sorted = other.is_sorted;
allocated = other.allocated;
if (other.allocated == 0)
{
data = 0;
}
else
{
data = allocator.allocate(other.allocated); // new T[other.allocated];
for (u32 i=0; i<other.used; ++i)
allocator.construct(&data[i], other.data[i]); // data[i] = other.data[i];
}
return *this; return *this;
} }
array<T>& operator=(const std::vector<T> &other)
{
m_data = other;
is_sorted = false;
return *this;
}
array<T>& operator=(std::vector<T> &&other)
{
m_data = std::move(other);
is_sorted = false;
return *this;
}
//! Equality operator //! Equality operator
bool operator == (const array<T, TAlloc>& other) const bool operator == (const array<T>& other) const
{ {
return equals(other.const_pointer(), other.size()); return equals(other.const_pointer(), other.size());
} }
//! Inequality operator //! Inequality operator
bool operator != (const array<T, TAlloc>& other) const bool operator != (const array<T>& other) const
{ {
return !(*this==other); return !(*this==other);
} }
@ -342,36 +190,36 @@ public:
//! Direct access operator //! Direct access operator
T& operator [](u32 index) T& operator [](u32 index)
{ {
_IRR_DEBUG_BREAK_IF(index>=used) // access violation _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation
return data[index]; return m_data[index];
} }
//! Direct const access operator //! Direct const access operator
const T& operator [](u32 index) const const T& operator [](u32 index) const
{ {
_IRR_DEBUG_BREAK_IF(index>=used) // access violation _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation
return data[index]; return m_data[index];
} }
//! Gets last element. //! Gets last element.
T& getLast() T& getLast()
{ {
_IRR_DEBUG_BREAK_IF(!used) // access violation _IRR_DEBUG_BREAK_IF(m_data.empty()) // access violation
return data[used-1]; return m_data.back();
} }
//! Gets last element //! Gets last element
const T& getLast() const const T& getLast() const
{ {
_IRR_DEBUG_BREAK_IF(!used) // access violation _IRR_DEBUG_BREAK_IF(m_data.empty()) // access violation
return data[used-1]; return m_data.back();
} }
@ -379,7 +227,7 @@ public:
/** \return Pointer to the array. */ /** \return Pointer to the array. */
T* pointer() T* pointer()
{ {
return data; return &m_data[0];
} }
@ -387,7 +235,7 @@ public:
/** \return Pointer to the array. */ /** \return Pointer to the array. */
const T* const_pointer() const const T* const_pointer() const
{ {
return data; return &m_data[0];
} }
@ -395,7 +243,7 @@ public:
/** \return Size of elements in the array which are actually occupied. */ /** \return Size of elements in the array which are actually occupied. */
u32 size() const u32 size() const
{ {
return used; return m_data.size();
} }
@ -404,7 +252,7 @@ public:
allocated would be allocated_size() * sizeof(ElementTypeUsed); */ allocated would be allocated_size() * sizeof(ElementTypeUsed); */
u32 allocated_size() const u32 allocated_size() const
{ {
return allocated; return m_data.capacity();
} }
@ -412,7 +260,7 @@ public:
/** \return True if the array is empty false if not. */ /** \return True if the array is empty false if not. */
bool empty() const bool empty() const
{ {
return used == 0; return m_data.empty();
} }
@ -421,9 +269,10 @@ public:
O(n*log n) in worst case. */ O(n*log n) in worst case. */
void sort() void sort()
{ {
if (!is_sorted && used>1) if (!is_sorted) {
heapsort(data, used); std::sort(m_data.begin(), m_data.end());
is_sorted = true; is_sorted = true;
}
} }
@ -437,10 +286,9 @@ public:
s32 binary_search(const T& element) s32 binary_search(const T& element)
{ {
sort(); sort();
return binary_search(element, 0, used-1); return binary_search(element, 0, (s32)m_data.size() - 1);
} }
//! Performs a binary search for an element if possible, returns -1 if not found. //! Performs a binary search for an element if possible, returns -1 if not found.
/** This method is for const arrays and so cannot call sort(), if the array is /** This method is for const arrays and so cannot call sort(), if the array is
not sorted then linear_search will be used instead. Potentially very slow! not sorted then linear_search will be used instead. Potentially very slow!
@ -450,12 +298,11 @@ public:
s32 binary_search(const T& element) const s32 binary_search(const T& element) const
{ {
if (is_sorted) if (is_sorted)
return binary_search(element, 0, used-1); return binary_search(element, 0, (s32)m_data.size() - 1);
else else
return linear_search(element); return linear_search(element);
} }
//! Performs a binary search for an element, returns -1 if not found. //! Performs a binary search for an element, returns -1 if not found.
/** \param element: Element to search for. /** \param element: Element to search for.
\param left First left index \param left First left index
@ -464,31 +311,15 @@ public:
is returned. */ is returned. */
s32 binary_search(const T& element, s32 left, s32 right) const s32 binary_search(const T& element, s32 left, s32 right) const
{ {
if (!used) if (left > right)
return -1; return -1;
auto lpos = std::next(m_data.begin(), left);
s32 m; auto rpos = std::next(m_data.begin(), right);
auto it = std::lower_bound(lpos, rpos, element);
do // *it = first element in [first, last) that is >= element, or last if not found.
{ if (*it < element || element < *it)
m = (left+right)>>1; return -1;
return it - m_data.begin();
if (element < data[m])
right = m - 1;
else
left = m + 1;
} while((element < data[m] || data[m] < element) && left<=right);
// this last line equals to:
// " while((element != array[m]) && left<=right);"
// but we only want to use the '<' operator.
// the same in next line, it is "(element == array[m])"
if (!(element < data[m]) && !(data[m] < element))
return m;
return -1;
} }
@ -503,25 +334,11 @@ public:
s32 binary_search_multi(const T& element, s32 &last) s32 binary_search_multi(const T& element, s32 &last)
{ {
sort(); sort();
s32 index = binary_search(element, 0, used-1); auto iters = std::equal_range(m_data.begin(), m_data.end(), element);
if ( index < 0 ) if (iters.first == iters.second)
return index; return -1;
last = (iters.second - m_data.begin()) - 1;
// The search can be somewhere in the middle of the set return iters.first - m_data.begin();
// look linear previous and past the index
last = index;
while ( index > 0 && !(element < data[index - 1]) && !(data[index - 1] < element) )
{
index -= 1;
}
// look linear up
while ( last < (s32) used - 1 && !(element < data[last + 1]) && !(data[last + 1] < element) )
{
last += 1;
}
return index;
} }
@ -533,11 +350,10 @@ public:
is returned. */ is returned. */
s32 linear_search(const T& element) const s32 linear_search(const T& element) const
{ {
for (u32 i=0; i<used; ++i) auto it = std::find(m_data.begin(), m_data.end(), element);
if (element == data[i]) if (it == m_data.end())
return (s32)i; return -1;
return it - m_data.begin();
return -1;
} }
@ -549,11 +365,11 @@ public:
is returned. */ is returned. */
s32 linear_reverse_search(const T& element) const s32 linear_reverse_search(const T& element) const
{ {
for (s32 i=used-1; i>=0; --i) auto it = std::find(m_data.rbegin(), m_data.rend(), element);
if (data[i] == element) if (it == m_data.rend())
return i; return -1;
size_t offset = it - m_data.rbegin();
return -1; return m_data.size() - offset - 1;
} }
@ -563,17 +379,9 @@ public:
\param index: Index of element to be erased. */ \param index: Index of element to be erased. */
void erase(u32 index) void erase(u32 index)
{ {
_IRR_DEBUG_BREAK_IF(index>=used) // access violation _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation
auto it = std::next(m_data.begin(), index);
for (u32 i=index+1; i<used; ++i) m_data.erase(it);
{
allocator.destruct(&data[i-1]);
allocator.construct(&data[i-1], data[i]); // data[i-1] = data[i];
}
allocator.destruct(&data[used-1]);
--used;
} }
@ -584,30 +392,14 @@ public:
\param count: Amount of elements to be erased. */ \param count: Amount of elements to be erased. */
void erase(u32 index, s32 count) void erase(u32 index, s32 count)
{ {
if (index>=used || count<1) if (index >= m_data.size() || count < 1)
return; return;
if (index+count>used) count = std::min(count, (s32)m_data.size() - (s32)index);
count = used-index; auto first = std::next(m_data.begin(), index);
auto last = std::next(first, count);
u32 i; m_data.erase(first, last);
for (i=index; i<index+count; ++i)
allocator.destruct(&data[i]);
for (i=index+count; i<used; ++i)
{
if (i-count >= index+count) // not already destructed before loop
allocator.destruct(&data[i-count]);
allocator.construct(&data[i-count], data[i]); // data[i-count] = data[i];
if (i >= used-count) // those which are not overwritten
allocator.destruct(&data[i]);
}
used-= count;
} }
//! Sets if the array is sorted //! Sets if the array is sorted
void set_sorted(bool _is_sorted) void set_sorted(bool _is_sorted)
{ {
@ -619,38 +411,30 @@ public:
/** Afterward this object will contain the content of the other object and the other /** Afterward this object will contain the content of the other object and the other
object will contain the content of this object. object will contain the content of this object.
\param other Swap content with this object */ \param other Swap content with this object */
void swap(array<T, TAlloc>& other) void swap(array<T>& other)
{ {
core::swap(data, other.data); m_data.swap(other.m_data);
core::swap(allocated, other.allocated); std::swap(is_sorted, other.is_sorted);
core::swap(used, other.used); }
core::swap(allocator, other.allocator); // memory is still released by the same allocator used for allocation
eAllocStrategy helper_strategy(strategy); // can't use core::swap with bitfields //! Pull the contents of this array as a vector.
strategy = other.strategy; // The array is left empty.
other.strategy = helper_strategy; std::vector<T> steal()
bool helper_free_when_destroyed(free_when_destroyed); {
free_when_destroyed = other.free_when_destroyed; std::vector<T> ret = std::move(m_data);
other.free_when_destroyed = helper_free_when_destroyed; m_data.clear();
bool helper_is_sorted(is_sorted); is_sorted = true;
is_sorted = other.is_sorted; return ret;
other.is_sorted = helper_is_sorted;
} }
typedef TAlloc allocator_type;
typedef T value_type; typedef T value_type;
typedef u32 size_type; typedef u32 size_type;
private: private:
T* data; std::vector<T> m_data;
u32 allocated; bool is_sorted;
u32 used;
TAlloc allocator;
eAllocStrategy strategy:4;
bool free_when_destroyed:1;
bool is_sorted:1;
}; };
} // end namespace core } // end namespace core
} // end namespace irr } // end namespace irr

@ -50,7 +50,6 @@
#include "EMessageBoxFlags.h" #include "EMessageBoxFlags.h"
#include "ESceneNodeTypes.h" #include "ESceneNodeTypes.h"
#include "fast_atof.h" #include "fast_atof.h"
#include "heapsort.h"
#include "IAnimatedMesh.h" #include "IAnimatedMesh.h"
#include "IAnimatedMeshSceneNode.h" #include "IAnimatedMeshSceneNode.h"
#include "IAttributes.h" #include "IAttributes.h"

@ -70,9 +70,9 @@ IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file)
const u32 WORD_BUFFER_LENGTH = 512; const u32 WORD_BUFFER_LENGTH = 512;
core::array<core::vector3df, core::irrAllocatorFast<core::vector3df> > vertexBuffer(1000); core::array<core::vector3df> vertexBuffer(1000);
core::array<core::vector3df, core::irrAllocatorFast<core::vector3df> > normalsBuffer(1000); core::array<core::vector3df> normalsBuffer(1000);
core::array<core::vector2df, core::irrAllocatorFast<core::vector2df> > textureCoordBuffer(1000); core::array<core::vector2df> textureCoordBuffer(1000);
SObjMtl * currMtl = new SObjMtl(); SObjMtl * currMtl = new SObjMtl();
Materials.push_back(currMtl); Materials.push_back(currMtl);

@ -112,12 +112,12 @@ bool COGLES1Driver::genericDriverInit(const core::dimension2d<u32>& screenSize,
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
UserClipPlane.reallocate(MaxUserClipPlanes); UserClipPlane.reallocate(MaxUserClipPlanes);
UserClipPlaneEnabled.reallocate(MaxUserClipPlanes); UserClipPlaneEnabled.resize(MaxUserClipPlanes);
for (s32 i = 0; i < MaxUserClipPlanes; ++i) for (s32 i = 0; i < MaxUserClipPlanes; ++i)
{ {
UserClipPlane.push_back(core::plane3df()); UserClipPlane.push_back(core::plane3df());
UserClipPlaneEnabled.push_back(false); UserClipPlaneEnabled[i] = false;
} }
for (s32 i = 0; i < ETS_COUNT; ++i) for (s32 i = 0; i < ETS_COUNT; ++i)

@ -363,7 +363,7 @@ namespace video
SMaterial Material, LastMaterial; SMaterial Material, LastMaterial;
core::array<core::plane3df> UserClipPlane; core::array<core::plane3df> UserClipPlane;
core::array<bool> UserClipPlaneEnabled; std::vector<bool> UserClipPlaneEnabled;
core::stringc VendorName; core::stringc VendorName;

@ -231,6 +231,9 @@ namespace scene
struct DefaultNodeEntry struct DefaultNodeEntry
{ {
DefaultNodeEntry()
{ }
DefaultNodeEntry(ISceneNode* n) : DefaultNodeEntry(ISceneNode* n) :
Node(n), TextureValue(0) Node(n), TextureValue(0)
{ {
@ -251,6 +254,9 @@ namespace scene
//! sort on distance (center) to camera //! sort on distance (center) to camera
struct TransparentNodeEntry struct TransparentNodeEntry
{ {
TransparentNodeEntry()
{ }
TransparentNodeEntry(ISceneNode* n, const core::vector3df& camera) TransparentNodeEntry(ISceneNode* n, const core::vector3df& camera)
: Node(n) : Node(n)
{ {

@ -1042,7 +1042,7 @@ void CSkinnedMesh::finalize()
for (i=0; i<LocalBuffers.size(); ++i) for (i=0; i<LocalBuffers.size(); ++i)
{ {
Vertices_Moved.push_back( core::array<bool>() ); Vertices_Moved.push_back( core::array<char>() );
Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
} }

@ -196,7 +196,9 @@ private:
core::array<SJoint*> AllJoints; core::array<SJoint*> AllJoints;
core::array<SJoint*> RootJoints; core::array<SJoint*> RootJoints;
core::array< core::array<bool> > Vertices_Moved; // bool can't be used here because std::vector<bool>
// doesn't allow taking a reference to individual elements.
core::array< core::array<char> > Vertices_Moved;
core::aabbox3d<f32> BoundingBox; core::aabbox3d<f32> BoundingBox;