blob: 8a75b999cc4c15853f1f09a66df7bd2556c6389f [file] [log] [blame]
/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file contains the declaration for the Buffer, VertexBuffer and
// IndexBuffer classes.
#ifndef O3D_CORE_CROSS_BUFFER_H_
#define O3D_CORE_CROSS_BUFFER_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "core/cross/field.h"
#include "core/cross/named_object.h"
#include "core/cross/types.h"
namespace o3d {
class RawData;
class Features;
// class Buffer -----------------------------
//
// DESIGN GOALS:the Buffer object is a low level container for a flat list of
// floating point or integer values. These are used to define geometry,
// parameter buffers and to hold animation data.
//
// The default implementation of the Buffer doesn't do much. Each render system
// (e.g. D3D, OGL, etc) should derive its own version of a Buffer that handles
// the underlying data resources appropriately
// The Buffer object is a low level container for a flat list of
// floating point or integer values. These are currently used to define
// geometry. Buffer is an abstract class and only declares the interface for
// buffer operations. Data storage needs to be allocated by derived classes.
class Buffer : public NamedObject {
public:
typedef SmartPointer<Buffer> Ref;
// Defines how you want to access a buffer when locking.
enum AccessMode {
NONE = 0,
READ_ONLY = 1,
WRITE_ONLY = 2,
READ_WRITE = 3,
};
// Yes, 65534 is the correct number. Specifically the Intel 945 only allows
// 65534 elements.
static const unsigned MAX_SMALL_INDEX = 65534;
// Yes, Sadly many modern cards only support 1048575 vertices.
static const unsigned MAX_LARGE_INDEX = 1048575;
// A four-character identifier used in the binary serialization format
// (not exposed to Javascript)
static const char *kSerializationID;
explicit Buffer(ServiceLocator* service_locator);
~Buffer();
// Allocates memory for the data to be stored in the buffer
bool AllocateElements(unsigned int num_elements);
// Frees any data currently allocated for this buffer.
void Free();
// Creates a field on this buffer
// Parameters:
// field_type: type of field.
// num_components: number of components.
// Returns:
// Pointer to created field.
Field* CreateField(const ObjectBase::Class* field_type,
unsigned num_components);
// Creates a field on this buffer
//
// this is for Javascript
//
// Paramters:
// field_type_name: name of type of field.
// num_components: number of components.
// Returns:
// Pointer to created field.
Field* CreateFieldByClassName(const String& field_type_name,
unsigned num_components);
// Removes a field
// Parameters:
// field: Field to remove.
void RemoveField(Field* field);
// Returns the stride of the buffer.
unsigned int stride() const {
return stride_;
}
// Returns the number of components per element. In other words the sum
// of all the components in all fields.
unsigned int total_components() const {
return total_components_;
}
// Returns the field change count. Anytime a field is added, removed or
// changed this value is incremented. Streams track it so they know
// to rebuild vertex declarations based on the buffer changing format.
unsigned int field_change_count() const {
return field_change_count_;
}
// Obtains a pointer to the memory location where the data is stored.
// This method should get called before data stored in the buffer can be
// modified. From C++ use LockAs
// Parameters:
// access_mode: How you want to access the data.
// buffer_data: pointer to void pointer to receive pointer to data.
// Returns:
// true if the operation succeeds.
bool Lock(AccessMode access_mode, void** buffer_data);
// Notifies that updates to the buffer data are completed. Once Unlock
// is called data should not be modified any more.
bool Unlock();
// Gets the number of elements.
unsigned int num_elements() const {
return num_elements_;
}
// Gets the array of fields.
const FieldRefArray& fields() const {
return fields_;
}
// Returns the size of the buffer in bytes.
size_t GetSizeInBytes() const {
return num_elements_ * stride_;
}
// A typed version of Lock
template <typename T>
bool LockAs(AccessMode access_mode, T** buffer_data) {
return Lock(access_mode, reinterpret_cast<void**>(buffer_data));
}
// De-serializes the data contained in |raw_data|
// The entire contents of |raw_data| from start to finish will
// be used
bool Set(o3d::RawData *raw_data);
// De-serializes the data contained in |raw_data|
// starting at byte offset |offset| and using |length|
// bytes
bool Set(o3d::RawData *raw_data,
size_t offset,
size_t length);
protected:
// The concrete version of AllocateElements.
virtual bool ConcreteAllocate(size_t size_in_bytes) = 0;
// The concrete version of Free
virtual void ConcreteFree() = 0;
// The concrete version of Lock. Platform specific versions of buffers
// need to override this.
//
// Parameters:
// access_mode: How you want to access the data. buffer_data: pointer to
// void pointer to receive pointer to data.
// Returns:
// true if the operation succeeds.
virtual bool ConcreteLock(AccessMode access_mode, void** buffer_data) = 0;
// The concrete version of Unlock. Platform specific versions of buffers need
// to override this.
virtual bool ConcreteUnlock() = 0;
private:
// Takes the data currently allocated and copies it to new data of a different
// stride.
// Parameters:
// new_stride: stride of new buffer.
// field_to_remove: address of field. If NULL no field is removed.
bool ReshuffleBuffer(unsigned int new_stride, Field* field_to_remove);
void AdjustBufferMemoryInfo(bool add);
Features* features_;
// Fields.
FieldRefArray fields_;
// The number of times fields have been added or removed. Streams
// can track this value so they can know if they need to update.
unsigned int field_change_count_;
// The total number of components in all fields.
unsigned int total_components_;
// The stride of the buffer.
unsigned int stride_;
// The current number of elements in the buffer.
unsigned int num_elements_;
// The mode the buffer is currently being accessed so we can fail if a
// different mode is requested
AccessMode access_mode_;
// The number of times this buffer has been locked.
int lock_count_;
// Pointer to data when it's locked.
void* locked_data_;
O3D_DECL_CLASS(Buffer, NamedObject);
};
// VertexBufferBase is just here so VertexBuffer and SourceBuffer can share IDL
// glue.
class VertexBufferBase : public Buffer {
public:
typedef SmartPointer<VertexBufferBase> Ref;
protected:
explicit VertexBufferBase(ServiceLocator* service_locator);
private:
O3D_DECL_CLASS(VertexBufferBase, Buffer);
DISALLOW_COPY_AND_ASSIGN(VertexBufferBase);
};
// VertexBuffer is Buffer object used for storing vertex data for geometry
// (e.g. vertex positions, normals, colors, etc). It is an abstract class
// declaring the interface only. Each rendering platform should derive its own
// implementation of the interface.
//
// NOTE: You can not READ data from a VertexBuffer.
class VertexBuffer : public VertexBufferBase {
public:
typedef SmartPointer<VertexBuffer> Ref;
protected:
explicit VertexBuffer(ServiceLocator* service_locator);
private:
friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
O3D_DECL_CLASS(VertexBuffer, VertexBufferBase);
DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
};
// SourceBuffer is a buffer object stored in system memory. It is used as
// the source for skinning, morph targets, etc.
class SourceBuffer : public VertexBufferBase {
public:
typedef SmartPointer<SourceBuffer> Ref;
~SourceBuffer();
protected:
// Overridden from Buffer.
virtual bool ConcreteAllocate(size_t size_in_bytes);
// Overridden from Buffer.
virtual bool ConcreteLock(AccessMode access_mode, void **buffer_data);
// Overridden from Buffer.
virtual bool ConcreteUnlock();
explicit SourceBuffer(ServiceLocator* service_locator);
protected:
// Frees the buffer if it exists.
void ConcreteFree();
private:
friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
scoped_array<char> buffer_; // The actual data for this buffer.
O3D_DECL_CLASS(SourceBuffer, VertexBufferBase);
DISALLOW_COPY_AND_ASSIGN(SourceBuffer);
};
// IndexBuffer is a buffer object used for storing geometry index data (e.g.
// triangle indices). It is an abstract class declaring the interface only.
// Each rendering platform should derive its own implementation of the
// interface.
//
// NOTE: You can not READ data from an IndexBuffer.
class IndexBuffer : public Buffer {
public:
typedef SmartPointer<IndexBuffer> Ref;
Field* index_field() const;
// De-serializes the data contained in |raw_data|
// The entire contents of |raw_data| from start to finish will
// be used
bool Set(o3d::RawData *raw_data) {
return Buffer::Set(raw_data);
}
// De-serializes the data contained in |raw_data|
// starting at byte offset |offset| and using |length|
// bytes
bool Set(o3d::RawData *raw_data,
size_t offset,
size_t length) {
return Buffer::Set(raw_data, offset, length);
}
protected:
explicit IndexBuffer(ServiceLocator* service_locator);
private:
friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
O3D_DECL_CLASS(IndexBuffer, Buffer);
DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
};
// BufferLockHelper can be used to lock a buffer in a safe way in that it will
// unlock the buffer on destruction so you can use it like this
//
// {
// BufferLockHelper helper(my_buffer);
// void* data = helper.GetData();
// if (data) {
// .. do something with data here ..
// }
// }
//
// Because there is no need to call Unlock it is much easier to deal with error
// conditions.
class BufferLockHelper {
public:
explicit BufferLockHelper(Buffer* buffer);
~BufferLockHelper();
// Gets a pointer to the data of the buffer, locking the buffer if necessary.
// Returns:
// Pointer to data in buffer or NULL if there was an error.
void* GetData(Buffer::AccessMode access_mode);
// Typed version of GetData
template <typename T>
T* GetDataAs(Buffer::AccessMode access_mode) {
return reinterpret_cast<T*>(GetData(access_mode));
}
private:
Buffer* buffer_;
void* data_;
bool locked_;
DISALLOW_COPY_AND_ASSIGN(BufferLockHelper);
};
} // namespace o3d
#endif // O3D_CORE_CROSS_BUFFER_H_