Index: /trunk/nv/array2d.hh
===================================================================
--- /trunk/nv/array2d.hh	(revision 130)
+++ /trunk/nv/array2d.hh	(revision 131)
@@ -11,6 +11,4 @@
  */
 
-// TODO: implement copy on resize! See image::set_region
-// TODO: implement set sub_array or something like that
 // TODO: make it work with the stl allocator
 
@@ -37,18 +35,73 @@
 		typedef const_pointer     const_iterator;
 
+		/**
+		 *Creates a new 2D array.
+		 */
 		array2d() : m_size(), m_data( nullptr ) {}
+
+		/**
+		 *Creates a new 2D array.
+		 *
+		 *@param asize The dimensions of the new array.
+		 */
 		array2d( const ivec2& asize ) : m_size(), m_data( nullptr ) { resize( asize ); }
+
+		/**
+		 *Creates a new 2D array.
+		 *
+		 *@param asize_x The width of the new array.
+		 *@param asize_y The height of the new array.
+		 */
+		array2d( const sint32 asize_x, const sint32 asize_y ) : m_size(), m_data( nullptr ) { resize( new ivec2( asize_x, asize_y ) ); }
 		
+		/**
+		 *Gets the dimensions of the array.
+		 *
+		 *@returns The size of the array.
+		 */
 		const ivec2& size() const { return m_size; }
+
+		/**
+		 *Gets a pointer to the data in the array.
+		 *
+		 *@returns A pointer to the data in the array.
+		 */
 		pointer data() { return m_data; }
+
+		/**
+		 *Gets a constant pointer to the data in the array.
+		 *
+		 *@returns A constant pointer to the data in the array.
+		 */
 		const_pointer data() const { return m_data; }
 
