Containers::Array<unsigned char> TgaImageConverter::doExportToData(const ImageReference2D& image) const { #ifndef MAGNUM_TARGET_GLES if(image.format() != ColorFormat::BGR && image.format() != ColorFormat::BGRA && image.format() != ColorFormat::Red) #else if(image.format() != ColorFormat::RGB && image.format() != ColorFormat::RGBA && image.format() != ColorFormat::Red) #endif { Error() << "Trade::TgaImageConverter::convertToData(): unsupported image format" << image.format(); return nullptr; } if(image.type() != ColorType::UnsignedByte) { Error() << "Trade::TgaImageConverter::convertToData(): unsupported image type" << image.type(); return nullptr; } /* Initialize data buffer */ const auto pixelSize = UnsignedByte(image.pixelSize()); auto data = Containers::Array<unsigned char>::zeroInitialized(sizeof(TgaHeader) + pixelSize*image.size().product()); /* Fill header */ auto header = reinterpret_cast<TgaHeader*>(data.begin()); header->imageType = image.format() == ColorFormat::Red ? 3 : 2; header->bpp = pixelSize*8; header->width = UnsignedShort(Utility::Endianness::littleEndian(image.size().x())); header->height = UnsignedShort(Utility::Endianness::littleEndian(image.size().y())); /* Fill data */ std::copy(image.data(), image.data()+pixelSize*image.size().product(), data.begin()+sizeof(TgaHeader)); #ifdef MAGNUM_TARGET_GLES if(image.format() == ColorFormat::RGB) { auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.begin()+sizeof(TgaHeader)); std::transform(pixels, pixels + image.size().product(), pixels, [](Math::Vector3<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r'>(pixel); }); } else if(image.format() == ColorFormat::RGBA) { auto pixels = reinterpret_cast<Math::Vector4<UnsignedByte>*>(data.begin()+sizeof(TgaHeader)); std::transform(pixels, pixels + image.size().product(), pixels, [](Math::Vector4<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r', 'a'>(pixel); }); } #endif return std::move(data); }
Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& image) { #ifndef MAGNUM_TARGET_GLES if(image.storage().swapBytes()) { Error() << "Trade::TgaImageConverter::exportToData(): pixel byte swap is not supported"; return nullptr; } #endif if(image.format() != PixelFormat::RGB && image.format() != PixelFormat::RGBA #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) && image.format() != PixelFormat::Red #endif #ifdef MAGNUM_TARGET_GLES2 && image.format() != PixelFormat::Luminance #endif ) { Error() << "Trade::TgaImageConverter::exportToData(): unsupported color format" << image.format(); return nullptr; } if(image.type() != PixelType::UnsignedByte) { Error() << "Trade::TgaImageConverter::exportToData(): unsupported color type" << image.type(); return nullptr; } /* Initialize data buffer */ const auto pixelSize = UnsignedByte(image.pixelSize()); Containers::Array<char> data{Containers::ValueInit, sizeof(TgaHeader) + pixelSize*image.size().product()}; /* Fill header */ auto header = reinterpret_cast<TgaHeader*>(data.begin()); switch(image.format()) { case PixelFormat::RGB: case PixelFormat::RGBA: header->imageType = 2; break; #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) case PixelFormat::Red: #endif #ifdef MAGNUM_TARGET_GLES2 case PixelFormat::Luminance: #endif header->imageType = 3; break; default: CORRADE_ASSERT_UNREACHABLE(); } header->bpp = pixelSize*8; header->width = UnsignedShort(Utility::Endianness::littleEndian(image.size().x())); header->height = UnsignedShort(Utility::Endianness::littleEndian(image.size().y())); /* Image data pointer including skip */ const char* imageData = image.data() + std::get<0>(image.dataProperties()); /* Fill data or copy them row by row if we need to drop the padding */ const std::size_t rowSize = image.size().x()*pixelSize; const std::size_t rowStride = std::get<1>(image.dataProperties()).x(); if(rowStride != rowSize) { for(std::int_fast32_t y = 0; y != image.size().y(); ++y) std::copy_n(imageData + y*rowStride, rowSize, data.begin() + sizeof(TgaHeader) + y*rowSize); } else std::copy_n(imageData, pixelSize*image.size().product(), data.begin() + sizeof(TgaHeader)); if(image.format() == PixelFormat::RGB) { auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.begin()+sizeof(TgaHeader)); std::transform(pixels, pixels + image.size().product(), pixels, [](Math::Vector3<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r'>(pixel); }); } else if(image.format() == PixelFormat::RGBA) { auto pixels = reinterpret_cast<Math::Vector4<UnsignedByte>*>(data.begin()+sizeof(TgaHeader)); std::transform(pixels, pixels + image.size().product(), pixels, [](Math::Vector4<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r', 'a'>(pixel); }); } return data; }
/* Computing absolute transformations for given list of objects The goal is to compute absolute transformation only once for each object involved. Objects contained in the subtree specified by `object` list are divided into two groups: - "joints", which are either part of `object` list or they have more than one child in the subtree - "non-joints", i.e. paths between joints Then for all joints their transformation (relative to parent joint) is computed and recursively concatenated together. Resulting transformations for joints which were originally in `object` list is then returned. */ template<class Transformation> std::vector<typename Transformation::DataType> Object<Transformation>::transformations(std::vector<std::reference_wrapper<Object<Transformation>>> objects, const typename Transformation::DataType& initialTransformation) const { CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", {}); /* Remember object count for later */ std::size_t objectCount = objects.size(); /* Mark all original objects as joints and create initial list of joints from them */ for(std::size_t i = 0; i != objects.size(); ++i) { /* Multiple occurences of one object in the array, don't overwrite it with different counter */ if(objects[i].get().counter != 0xFFFFu) continue; objects[i].get().counter = UnsignedShort(i); objects[i].get().flags |= Flag::Joint; } std::vector<std::reference_wrapper<Object<Transformation>>> jointObjects(objects); /* Scene object */ const Scene<Transformation>* scene = this->scene(); /* Nearest common ancestor not yet implemented - assert this is done on scene */ CORRADE_ASSERT(scene == this, "SceneGraph::Object::transformationMatrices(): currently implemented only for Scene", {}); /* Mark all objects up the hierarchy as visited */ auto it = objects.begin(); while(!objects.empty()) { /* Already visited, remove and continue to next (duplicate occurence) */ if(it->get().flags & Flag::Visited) { it = objects.erase(it); continue; } /* Mark the object as visited */ it->get().flags |= Flag::Visited; Object<Transformation>* parent = it->get().parent(); /* If this is root object, remove from list */ if(!parent) { CORRADE_ASSERT(&it->get() == scene, "SceneGraph::Object::transformations(): the objects are not part of the same tree", {}); it = objects.erase(it); /* Parent is an joint or already visited - remove current from list */ } else if(parent->flags & (Flag::Visited|Flag::Joint)) { it = objects.erase(it); /* If not already marked as joint, mark it as such and add it to list of joint objects */ if(!(parent->flags & Flag::Joint)) { CORRADE_ASSERT(jointObjects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", {}); CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu); parent->counter = UnsignedShort(jointObjects.size()); parent->flags |= Flag::Joint; jointObjects.push_back(*parent); } /* Else go up the hierarchy */ } else *it = *parent; /* Cycle if reached end */ if(it == objects.end()) it = objects.begin(); } /* Array of absolute transformations in joints */ std::vector<typename Transformation::DataType> jointTransformations(jointObjects.size()); /* Compute transformations for all joints */ for(std::size_t i = 0; i != jointTransformations.size(); ++i) computeJointTransformation(jointObjects, jointTransformations, i, initialTransformation); /* Copy transformation for second or next occurences from first occurence of duplicate object */ for(std::size_t i = 0; i != objectCount; ++i) { if(jointObjects[i].get().counter != i) jointTransformations[i] = jointTransformations[jointObjects[i].get().counter]; } /* All visited marks are now cleaned, clean joint marks and counters */ for(auto i: jointObjects) { /* All not-already cleaned objects (...duplicate occurences) should have joint mark */ CORRADE_INTERNAL_ASSERT(i.get().counter == 0xFFFFu || i.get().flags & Flag::Joint); i.get().flags &= ~Flag::Joint; i.get().counter = 0xFFFFu; } /* Shrink the array to contain only transformations of requested objects and return */ jointTransformations.resize(objectCount); return jointTransformations; }