diff options
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/core/cross/buffer_test.cc | 2 | ||||
-rw-r--r-- | o3d/core/cross/field.cc | 59 | ||||
-rw-r--r-- | o3d/core/cross/field.h | 34 | ||||
-rw-r--r-- | o3d/core/cross/field_test.cc | 51 | ||||
-rw-r--r-- | o3d/core/cross/stream.h | 2 | ||||
-rw-r--r-- | o3d/core/cross/stream_test.cc | 2 | ||||
-rw-r--r-- | o3d/import/cross/collada.cc | 36 | ||||
-rw-r--r-- | o3d/serializer/cross/serializer_binary.cc | 8 |
8 files changed, 174 insertions, 20 deletions
diff --git a/o3d/core/cross/buffer_test.cc b/o3d/core/cross/buffer_test.cc index 002c955..7e4561e 100644 --- a/o3d/core/cross/buffer_test.cc +++ b/o3d/core/cross/buffer_test.cc @@ -551,7 +551,7 @@ TEST_F(BufferTest, TestVertexBufferFromRawData) { 0, &buffer_float_data[0], 3, kNumElements); down_cast<UInt32Field*>(buffer->fields()[1].Get())->GetAsUInt32s( 0, &buffer_int_data[0], 2, kNumElements); - down_cast<UByteNField*>(buffer->fields()[2].Get())->GetAsBytes( + down_cast<UByteNField*>(buffer->fields()[2].Get())->GetAsUByteNs( 0, &buffer_byte_data[0], 4, kNumElements); for (int i = 0; i < kNumElements; ++i) { diff --git a/o3d/core/cross/field.cc b/o3d/core/cross/field.cc index c85c9d3..1ccbfde 100644 --- a/o3d/core/cross/field.cc +++ b/o3d/core/cross/field.cc @@ -34,6 +34,7 @@ // IndexBuffer. #include "core/cross/precompile.h" +#include <vector> #include "core/cross/field.h" #include "core/cross/error.h" #include "core/cross/buffer.h" @@ -283,6 +284,23 @@ bool Field::RangeValid(unsigned int start_index, unsigned int num_elements) { return true; } +void Field::Copy(const Field& source) { + if (!source.IsA(GetClass())) { + O3D_ERROR(service_locator()) + << "source field of type " << source.GetClassName() + << " is not compatible with field of type " << GetClassName(); + return; + } + if (!source.buffer()) { + O3D_ERROR(service_locator()) << "source buffer is null"; + return; + } + if (!buffer()) { + O3D_ERROR(service_locator()) << "destination buffer is null"; + return; + } + ConcreteCopy(source); +} // FloatField ------------------- @@ -361,6 +379,16 @@ void FloatField::GetAsFloats(unsigned source_start_index, num_elements); } +void FloatField::ConcreteCopy(const Field& source) { + DCHECK(source.IsA(GetClass())); + DCHECK(source.buffer()); + unsigned num_components = source.num_components(); + unsigned num_elements = source.buffer()->num_elements(); + scoped_array<float> temp(new float[num_components * num_elements]); + source.GetAsFloats(0, temp.get(), num_components, num_elements); + SetFromFloats(temp.get(), num_components, 0, num_elements); +} + Field::Ref FloatField::Create(ServiceLocator* service_locator, Buffer* buffer, unsigned num_components, @@ -454,6 +482,17 @@ void UInt32Field::GetAsUInt32s(unsigned source_start_index, num_elements); } +void UInt32Field::ConcreteCopy(const Field& source) { + DCHECK(source.IsA(GetClass())); + DCHECK(source.buffer()); + unsigned num_components = source.num_components(); + unsigned num_elements = source.buffer()->num_elements(); + scoped_array<uint32> temp(new uint32[num_components * num_elements]); + down_cast<const UInt32Field*>(&source)->GetAsUInt32s( + 0, temp.get(), num_components, num_elements); + SetFromUInt32s(temp.get(), num_components, 0, num_elements); +} + Field::Ref UInt32Field::Create(ServiceLocator* service_locator, Buffer* buffer, unsigned num_components, @@ -543,10 +582,10 @@ void UByteNField::GetAsFloats(unsigned source_start_index, swizzle_table_); } -void UByteNField::GetAsBytes(unsigned source_start_index, - uint8* destination, - unsigned destination_stride, - unsigned num_elements) const { +void UByteNField::GetAsUByteNs(unsigned source_start_index, + uint8* destination, + unsigned destination_stride, + unsigned num_elements) const { GetAsWithSwizzle<const uint8, uint8, ConvertUByteNToUByteN>( this, source_start_index, @@ -556,6 +595,18 @@ void UByteNField::GetAsBytes(unsigned source_start_index, swizzle_table_); } +void UByteNField::ConcreteCopy(const Field& source) { + DCHECK(source.IsA(GetClass())); + DCHECK(source.buffer()); + unsigned num_components = source.num_components(); + unsigned num_elements = source.buffer()->num_elements(); + scoped_array<uint8> temp(new uint8[num_components * num_elements]); + down_cast<const UByteNField*>(&source)->GetAsUByteNs( + 0, temp.get(), num_components, num_elements); + SetFromUByteNs(temp.get(), num_components, 0, num_elements); +} + + Field::Ref UByteNField::Create(ServiceLocator* service_locator, Buffer* buffer, unsigned num_components, diff --git a/o3d/core/cross/field.h b/o3d/core/cross/field.h index d44d556..212b003 100644 --- a/o3d/core/cross/field.h +++ b/o3d/core/cross/field.h @@ -163,6 +163,19 @@ class Field : public NamedObject { // outside the buffer associated with this field. bool RangeValid(unsigned int start_index, unsigned int num_elements); + // Copies a field. The field must be of the same type. + // Paremeters: + // source: field to copy from. + void Copy(const Field& source); + + protected: + // The concrete version of Copy. Copy calls this function to do the actual + // copying after it has verified the types are compatible and the buffers + // exist. ConcreteCopy does NOT have to check for those errors. + // Paremeters: + // source: field to copy from. + virtual void ConcreteCopy(const Field& source) = 0; + private: friend class Buffer; void set_offset(unsigned offset) { @@ -226,6 +239,10 @@ class FloatField : public Field { unsigned destination_stride, unsigned num_elements) const; + protected: + // Overridden from Field. + virtual void ConcreteCopy(const Field& source); + private: FloatField(ServiceLocator* service_locator, Buffer* buffer, @@ -297,6 +314,10 @@ class UInt32Field : public Field { unsigned destination_stride, unsigned num_elements) const; + protected: + // Overridden from Field. + virtual void ConcreteCopy(const Field& source); + private: UInt32Field(ServiceLocator* service_locator, Buffer* buffer, @@ -350,7 +371,7 @@ class UByteNField : public Field { unsigned destination_stride, unsigned num_elements) const; - // Gets this field as byte data. + // Gets this field as ubyten data. // // This function copies elements from the the field to the destination array. // It assumes that there are a multiple of N components in the destination @@ -364,11 +385,14 @@ class UByteNField : public Field { // destination_stride: stride between elements in the destination in // destination units. // num_elements: The number of elements to copy. - void GetAsBytes(unsigned source_start_index, - uint8* destination, - unsigned destination_stride, - unsigned num_elements) const; + void GetAsUByteNs(unsigned source_start_index, + uint8* destination, + unsigned destination_stride, + unsigned num_elements) const; + protected: + // Overridden from Field. + virtual void ConcreteCopy(const Field& source); private: UByteNField(ServiceLocator* service_locator, diff --git a/o3d/core/cross/field_test.cc b/o3d/core/cross/field_test.cc index b7ce54a..6340f30 100644 --- a/o3d/core/cross/field_test.cc +++ b/o3d/core/cross/field_test.cc @@ -261,6 +261,19 @@ TEST_F(FloatFieldTest, TestBasic) { kFloatsNumElements, kFloatsNumComponents)); + Field* new_field = buffer()->CreateField(FloatField::GetApparentClass(), + kFloatsNumComponents); + ASSERT_TRUE(new_field != NULL); + new_field->Copy(*field); + memset(&out_floats, 0, sizeof(out_floats)); + new_field->GetAsFloats(0, &out_floats[0][0], kFloatsStride, + kFloatsNumElements); + + EXPECT_TRUE(CompareElements(&kInFloats[0][0], + &out_floats[0][0], + kFloatsNumElements, + kFloatsNumComponents)); + field->SetFromUInt32s(&kInUInt32s[0][0], kUInt32sStride, 0, kUInt32sNumElements); @@ -355,6 +368,20 @@ TEST_F(UInt32FieldTest, TestBasic) { } } + Field* new_field = buffer()->CreateField(UInt32Field::GetApparentClass(), + kUInt32sNumComponents); + ASSERT_TRUE(new_field != NULL); + new_field->Copy(*field); + memset(&out_uint32s, 0, sizeof(out_uint32s)); + down_cast<UInt32Field*>(new_field)->GetAsUInt32s( + 0, &out_uint32s[0][0], kUInt32sStride, kUInt32sNumElements); + + for (unsigned jj = 0; jj < kUInt32sNumElements; ++jj) { + for (unsigned ii = 0; ii < kUInt32sNumComponents; ++ii) { + EXPECT_EQ(kInUInt32s[jj][ii], out_uint32s[jj][ii]); + } + } + memset(&out_floats, 0, sizeof(out_floats)); field->GetAsFloats(0, &out_floats[0][0], kFloatsStride, kUInt32sNumElements); @@ -451,17 +478,33 @@ TEST_F(UByteNFieldTest, TestBasic) { field->SetFromUByteNs(&kInUByteNs[0][0], kUByteNsStride, 0, kUByteNsNumElements); + uint8 out_ubytens[kUByteNsNumElements][kUByteNsNumComponents]; + memset(&out_ubytens, 0, sizeof(out_ubytens)); + down_cast<UByteNField*>(field)->GetAsUByteNs( + 0, &out_ubytens[0][0], kUByteNsStride, kUByteNsNumElements); - memset(&out_floats, 0, sizeof(out_floats)); - field->GetAsFloats(0, &out_floats[0][0], kFloatsStride, kUByteNsNumElements); + for (unsigned jj = 0; jj < kUByteNsNumElements; ++jj) { + for (unsigned ii = 0; ii < kUByteNsNumComponents; ++ii) { + EXPECT_EQ(kInUByteNs[jj][ii], out_ubytens[jj][ii]); + } + } + + Field* new_field = buffer()->CreateField(UByteNField::GetApparentClass(), + kUByteNsNumComponents); + ASSERT_TRUE(new_field != NULL); + new_field->Copy(*field); + + memset(&out_ubytens, 0, sizeof(out_ubytens)); + down_cast<UByteNField*>(new_field)->GetAsUByteNs( + 0, &out_ubytens[0][0], kUByteNsStride, kUByteNsNumElements); for (unsigned jj = 0; jj < kUByteNsNumElements; ++jj) { for (unsigned ii = 0; ii < kUByteNsNumComponents; ++ii) { - EXPECT_EQ(static_cast<float>(kInUByteNs[jj][ii] / 255.0f), - out_floats[jj][ii]); + EXPECT_EQ(kInUByteNs[jj][ii], out_ubytens[jj][ii]); } } + // Test that we can't make a UByteN field that is not multiple of 4 EXPECT_TRUE(buffer()->CreateField(UByteNField::GetApparentClass(), 1) == NULL); diff --git a/o3d/core/cross/stream.h b/o3d/core/cross/stream.h index 526b739..15830bd 100644 --- a/o3d/core/cross/stream.h +++ b/o3d/core/cross/stream.h @@ -70,7 +70,7 @@ class Stream : public ObjectBase { int semantic_index); // Returns a pointer to the associated Field object. - const Field& field() const { + Field& field() const { // This is guaranteed to be not NULL. return *field_.Get(); } diff --git a/o3d/core/cross/stream_test.cc b/o3d/core/cross/stream_test.cc index bd9d751..cfbacff 100644 --- a/o3d/core/cross/stream_test.cc +++ b/o3d/core/cross/stream_test.cc @@ -70,6 +70,8 @@ class FieldTest : public Field { unsigned num_elements) const { } virtual bool SetFromMemoryStream(MemoryReadStream* stream) { return true; } + + virtual void ConcreteCopy(const Field& source) { } }; } // end unnamed namespace diff --git a/o3d/import/cross/collada.cc b/o3d/import/cross/collada.cc index b62ae8f..64d39fc 100644 --- a/o3d/import/cross/collada.cc +++ b/o3d/import/cross/collada.cc @@ -1378,8 +1378,23 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, Matrix4 matrix(bind_shape_matrix); // Copy shape->primitive buffers. + // Here we need to also split the original vertex buffer. The issue is + // the original VertexBuffer might contain POSITION, NORMAL, TEXCOORD, + // COLOR. Of those, only POSITION and NORMAL are copied to the SourceBuffer. + // The VertexBuffer still contains POSITON, NORMAL, TEXCOORD, and COLOR so + // two issues come up + // + // 1) If we serialize that VertexBuffer, POSITION and NORMAL are stored + // twice. Once in the SourceBuffer, again in the VertexBuffer. That's a lot + // of data to download just to throw it away. + // + // 2) If we want to instance the skin we'll need to make a new VertexBuffer + // so we can store the skinned vertices for the second instance. But we'd + // like to share the COLOR and TEXCOORDS. To do that they need to be in + // a separate VertexBuffer. StreamBank* stream_bank = primitive->stream_bank(); SourceBuffer* buffer = pack_->Create<SourceBuffer>(); + VertexBuffer* shared_buffer = pack_->Create<VertexBuffer>(); const StreamParamVector& source_stream_params = stream_bank->vertex_stream_params(); std::vector<Field*> new_fields(source_stream_params.size(), NULL); @@ -1387,6 +1402,7 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, for (unsigned ii = 0; ii < source_stream_params.size(); ++ii) { const Stream& source_stream = source_stream_params[ii]->stream(); const Field& field = source_stream.field(); + bool copied = false; if (field.IsA(FloatField::GetApparentClass()) && (field.num_components() == 3 || field.num_components() == 4)) { @@ -1395,6 +1411,7 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, case Stream::NORMAL: case Stream::BINORMAL: case Stream::TANGENT: { + copied = true; unsigned num_source_components = field.num_components(); unsigned num_source_vertices = source_stream.GetMaxVertices(); if (num_source_vertices != num_vertices) { @@ -1410,9 +1427,15 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, } } } + if (!copied) { + // It's a shared field, copy it to the shared buffer. + new_fields[ii] = shared_buffer->CreateField(field.GetClass(), + field.num_components()); + } } - if (!buffer->AllocateElements(num_vertices)) { + if (!buffer->AllocateElements(num_vertices) || + !shared_buffer->AllocateElements(num_vertices)) { O3D_ERROR(service_locator_) << "Failed to allocate destination vertex buffer"; return NULL; @@ -1421,6 +1444,7 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, for (unsigned ii = 0; ii < source_stream_params.size(); ++ii) { const Stream& source_stream = source_stream_params[ii]->stream(); const Field& field = source_stream.field(); + bool copied = false; if (field.IsA(FloatField::GetApparentClass()) && (field.num_components() == 3 || field.num_components() == 4)) { @@ -1429,6 +1453,7 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, case Stream::NORMAL: case Stream::BINORMAL: case Stream::TANGENT: { + copied = true; unsigned num_source_components = field.num_components(); Field* new_field = new_fields[ii]; @@ -1485,6 +1510,15 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, } } } + if (!copied) { + Field* new_field = new_fields[ii]; + new_field->Copy(field); + field.buffer()->RemoveField(&source_stream.field()); + stream_bank->SetVertexStream(source_stream.semantic(), + source_stream.semantic_index(), + new_field, + 0); + } } } return shape; diff --git a/o3d/serializer/cross/serializer_binary.cc b/o3d/serializer/cross/serializer_binary.cc index 1af3e2c..9b7f523 100644 --- a/o3d/serializer/cross/serializer_binary.cc +++ b/o3d/serializer/cross/serializer_binary.cc @@ -144,10 +144,10 @@ void SerializeBuffer(const Buffer &buffer, MemoryBuffer<uint8> *output) { } else if (field.IsA(UByteNField::GetApparentClass())) { const UByteNField &byte_field = static_cast<const UByteNField&>(field); uint8 *byte_destination = reinterpret_cast<uint8*>(destination); - byte_field.GetAsBytes(0, - byte_destination, - field.num_components(), - num_elements); + byte_field.GetAsUByteNs(0, + byte_destination, + field.num_components(), + num_elements); // Write out the bytes stream.Write(byte_destination, nitems); } |