示例#1
0
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);
}
示例#2
0
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;
}
示例#3
0
/*
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;
}