/* * 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 serializer code for binary objects: // Buffer, Curve, Skin... #include #include "core/cross/buffer.h" #include "core/cross/curve.h" #include "core/cross/error.h" #include "core/cross/skin.h" #include "import/cross/memory_buffer.h" #include "import/cross/memory_stream.h" const size_t kSerializationIDSize = 4; const size_t kVersionSize = sizeof(int32); namespace o3d { // |output| will be filled with the serialized data void SerializeBuffer(const Buffer &buffer, MemoryBuffer *output) { // Determine the total size for the serialization data const unsigned num_elements = buffer.num_elements(); const size_t num_fields = buffer.fields().size(); const size_t kNumFieldsSize = sizeof(int32); const size_t kSingleFieldInfoSize = 2 * sizeof(uint8); // id / num_components const size_t all_field_infos_size = num_fields * kSingleFieldInfoSize; const size_t kNumElementsSize = sizeof(int32); // Add up all the parts comprising the header const size_t header_size = kSerializationIDSize + kVersionSize + kNumFieldsSize + all_field_infos_size + kNumElementsSize; const size_t data_size = buffer.GetSizeInBytes(); const size_t total_size = header_size + data_size; output->Resize(total_size); MemoryWriteStream stream(*output, total_size); // write out serialization ID for buffer stream.Write(Buffer::kSerializationID, 4); // write out version stream.WriteLittleEndianInt32(1); // write out number of fields stream.WriteLittleEndianInt32(static_cast(num_fields)); // Write out the specification for the fields for (size_t i = 0; i < num_fields; ++i) { const Field &field = *buffer.fields()[i]; // Determine the FIELDID code we need to write out // Start out "unknown" until we determine the class uint8 field_id = Field::FIELDID_UNKNOWN; if (field.IsA(FloatField::GetApparentClass())) { field_id = Field::FIELDID_FLOAT32; } else if (field.IsA(UInt32Field::GetApparentClass())) { field_id = Field::FIELDID_UINT32; } else if (field.IsA(UByteNField::GetApparentClass())) { field_id = Field::FIELDID_BYTE; } else { O3D_ERROR(buffer.service_locator()) << "illegal buffer field"; return; } stream.WriteByte(field_id); stream.WriteByte(field.num_components()); } // Write out the number of elements stream.WriteLittleEndianUInt32(num_elements); // Write out the data for each field // Write out the specification for the fields for (size_t i = 0; i < num_fields; ++i) { const Field &field = *buffer.fields()[i]; MemoryBuffer field_data(field.size() * num_elements); uint8 *destination = field_data; // Figure out what type of field it is, and get the data // appropriately size_t nitems = num_elements * field.num_components(); if (field.IsA(FloatField::GetApparentClass())) { float *float_destination = reinterpret_cast(destination); field.GetAsFloats(0, float_destination, field.num_components(), num_elements); // Write out as little endian float32 for (size_t i = 0; i < nitems; ++i) { stream.WriteLittleEndianFloat32(float_destination[i]); } } else if (field.IsA(UInt32Field::GetApparentClass())) { const UInt32Field &int_field = static_cast(field); uint32 *int_destination = reinterpret_cast(destination); int_field.GetAsUInt32s(0, int_destination, field.num_components(), num_elements); // Write out as little endian int32 for (size_t i = 0; i < nitems; ++i) { stream.WriteLittleEndianInt32(int_destination[i]); } } else if (field.IsA(UByteNField::GetApparentClass())) { const UByteNField &byte_field = static_cast(field); uint8 *byte_destination = reinterpret_cast(destination); byte_field.GetAsUByteNs(0, byte_destination, field.num_components(), num_elements); // Write out the bytes stream.Write(byte_destination, nitems); } } if (stream.GetStreamPosition() != total_size) { O3D_ERROR(buffer.service_locator()) << "error in serializing buffer"; return; } } // |output| will be filled with the serialized data void SerializeCurve(const Curve &curve, MemoryBuffer *output) { const size_t num_keys = const_cast(curve).keys().size(); // Bezier entry size is biggest, so compute kKeyEntryMaxSize based on it const size_t kFloat2Size = 2 * sizeof(float); const size_t kKeyEntryMaxSize = sizeof(uint8) + 2 * sizeof(float) + 2 * kFloat2Size; const size_t key_data_max_size = num_keys * kKeyEntryMaxSize; const size_t max_total_size = kSerializationIDSize + kVersionSize + key_data_max_size; // Allocate a buffer which is large enough to hold the serialized data // It may be larger than the actual size required. It will be resized // to the exact size at the end output->Resize(max_total_size); MemoryWriteStream stream(*output, max_total_size); // write out serialization ID for curve stream.Write(Curve::kSerializationID, 4); // write out version stream.WriteLittleEndianInt32(1); for (size_t i = 0; i < num_keys; ++i) { const CurveKey &key = *curve.GetKey(i); // determine the KeyType based on the key's class if (key.IsA(StepCurveKey::GetApparentClass())) { stream.WriteByte(CurveKey::TYPE_STEP); stream.WriteLittleEndianFloat32(key.input()); stream.WriteLittleEndianFloat32(key.output()); } else if (key.IsA(LinearCurveKey::GetApparentClass())) { stream.WriteByte(CurveKey::TYPE_LINEAR); stream.WriteLittleEndianFloat32(key.input()); stream.WriteLittleEndianFloat32(key.output()); } else if (key.IsA(BezierCurveKey::GetApparentClass())) { const BezierCurveKey &bezier_key = static_cast(key); stream.WriteByte(CurveKey::TYPE_BEZIER); stream.WriteLittleEndianFloat32(bezier_key.input()); stream.WriteLittleEndianFloat32(bezier_key.output()); stream.WriteLittleEndianFloat32(bezier_key.in_tangent().getX()); stream.WriteLittleEndianFloat32(bezier_key.in_tangent().getY()); stream.WriteLittleEndianFloat32(bezier_key.out_tangent().getX()); stream.WriteLittleEndianFloat32(bezier_key.out_tangent().getY()); } else { O3D_ERROR(curve.service_locator()) << "error in serializing curve"; return; } } // Make note of total amount of data written and set the buffer to this // exact size size_t total_size = stream.GetStreamPosition(); output->Resize(total_size); } // |output| will be filled with the serialized data void SerializeSkin(const Skin &skin, MemoryBuffer *output) { const Skin::InfluencesArray &influences_array = skin.influences(); const size_t influences_array_size = influences_array.size(); // Count up total number of individual influences size_t total_influence_count = 0; for (size_t i = 0; i < influences_array_size; ++i) { total_influence_count += influences_array[i].size(); } const size_t kInfluenceSize = sizeof(uint32) + sizeof(float); const size_t total_size = kSerializationIDSize + kVersionSize + influences_array_size * sizeof(uint32) + total_influence_count * kInfluenceSize; // Allocate a buffer to hold the serialized data output->Resize(total_size); MemoryWriteStream stream(*output, total_size); // write out serialization ID for skin stream.Write(Skin::kSerializationID, 4); // write out version stream.WriteLittleEndianInt32(1); for (size_t i = 0; i < influences_array_size; ++i) { const Skin::Influences &influences = influences_array[i]; // Write the influence count for this Influences object size_t influence_count = influences.size(); stream.WriteLittleEndianInt32(static_cast(influence_count)); for (size_t j = 0; j < influence_count; ++j) { const Skin::Influence &influence = influences[j]; stream.WriteLittleEndianInt32(influence.matrix_index); stream.WriteLittleEndianFloat32(influence.weight); } } } } // namespace o3d