-		void resize( const ivec2& new_size ) 
-		{
+		/**
+		 *Changes the dimensions of the array.
+		 *
+		 *@param new_size The new dimensions of the array.
+		 *@param preserve True to keep as much of the existing data as will fit in the new array, False to discard the existing data.
+		 */
+		void resize( const ivec2& new_size, bool preserve = false ) 
+		{
+			if (new_size == m_size) return; // Don't do anything if the sizes are the same.
+
 			pointer new_data = new value_type[ new_size.x * new_size.y ];
 			if ( m_data != nullptr )
 			{
-				// TODO: implement copy! See image::set_region
-				delete[] m_data;
+				if (!preserve)
+				{
+					// Just delete the data.
+					delete[] m_data;
+				}
+				else
+				{
+					// Copy the data.  Truncates the bottom or right side of the data if destination is smaller.
+					for ( sint32 i = 0; i < min(new_size.y, m_size.y); i++ )
+					{
+						std::copy( m_data + m_size.x * i, m_data + m_size.x * i + min( new_size.x, m_size.x ), new_data + m_size.x * i );
+					}
+					// ...then delete the original data.
+					delete[] m_data;
+				}
 			}
 			m_data = new_data;
@@ -56,9 +109,40 @@
 		}
 
+		/**
+		 *Gets a pointer to the start of the array.
+		 *
+		 *@returns A pointer to the first position in the array.
+		 */
 		iterator       begin()       { return m_data; }
+
+		/**
+		 *Gets a constant pointer to the start of the array.
+		 *
+		 *@returns A constant pointer to the first position in the array.
+		 */
 		const_iterator begin() const { return m_data; }
+
+		/**
+		 *Gets a pointer to the end of the array.
+		 *
+		 *@returns A pointer to the end of the array.
+		 */
 		iterator       end()         { return m_data + ( m_size.x * m_size.y ); }
+
+		/**
+		 *Gets a constant pointer to the end of the array.
+		 *
+		 *@returns A constant pointer to the end of the array.
+		 */
 		const_iterator end() const   { return m_data + ( m_size.x * m_size.y ); }
 
+
+		/**
+		 *Looks up a position by X and Y value.
+		 *
+		 *@param x The X position of the array to look up.
+		 *@param y The Y position of the array to look up.
+		 *@returns A reference to the data at the indicated position.
+		 */
 		inline const_reference operator() ( sint32 x, sint32 y ) const
 		{
@@ -66,4 +150,12 @@
 			return m_data[ y * m_size.x + x ];
 		}
+
+		/**
+		 *Looks up a position by X and Y value.
+		 *
+		 *@param x The X position of the array to look up.
+		 *@param y The Y position of the array to look up.
+		 *@returns A reference to the data at the indicated position.
+		 */
 		inline reference operator() ( sint32 x, sint32 y )
 		{
@@ -71,4 +163,11 @@
 			return m_data[ y * m_size.x + x ];
 		}
+
+		/**
+		 *Looks up the given position in the array.
+		 *
+		 *@param c The position to look up.
+		 *@returns A reference to the data at the indicated position.
+		 */
 		inline const_reference operator[] ( const ivec2& c ) const 
 		{
@@ -76,4 +175,11 @@
 			return m_data[ c.y * m_size.x + c.x ];
 		}
+
+		/**
+		 *Looks up the given position in the array.
+		 *
+		 *@param c The position to look up.
+		 *@returns A reference to the data at the indicated position.
+		 */
 		inline reference operator[] ( const ivec2& c )
 		{
@@ -82,4 +188,160 @@
 		}
 
+		/**
+		 *Returns a copy of this array in a new instance.
+		 *
+		 *@returns An independent copy of this array.
+		 */
+		array2d<T> clone()
+		{
+			array2d<T> temp = new array2d<T>(m_size);
+			for ( sint32 i = 0; i < m_size.y; i++ )
+			{
+				std::copy( m_data + m_size.x * i, m_data + m_size.x * i + m_size.x, m_size.x * i );
+			}
+			return temp;
+		}
+
+		/**
+		 *Returns an array that represents a subset of the data in this array.
+		 *
+		 *@param start The upper and left bounds of data to retrieve.
+		 *@param size The width and height of the data to retrieve.
+		 *@returns A new 2D array containing the subset of data within the bounds specified.
+		 */
+		array2d<T> get_sub_array( const ivec2& start, const ivec2& size ) {	return get_sub_array( start.x, start.y, size.x, size.y ); }
+		/**
+		 *Returns an array that represents a subset of the data in this array.
+		 *
+		 *@param start_x The left bound of the data to retrieve.
+		 *@param start_y The upper bound of the data to retrieve.
+		 *@param size_x The width of the data to retrieve.
+		 *@param size_y The height of the data to retrieve.
+		 *@returns A new 2D array containing the subset of data within the bounds specified.
+		 */
+		array2d<T> get_sub_array( const sint32 start_x, const sint32 start_y, const sint32 size_x, const sint32 size_y)
+		{
+			// Make sure the parameters are correct and in bounds.
+			NV_ASSERT( start_x >= 0 && start_x < m_size.x && start_y >= 0 && start_y < m_size.y, "get_sub_array: start is out of bounds." );
+			NV_ASSERT( size_x >= 1 && size_x + start_x <= m_size.x && size_y >= 1 && size_y + start_y <= m_size.y, "get_sub_array: size is invalid." );
+			// Empty holder for the sub array of the correct size.
+			array2d<T> temp = new array2d<T>( size_x, size_y );
+			for ( sint32 i = start_y; i < start_y + size_y; i++ )
+			{
+				// Copy starts at start_x.
+				// Copy end is the end position.
+				// Destination is the start of the destination row.
+				//         Start                              End                                         Destination
+				std::copy( m_data + m_size().x * i + start_x, m_data + m_size().x * i + start_x + size_x, temp.m_data + temp.m_size().x * ( i - start_y ) );
+			}
+			return temp;
+		}
+
+		/**
+		 *Fills this array with another array.
+		 *
+		 *@param source The array to fill with.  If it does not fit in the destination it will be truncated.
+		 *@param dest_start The upper and left bounds of the data to fill.
+		 */
+		void set_sub_array( const array2d<T> source, const ivec2& dest_start )
+		{
+			return set_sub_array( source, dest_start.x, dest_start.y, 0, 0, source.m_size.x, source.m_size.y );
+		}
+
+		/**
+		 *Fills this array with a subset of another array.
+		 *
+		 *@param source The arrya to fill with.  If it does not fit in the destination it will be truncated.
+		 *@param dest_start The upper and left bounds of the data to fill.
+		 *@param size The size of the area to copy over.
+		 */
+		void set_sub_array( const array2d<T> source, const ivec2& dest_start, const ivec2& size )
+		{
+			return set_sub_array( source, dest_start.x, dest_start.y, 0, 0, size.x, size.y );
+		}
+
+
+		/**
+		 *Fills this array with a subset of another array.
+		 *
+		 *@param source The array to fill with.  If it does not fit in the destination it will be truncated.
+		 *@param dest_start The upper and left bounds of the data to fill.
+		 *@param source_start The upper and left bounds of the source to fill with.
+		 *@param size The size of the area to copy over.
+		 */
+		void set_sub_array( const array2d<T> source, const ivec2& dest_start, const ivec2& source_start, const ivec2& size )
+		{
+			return set_sub_array( source, dest_start.x, dest_start.y, source_start.x, source_start.y, size.x, size.y );
+		}
+
+		/**
+		 *Fills this array with another array.
+		 *
+		 *@param source The array to fill with.  If it does not fit in the area to fill, it will be truncated.
+		 *@param dest_start_x The left bound of the data to fill.
+		 *@param dest_start_y The upper bound of the data to fill.
+		 */
+		void set_sub_array( const array2d<T> source, const sint32 dest_start_x, const sint32 dest_start_y )
+		{
+			return set_sub_array( source, dest_start_x, dest_start_y, 0, 0, source.m_size.x, source.m_size.y );
+		}
+
+		/**
+		 *Fills this array with another array.
+		 *
+		 *@param source The array to fill with.  If it does not fit in the area to fill, it will be truncated.
+		 *@param dest_start_x The left bound of the data to fill.
+		 *@param dest_start_y The upper bound of the data to fill.
+		 *@param size_x The width of the area to copy over.
+		 *@param size_y The height of the area to copy over.
+		 */
+		void set_sub_array( const array2d<T> source, const sint32 dest_start_x, const sint32 dest_start_y, const sint32 size_x, const sint32 size_y )
+		{
+			return set_sub_array( source, dest_start_x, dest_start_y, 0, 0, size_x, size_y );
+		}
+
+		/**
+		 *Fills this array with a subset of another array.
+		 *
+		 *@param source The array to fill with.  If it does not fit in the area to fill, it will be truncated.
+		 *@param dest_start_x The left bound of the data to fill.
+		 *@param dest_start_y The upper bound of the data to fill.
+		 *@param source_start_x The left bound of the source to fill with.
+		 *@param source_start_y The upper bound of the source to fill with.
+		 *@param size_x The width of the area to copy over.
+		 *@param size_y The height of the area to copy over.
+		 */
+		void set_sub_array( const array2d<T> source, const sint32 dest_start_x, const sint32 dest_start_y, const sint32 source_start_x, const sint32 source_start_y, const sint32 size_x, const sint32 size_y )
+		{
+			// Start by checking the parameters.  Make sure nothing is out of bounds.
+			NV_ASSERT( source != nullptr, "set_sub_array: no source defined." );
+			NV_ASSERT( dest_start_x >= 0 && dest_start_x < m_size.x && dest_start_y >= 0 && dest_start_y < m_size.y, "set_sub_array: destination start is out of bounds." );
+			NV_ASSERT( source_start_x >= 0 && source_start_x < source.m_size.x && source_start_y >= 0 && source_start_y < source.m_size.y, "set_sub_array: source start is out of bounds." );
+			NV_ASSERT( size_x >= 1 && size_y >= 1, "set_sub_array: invalid size specified." ); // If size is 0, nothing would be copied in the first place.
+		
+			// Warn when copied data is truncated.
+			// If the end of the copied area is beyond the bounds of the destination array, data will be truncated.
+			if ( dest_start_x + min(size_x, source.m_size.x - source_start_x) > m_size.x || dest_start_y + min(size_y, source.m_size.y - source_start_y) > m_size.y )
+			{
+				NV_LOG( LOG_WARNING, "set_sub_array: Source area does not fit in the destination area.  Data will be truncated." );
+			}
+		
+			// Copy into THIS array from source the following.
+			// Highest row is either the size limit or the end of either array, whichever is smaller.
+			for ( i = 0; i < min( size_y , min ( m_size.y - dest_start_y, source.m_size.y - source_start_y ) ); i++ )
+			{
+				// Copy the indicated row.
+				// The start position is the beginning of the current row (which is source_start_y + i), offset by source_start_x.
+				// The end position is either the size limit or the end of either array, whichever is smaller.
+				// Destination start is the beginning of the current destination row (which is dest_start_y + i), offset by dest_start_x.
+				std:copy( source.m_data + ( source_start_y + i ) * source.m_size.x + source_start_x,  // Source Start
+						  source.m_data + ( source_start_y + i ) * source.m_size.x + min( source.m_size.x, min( source_start_x + size_x, source_start_x + m_size.x - dest_start_x ) ), // Source End
+						  m_data + (dest_start_y + i) * m_size.x + dest_start_x ) // Destination Start
+			}
+		}
+
+		/**
+		 *Destructor.
+		 */
 		~array2d()
 		{
@@ -90,6 +352,6 @@
 		}
 	protected:
-		pointer m_data;
-		ivec2   m_size;
+		pointer m_data; ///< Pointer to the data.
+		ivec2   m_size; ///< Allocated size of the data.
 	};
 
