diff options
-rw-r--r-- | o3d/converter/cross/converter.cc | 4 | ||||
-rw-r--r-- | o3d/core/cross/object_base.cc | 10 | ||||
-rw-r--r-- | o3d/core/cross/object_base.h | 28 | ||||
-rw-r--r-- | o3d/core/cross/stream_bank.cc | 3 | ||||
-rw-r--r-- | o3d/import/build.scons | 1 | ||||
-rw-r--r-- | o3d/import/cross/collada.cc | 152 | ||||
-rw-r--r-- | o3d/import/cross/collada.h | 8 | ||||
-rw-r--r-- | o3d/import/cross/destination_buffer.cc | 79 | ||||
-rw-r--r-- | o3d/import/cross/destination_buffer.h | 83 | ||||
-rw-r--r-- | o3d/import/cross/destination_buffer_test.cc | 104 | ||||
-rw-r--r-- | o3d/samples/o3djs/serialization.js | 14 | ||||
-rw-r--r-- | o3d/serializer/cross/serializer.cc | 33 | ||||
-rw-r--r-- | o3d/serializer/cross/version.h | 2 | ||||
-rw-r--r-- | o3d/tests/build.scons | 11 | ||||
-rw-r--r-- | o3d/tests/selenium/tests/serialization-test.html | 38 |
15 files changed, 517 insertions, 53 deletions
diff --git a/o3d/converter/cross/converter.cc b/o3d/converter/cross/converter.cc index 6f50787..42d7996 100644 --- a/o3d/converter/cross/converter.cc +++ b/o3d/converter/cross/converter.cc @@ -94,6 +94,7 @@ bool Convert(const FilePath& in_filename, ErrorStatus error_status(&service_locator); Features features(&service_locator); + Collada::Init(&service_locator); features.Init("MaxCapabilities"); // Collect error messages. @@ -119,7 +120,8 @@ bool Convert(const FilePath& in_filename, collada_options.base_path = options.base_path; collada_options.up_axis = options.up_axis; Collada collada(pack.Get(), collada_options); - if (!collada.ImportFile(in_filename, root, param_float)) { + bool result = collada.ImportFile(in_filename, root, param_float); + if (!result || !error_collector.errors().empty()) { if (error_messages) { *error_messages += error_collector.errors(); } diff --git a/o3d/core/cross/object_base.cc b/o3d/core/cross/object_base.cc index 36cc43f..7a91f41 100644 --- a/o3d/core/cross/object_base.cc +++ b/o3d/core/cross/object_base.cc @@ -44,6 +44,16 @@ ObjectBase::Class ObjectBase::class_ = { O3D_STRING_CONSTANT("ObjectBase"), NULL }; +const char* ObjectBase::Class::unqualified_name() const { + if (strncmp( + name_, + O3D_NAMESPACE O3D_NAMESPACE_SEPARATOR, + sizeof(O3D_NAMESPACE) + sizeof(O3D_NAMESPACE_SEPARATOR) - 2) == 0) { + return name_ + sizeof(O3D_NAMESPACE) + sizeof(O3D_NAMESPACE_SEPARATOR) - 2; + } + return name_; +} + ObjectBase::ObjectBase(ServiceLocator *service_locator) : id_(IdManager::CreateId()), service_locator_(service_locator) { diff --git a/o3d/core/cross/object_base.h b/o3d/core/cross/object_base.h index 0fa9edf..9a174c0 100644 --- a/o3d/core/cross/object_base.h +++ b/o3d/core/cross/object_base.h @@ -50,11 +50,12 @@ #define O3D_STRING_CONSTANT(value) \ (O3D_NAMESPACE O3D_NAMESPACE_SEPARATOR value) + // This macro declares the necessary functions for the type mechanism to work. // It needs to be used in each of the definition of any class that derives from // ObjectBase. // CLASS is the class being defined, BASE is its base class. -#define O3D_DECL_CLASS(CLASS, BASE) \ +#define O3D_OBJECT_BASE_DECL_CLASS(CLASS, BASE) \ public: \ static const ObjectBase::Class *GetApparentClass() { return &class_; } \ static const String GetApparentClassName() { \ @@ -72,10 +73,24 @@ // This macro defines the class descriptor for the type mechanism. It needs to // be used once in the definition file of any class that derives from // ObjectBase. +// CLASSNAME is the name to use to identify the class. +// CLASS is the class being defined. +// BASE is its base class. +#define O3D_OBJECT_BASE_DEFN_CLASS(CLASSNAME, CLASS, BASE) \ + ObjectBase::Class CLASS::class_ = { CLASSNAME, BASE::GetApparentClass() }; + +// This macro declares the necessary functions for the type mechanism to work. +// It needs to be used in each of the definition of any class that derives from +// ObjectBase. // CLASS is the class being defined, BASE is its base class. -#define O3D_DEFN_CLASS(CLASS, BASE) \ - ObjectBase::Class CLASS::class_ = \ - { O3D_STRING_CONSTANT(#CLASS), BASE::GetApparentClass() }; +#define O3D_DECL_CLASS(CLASS, BASE) O3D_OBJECT_BASE_DECL_CLASS(CLASS, BASE) + +// This macro defines the class descriptor for the type mechanism. It needs to +// be used once in the definition file of any class that derives from +// ObjectBase. +// CLASS is the class being defined, BASE is its base class. +#define O3D_DEFN_CLASS(CLASS, BASE) \ + O3D_OBJECT_BASE_DEFN_CLASS(O3D_STRING_CONSTANT(#CLASS), CLASS, BASE) namespace o3d { @@ -142,10 +157,7 @@ class ObjectBase : public RefCounted { return name_; } - const char* unqualified_name() const { - return name_ + sizeof(O3D_NAMESPACE) + - sizeof(O3D_NAMESPACE_SEPARATOR) - 2; - } + const char* unqualified_name() const; public: // The name of the class. diff --git a/o3d/core/cross/stream_bank.cc b/o3d/core/cross/stream_bank.cc index 54c5f2d..65f6b73 100644 --- a/o3d/core/cross/stream_bank.cc +++ b/o3d/core/cross/stream_bank.cc @@ -89,6 +89,9 @@ bool StreamBank::SetVertexStream(Stream::Semantic stream_semantic, O3D_ERROR(service_locator()) << "No buffer on field"; return false; } + + // Check that this buffer is renderable. StreamBanks are used to submit + // data to GPU so we can only allow GPU accessible buffers through here. if (!buffer->IsA(VertexBuffer::GetApparentClass())) { O3D_ERROR(service_locator()) << "Buffer is not a VertexBuffer"; return false; diff --git a/o3d/import/build.scons b/o3d/import/build.scons index 554750b..a695a0a 100644 --- a/o3d/import/build.scons +++ b/o3d/import/build.scons @@ -64,6 +64,7 @@ else: collada_inputs = [ 'cross/collada.cc', 'cross/collada_zip_archive.cc', + 'cross/destination_buffer.cc', 'cross/zip_archive.cc', 'cross/gz_compressor.cc', 'cross/file_output_stream_processor.cc', diff --git a/o3d/import/cross/collada.cc b/o3d/import/cross/collada.cc index e2041e86..6379274 100644 --- a/o3d/import/cross/collada.cc +++ b/o3d/import/cross/collada.cc @@ -36,6 +36,7 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/string_util.h" +#include "core/cross/class_manager.h" #include "core/cross/curve.h" #include "core/cross/error.h" #include "core/cross/function.h" @@ -53,6 +54,7 @@ #include "import/cross/collada.h" #include "import/cross/collada_conditioner.h" #include "import/cross/collada_zip_archive.h" +#include "import/cross/destination_buffer.h" #include "utils/cross/file_path_utils.h" #define COLLADA_NAMESPACE "collada" @@ -147,6 +149,12 @@ bool Collada::Import(Pack* pack, options); } +void Collada::Init(ServiceLocator* service_locator) { + ClassManager* class_manager= + service_locator->GetService<o3d::ClassManager>(); + class_manager->AddTypedClass<DestinationBuffer>(); +} + // Parameters: // pack: The pack into which the scene objects will be placed. // Returns true on success. @@ -391,11 +399,13 @@ bool Collada::ImportDAEDocument(FCDocument* doc, FCDSceneNode* scene = doc->GetVisualSceneInstance(); if (scene) { instance_root_ = CreateInstanceTree(scene); - ImportTree(instance_root_, parent, animation_input); - ImportTreeInstances(doc, instance_root_); + if (ImportTree(instance_root_, parent, animation_input)) { + if (ImportTreeInstances(doc, instance_root_)) { + status = true; + } + } delete instance_root_; instance_root_ = NULL; - status = true; } } } @@ -796,7 +806,7 @@ NodeInstance *Collada::FindNodeInstanceFast(FCDSceneNode *node) { // animation_input: The float parameter used as the input to the animation // (if present). This is usually time. This can be null // if there is no animation. -void Collada::ImportTree(NodeInstance *instance, +bool Collada::ImportTree(NodeInstance *instance, Transform* parent_transform, ParamFloat* animation_input) { FCDSceneNode *node = instance->node(); @@ -807,17 +817,22 @@ void Collada::ImportTree(NodeInstance *instance, // recursively import the rest of the nodes in the tree const NodeInstance::NodeInstanceList &children = instance->children(); for (size_t i = 0; i < children.size(); ++i) { - ImportTree(children[i], transform, animation_input); + if (!ImportTree(children[i], transform, animation_input)) { + return false; + } } + return true; } -void Collada::ImportTreeInstances(FCDocument* doc, +bool Collada::ImportTreeInstances(FCDocument* doc, NodeInstance *node_instance) { FCDSceneNode *node = node_instance->node(); // recursively import the rest of the nodes in the tree const NodeInstance::NodeInstanceList &children = node_instance->children(); for (size_t i = 0; i < children.size(); ++i) { - ImportTreeInstances(doc, children[i]); + if (!ImportTreeInstances(doc, children[i])) { + return false; + } } Transform* transform = node_instance->transform(); @@ -847,9 +862,19 @@ void Collada::ImportTreeInstances(FCDocument* doc, case FCDEntity::CONTROLLER: { FCDControllerInstance* controller_instance = static_cast<FCDControllerInstance*> (instance); - Shape* shape = GetSkinnedShape(doc, controller_instance, node_instance); - if (shape) { - transform->AddShape(shape); + FCDController* controller = + static_cast<FCDController*>(controller_instance->GetEntity()); + if (controller) { + if (controller->IsSkin()) { + Shape* shape = GetSkinnedShape(doc, + controller_instance, + node_instance); + if (shape) { + transform->AddShape(shape); + } else { + return false; + } + } } break; } @@ -858,6 +883,7 @@ void Collada::ImportTreeInstances(FCDocument* doc, break; } } + return true; } // Converts an FCollada vertex attribute semantic into an O3D @@ -1318,9 +1344,23 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, // skin everything. This is actually what was BuildShape was doing at the // time this code was written. const ElementRefArray& elements = shape->GetElementRefs(); - if (elements.empty() || !elements[0]->IsA(Primitive::GetApparentClass())) { + if (elements.empty()) { return NULL; } + // check that they all use the same StreamBank and are all Primitives + for (unsigned ii = 0; ii < elements.size(); ++ii) { + if (!elements[ii]->IsA(Primitive::GetApparentClass())) { + O3D_ERROR(service_locator_) + << "Element in Shape '" << shape->name() << "' is not a Primitive."; + return NULL; + } + if (down_cast<Primitive*>(elements[ii].Get())->stream_bank() != + down_cast<Primitive*>(elements[0].Get())->stream_bank()) { + O3D_ERROR(service_locator_) + << "More than one StreamBank in Shape '" << shape->name() << "'."; + return NULL; + } + } Primitive* primitive = down_cast<Primitive*>(elements[0].Get()); String controller_name = WideToUTF8(controller->GetName().c_str()); @@ -1412,16 +1452,29 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, // 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>(); + StreamBank* old_stream_bank = primitive->stream_bank(); + StreamBank* new_stream_bank = pack_->Create<StreamBank>(); + new_stream_bank->set_name(String("skinned_") + old_stream_bank->name()); + Buffer* old_buffer = NULL; + SourceBuffer* source_buffer = pack_->Create<SourceBuffer>(); VertexBuffer* shared_buffer = pack_->Create<VertexBuffer>(); + DestinationBuffer* dest_buffer = pack_->Create<DestinationBuffer>(); const StreamParamVector& source_stream_params = - stream_bank->vertex_stream_params(); - std::vector<Field*> new_fields(source_stream_params.size(), NULL); + old_stream_bank->vertex_stream_params(); + std::vector<Field*> source_fields(source_stream_params.size(), NULL); + std::vector<Field*> dest_fields(source_stream_params.size(), NULL); // first make all the fields. 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(); + if (old_buffer == NULL) { + old_buffer = field.buffer(); + } else if (old_buffer != field.buffer()) { + O3D_ERROR(service_locator_) + << "More than 1 buffer used by StreamBank '" + << old_stream_bank->name().c_str() + << "' which the collada importer does not currently support"; + } bool copied = false; if (field.IsA(FloatField::GetApparentClass()) && (field.num_components() == 3 || @@ -1437,25 +1490,44 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, if (num_source_vertices != num_vertices) { O3D_ERROR(service_locator_) << "Number of vertices in stream_bank '" - << stream_bank->name().c_str() + << old_stream_bank->name().c_str() << "' does not equal the number of vertices in the Skin '" << skin->name().c_str() << "'"; return NULL; } - new_fields[ii] = buffer->CreateField(FloatField::GetApparentClass(), - num_source_components); + source_fields[ii] = source_buffer->CreateField( + FloatField::GetApparentClass(), num_source_components); + DCHECK(source_fields[ii]); + dest_fields[ii] = dest_buffer->CreateField( + FloatField::GetApparentClass(), num_source_components); + DCHECK(dest_fields[ii]); + if (!new_stream_bank->SetVertexStream( + source_stream.semantic(), + source_stream.semantic_index(), + dest_fields[ii], + 0)) { + O3D_ERROR(service_locator_) + << "could not SetVertexStream on StreamBank '" + << new_stream_bank->name() << "'"; + return NULL; + } } } } if (!copied) { // It's a shared field, copy it to the shared buffer. - new_fields[ii] = shared_buffer->CreateField(field.GetClass(), - field.num_components()); + source_fields[ii] = shared_buffer->CreateField(field.GetClass(), + field.num_components()); + new_stream_bank->SetVertexStream(source_stream.semantic(), + source_stream.semantic_index(), + source_fields[ii], + 0); } } - if (!buffer->AllocateElements(num_vertices) || - !shared_buffer->AllocateElements(num_vertices)) { + if (!source_buffer->AllocateElements(num_vertices) || + !shared_buffer->AllocateElements(num_vertices) || + !dest_buffer->AllocateElements(num_vertices)) { O3D_ERROR(service_locator_) << "Failed to allocate destination vertex buffer"; return NULL; @@ -1475,7 +1547,7 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, case Stream::TANGENT: { copied = true; unsigned num_source_components = field.num_components(); - Field* new_field = new_fields[ii]; + Field* source_field = source_fields[ii]; std::vector<float> data(num_vertices * num_source_components); field.GetAsFloats(0, &data[0], num_source_components, @@ -1516,30 +1588,38 @@ Shape* Collada::BuildSkinnedShape(FCDocument* doc, } } } - new_field->SetFromFloats(&data[0], num_source_components, 0, - num_vertices); + source_field->SetFromFloats(&data[0], num_source_components, 0, + num_vertices); // Bind streams skin_eval->SetVertexStream(source_stream.semantic(), source_stream.semantic_index(), - new_field, + source_field, 0); - stream_bank->BindStream(skin_eval, - source_stream.semantic(), - source_stream.semantic_index()); + new_stream_bank->BindStream(skin_eval, + source_stream.semantic(), + source_stream.semantic_index()); break; } } } 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); + Field* source_field = source_fields[ii]; + source_field->Copy(field); } } + + // Set all primitives to use new stream bank. + for (unsigned ii = 0; ii < elements.size(); ++ii) { + down_cast<Primitive*>(elements[ii].Get())->set_stream_bank( + new_stream_bank); + } + pack_->RemoveObject(old_stream_bank); + if (old_buffer) { + source_buffer->set_name(String("source_") + old_buffer->name()); + dest_buffer->set_name(String("skinned_") + old_buffer->name()); + shared_buffer->set_name(String("shared_") + old_buffer->name()); + pack_->RemoveObject(old_buffer); + } } return shape; } diff --git a/o3d/import/cross/collada.h b/o3d/import/cross/collada.h index a3aa963..77382d8 100644 --- a/o3d/import/cross/collada.h +++ b/o3d/import/cross/collada.h @@ -66,6 +66,7 @@ class FilePath; namespace o3d { +class ClassManager; class ColladaZipArchive; class Effect; class IErrorStatus; @@ -221,6 +222,9 @@ class Collada { std::vector<FilePath> GetOriginalDataFilenames() const; const std::string& GetOriginalData(const FilePath& filename) const; + // Init the Collada Importer. + static void Init(ServiceLocator* service_locator); + private: // Imports the given ZIP file into the given pack. bool ImportZIP(const FilePath& filename, Transform* parent, @@ -244,7 +248,7 @@ class Collada { // Recursively imports a tree of nodes from FCollada, rooted at the // given node, into the O3D scene. - void ImportTree(NodeInstance *instance, + bool ImportTree(NodeInstance *instance, Transform* parent, ParamFloat* animation_input); @@ -252,7 +256,7 @@ class Collada { // rooted at the given node, into the O3D scene. This is a separate step // from ImportTree because various kinds of instances can reference other // parts of the tree. - void ImportTreeInstances(FCDocument* doc, + bool ImportTreeInstances(FCDocument* doc, NodeInstance* instance); bool BuildFloatAnimation(ParamFloat* result, diff --git a/o3d/import/cross/destination_buffer.cc b/o3d/import/cross/destination_buffer.cc new file mode 100644 index 0000000..5aa3124 --- /dev/null +++ b/o3d/import/cross/destination_buffer.cc @@ -0,0 +1,79 @@ +/*
+ * 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.
+ */
+
+#include "import/cross/destination_buffer.h"
+
+namespace o3d {
+
+O3D_OBJECT_BASE_DEFN_CLASS(
+ "o3djs.DestinationBuffer", DestinationBuffer, VertexBuffer);
+
+DestinationBuffer::DestinationBuffer(ServiceLocator* service_locator)
+ : VertexBuffer(service_locator),
+ buffer_() {
+}
+
+DestinationBuffer::~DestinationBuffer() {
+ ConcreteFree();
+}
+
+void DestinationBuffer::ConcreteFree() {
+ buffer_.reset();
+}
+
+bool DestinationBuffer::ConcreteAllocate(size_t size_in_bytes) {
+ ConcreteFree();
+
+ buffer_.reset(new char[size_in_bytes]);
+
+ return true;
+}
+
+bool DestinationBuffer::ConcreteLock(AccessMode access_mode,
+ void **buffer_data) {
+ if (!buffer_.get()) {
+ return false;
+ }
+
+ *buffer_data = reinterpret_cast<void*>(buffer_.get());
+ return true;
+}
+
+bool DestinationBuffer::ConcreteUnlock() {
+ return buffer_.get() != NULL;
+}
+
+ObjectBase::Ref DestinationBuffer::Create(ServiceLocator* service_locator) {
+ return ObjectBase::Ref(new DestinationBuffer(service_locator));
+}
+
+} // namespace o3d
+
diff --git a/o3d/import/cross/destination_buffer.h b/o3d/import/cross/destination_buffer.h new file mode 100644 index 0000000..5b12e34 --- /dev/null +++ b/o3d/import/cross/destination_buffer.h @@ -0,0 +1,83 @@ +/*
+ * 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 declares the DestinationBuffer class.
+
+#ifndef O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+#define O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+
+#include "core/cross/buffer.h"
+
+namespace o3d {
+
+// DestinationBuffer is a used for serialization only and is not part of the
+// normal O3D plugin. It is used for Skinning to distinguish between a normal
+// VertexBuffer that needs to have its contents serialized and a
+// DestinationBuffer that only needs to know its structure but not its
+// contents.
+class DestinationBuffer : public VertexBuffer {
+ public:
+ typedef SmartPointer<DestinationBuffer> Ref;
+
+ ~DestinationBuffer();
+
+ 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 DestinationBuffer(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_OBJECT_BASE_DECL_CLASS(DestinationBuffer, VertexBuffer);
+ DISALLOW_COPY_AND_ASSIGN(DestinationBuffer);
+};
+
+
+} // namespace o3d
+
+#endif // O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+
diff --git a/o3d/import/cross/destination_buffer_test.cc b/o3d/import/cross/destination_buffer_test.cc new file mode 100644 index 0000000..c7f69d3 --- /dev/null +++ b/o3d/import/cross/destination_buffer_test.cc @@ -0,0 +1,104 @@ +/*
+ * 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.
+ */
+
+#include "tests/common/win/testing_common.h"
+#include "import/cross/destination_buffer.h"
+#include "core/cross/class_manager.h"
+#include "core/cross/object_manager.h"
+#include "core/cross/pack.h"
+#include "core/cross/service_dependency.h"
+
+namespace o3d {
+
+class DestinationBufferTest : public testing::Test {
+ protected:
+ DestinationBufferTest()
+ : class_manager_(g_service_locator),
+ object_manager_(g_service_locator) {
+ class_manager_->AddTypedClass<DestinationBuffer>();
+ }
+
+ virtual void SetUp();
+ virtual void TearDown();
+
+ Pack* pack() { return pack_; }
+
+ private:
+ ServiceDependency<ClassManager> class_manager_;
+ ServiceDependency<ObjectManager> object_manager_;
+ Pack* pack_;
+};
+
+void DestinationBufferTest::SetUp() {
+ pack_ = object_manager_->CreatePack();
+}
+
+void DestinationBufferTest::TearDown() {
+ object_manager_->DestroyPack(pack_);
+}
+
+
+// Creates a Destination buffer, tests basic properties, and checks that writing
+// then reading data works.
+TEST_F(DestinationBufferTest, TestDestinationBuffer) {
+ Buffer *buffer = pack()->Create<DestinationBuffer>();
+ EXPECT_TRUE(buffer->IsA(DestinationBuffer::GetApparentClass()));
+ EXPECT_TRUE(buffer->IsA(VertexBuffer::GetApparentClass()));
+ EXPECT_TRUE(buffer->IsA(Buffer::GetApparentClass()));
+
+ const size_t kSize = 100;
+ Field* field = buffer->CreateField(UInt32Field::GetApparentClass(), 1);
+ ASSERT_TRUE(field != NULL);
+ ASSERT_TRUE(buffer->AllocateElements(kSize));
+ EXPECT_EQ(kSize * sizeof(uint32), buffer->GetSizeInBytes()); // NOLINT
+
+ // Put some data into the buffer.
+ uint32 *data = NULL;
+ ASSERT_TRUE(buffer->LockAs(Buffer::WRITE_ONLY, &data));
+ ASSERT_TRUE(data != NULL);
+ for (uint32 i = 0; i < kSize; ++i) {
+ data[i] = i;
+ }
+ ASSERT_TRUE(buffer->Unlock());
+
+ data = NULL;
+ // Read the data from the buffer, checks that it's the expected values.
+ ASSERT_TRUE(buffer->LockAs(Buffer::READ_ONLY, &data));
+ ASSERT_TRUE(data != NULL);
+ for (uint32 i = 0; i < kSize; ++i) {
+ EXPECT_EQ(i, data[i]);
+ }
+ ASSERT_TRUE(buffer->Unlock());
+}
+
+
+} // namespace o3d
+
diff --git a/o3d/samples/o3djs/serialization.js b/o3d/samples/o3djs/serialization.js index a8b4ea5..bc459a3 100644 --- a/o3d/samples/o3djs/serialization.js +++ b/o3d/samples/o3djs/serialization.js @@ -96,6 +96,20 @@ o3djs.serialization.Deserializer = function(pack, json) { * @type {!Object} */ this.createCallbacks = { + 'o3djs.DestinationBuffer': function(deserializer, json) { + var object = deserializer.pack.createObject('o3d.VertexBuffer'); + if ('custom' in json) { + for (var i = 0; i < json.custom.fields.length; ++i) { + var fieldInfo = json.custom.fields[i] + var field = object.createField(fieldInfo.type, + fieldInfo.numComponents); + deserializer.addObject(fieldInfo.id, field); + } + object.allocateElements(json.custom.numElements); + } + return object; + }, + 'o3d.VertexBuffer': function(deserializer, json) { var object = deserializer.pack.createObject('o3d.VertexBuffer'); if ('custom' in json) { diff --git a/o3d/serializer/cross/serializer.cc b/o3d/serializer/cross/serializer.cc index 066ce30..25996c8 100644 --- a/o3d/serializer/cross/serializer.cc +++ b/o3d/serializer/cross/serializer.cc @@ -47,6 +47,7 @@ #include "core/cross/skin.h" #include "core/cross/texture.h" #include "core/cross/transform.h" +#include "import/cross/destination_buffer.h" #include "import/cross/iarchive_generator.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" @@ -345,6 +346,7 @@ class CustomVisitor : public VisitorBase<CustomVisitor> { BinaryArchiveManager* binary_archive_manager) : writer_(writer), binary_archive_manager_(binary_archive_manager) { + Enable<DestinationBuffer>(&CustomVisitor::Visit); Enable<Buffer>(&CustomVisitor::Visit); Enable<Curve>(&CustomVisitor::Visit); Enable<Primitive>(&CustomVisitor::Visit); @@ -356,6 +358,31 @@ class CustomVisitor : public VisitorBase<CustomVisitor> { } private: + void Visit(DestinationBuffer* buffer) { + // NOTE: We don't call Visit<VertexBuffer*> because we don't want to + // serialize the contents of the Buffer. We only serialize its structure. + Visit(static_cast<NamedObject*>(buffer)); + writer_->WritePropertyName("numElements"); + Serialize(writer_, buffer->num_elements()); + writer_->WritePropertyName("fields"); + writer_->OpenArray(); + const FieldRefArray& fields = buffer->fields(); + for (size_t ii = 0; ii < fields.size(); ++ii) { + Field* field = fields[ii].Get(); + writer_->BeginCompacting(); + writer_->OpenObject(); + writer_->WritePropertyName("id"); + Serialize(writer_, field->id()); + writer_->WritePropertyName("type"); + Serialize(writer_, field->GetClassName()); + writer_->WritePropertyName("numComponents"); + Serialize(writer_, field->num_components()); + writer_->CloseObject(); + writer_->EndCompacting(); + } + writer_->CloseArray(); + } + void Visit(Buffer* buffer) { Visit(static_cast<NamedObject*>(buffer)); @@ -585,6 +612,7 @@ class BinaryVisitor : public VisitorBase<BinaryVisitor> { : binary_archive_manager_(binary_archive_manager) { Enable<Curve>(&BinaryVisitor::Visit); Enable<IndexBuffer>(&BinaryVisitor::Visit); + Enable<DestinationBuffer>(&BinaryVisitor::Visit); Enable<VertexBufferBase>(&BinaryVisitor::Visit); Enable<Skin>(&BinaryVisitor::Visit); } @@ -608,6 +636,11 @@ class BinaryVisitor : public VisitorBase<BinaryVisitor> { serialized_data.GetLength()); } + void Visit(DestinationBuffer* buffer) { + // Destination buffers should NOT have their contents serialized. + Visit(static_cast<Buffer*>(buffer)); + } + void Visit(IndexBuffer* buffer) { Visit(static_cast<Buffer*>(buffer)); diff --git a/o3d/serializer/cross/version.h b/o3d/serializer/cross/version.h index 6792023..619ad3b 100644 --- a/o3d/serializer/cross/version.h +++ b/o3d/serializer/cross/version.h @@ -39,7 +39,7 @@ #define O3D_SERIALIZER_CROSS_VERSION_H_ namespace o3d { -const int kSerializerVersion = 5; +const int kSerializerVersion = 6; } #endif // O3D_SERIALIZER_CROSS_VERSION_H_ diff --git a/o3d/tests/build.scons b/o3d/tests/build.scons index 218fbda..58b897c 100644 --- a/o3d/tests/build.scons +++ b/o3d/tests/build.scons @@ -217,6 +217,7 @@ tests = [ 'core/cross/vertex_source_test.cc', 'core/cross/visitor_base_test.cc', 'core/cross/weak_ptr_test.cc', + 'import/cross/destination_buffer_test.cc', 'import/cross/gz_compressor_test.cc', 'import/cross/gz_decompressor_test.cc', 'import/cross/memory_buffer_test.cc', @@ -458,10 +459,10 @@ if ARGUMENTS.get('SYSTEM_TESTS_ENABLED', False): # Also require gl related libraries based on variant. system_tests_req += gl_requirements - + # Require SwiftShader (only if it is available). system_tests_req += swiftshader_install - + # Add requirements for system_tests. env.Requires(system_tests_install, system_tests_req) @@ -542,7 +543,7 @@ selenium_good_to_go = True if run_env.Bit('mac'): plugin_path = '$ARTIFACTS_DIR/O3D.plugin' - + if run_env['MAC_HERMETIC_FIREFOX_DIR']: # if we have a hermetic version of Firefox, then run it if os.path.exists(run_env.subst('$MAC_HERMETIC_FIREFOX_DIR')): @@ -579,7 +580,7 @@ if run_env.Bit('mac'): cleanup_steps = [ 'rm -rf "$MAC_FIREFOX_DIR"', ] - + def DeferSelenium(env): if not selenium_good_to_go: @@ -604,7 +605,7 @@ def DeferSelenium(env): '--screenshotsdir=$ARTIFACTS_DIR/selenium/screenshots_firefox'])] + cleanup_steps, ) - + # Require SwiftShader (only if it is available). run_env.Requires(run_selenium_firefox, swiftshader_install) diff --git a/o3d/tests/selenium/tests/serialization-test.html b/o3d/tests/selenium/tests/serialization-test.html index dcb5ddc..a59b0cb 100644 --- a/o3d/tests/selenium/tests/serialization-test.html +++ b/o3d/tests/selenium/tests/serialization-test.html @@ -929,6 +929,44 @@ g_suite.testShouldSetVertexBufferData = function() { g_test.assertEquals(12, field.size); }; +g_suite.testShouldSetDestinationBufferData = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3djs.DestinationBuffer': [ + { + 'custom':{ + 'numElements':1398, + 'fields':[ + { + 'id':197809, + 'type':'o3d.FloatField', + 'numComponents':3}, + { + 'id':197813, + 'type':'o3d.FloatField', + 'numComponents':3}] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var buffer = pack.objects[0]; + g_test.assertEquals(1398, buffer.numElements); + g_test.assertEquals(2, buffer.fields.length); + var field = buffer.fields[0]; + g_test.assertEquals('o3d.FloatField', field.className); + g_test.assertEquals(3, field.numComponents); + g_test.assertEquals(12, field.size); +}; + g_suite.testShouldSetSourceBufferData = function() { var json = { version: o3djs.serialization.supportedVersion, |