Russian Qt Forum
Апрель 30, 2024, 18:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Варианты вариантов  (Прочитано 7020 раз)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« : Ноябрь 30, 2016, 18:06 »

Продолжаем играть в Igors:)

Пишу сейчас библиотечку, замену imageformat'ам.
Итак, что мы имеем. Есть 3 типа "картинок" - текстура (здесь и далее Image), кубическая текстура (здесь и далее CubeTexture), объемная текстура (здесь и далее VolumeTexture). Бывают массивы каждого типа (на самом деле, массива VolumeTexture я не встречал, но для простоты пусть будет). Бывают mipmaps - то есть массив однотипных текстур разного размера (каждая следующая в 2 раза меньше предыдущей).
Например:
png, jpeg - это просто Image.
gif - это массив Image (с доп атрибутами, например задержка между кадрами или кол-во циклов, пока опустим)
ico, icns - это мимпапы Image'ей
dds - в зависимости от флагов либо Image (один или массив), либо CubeTexture (одна или массив), либо VolumeTexture. Ну и для каждого элемента массива могут быть мипмапы. Итого, двумерный массив (index массива, level мипмапы) элементов одного из 3х типов.
Это вводная часть.

Вкратце:
У нас есть двумерный массив однотипных объектов.

Проблема: как его представить.
Вариант 1
Код:
using Resource = union {Image, CubeTexture, VolumeTexture } // обычный Variant из 3х типов
using ImageDocument: QVector<QVector<Resource>>;

// reading:
auto doc = readFromFile();
for (int i = 0; i < doc.imageCount(); ++i) {
    auto res = doc.resource(i, /*level*/ 0);
    switch (res.type) {
    ....
    }
}
// writing:
auto imageCount = 10;
Document doc(imageCount, Resource::Type::Image);
for (int i = 0; i < imageCount; ++i) {
    doc.setResource(i, 0, Resource(QImage(...))); // тту выдаем ошибку если пытаемся засунунть ресурс не того типа.
}
Этот вариант плох тем, что юзер может попробовать класть ресурсы разных типов. А может и разрешить? Вдруг появятся такие форматы?)

Вариант 2.
Выкидываем ресурс, засовываем внутрь документа:
Код:
using ImageDocument: QVector<QVector<{Image, CubeTexture, VolumeTexture}>>;

// reading:
auto doc = readFromFile();
if (doc.type() == Type::CubeTexture) {
    for (int i = 0; i < doc.imageCount(); ++i) {
        auto res = doc.resource(i, /*level*/ 0);
            auto texture = doc.cubeTexture(i, 0);
        }
    }
}

// запись то же самое, doc.setCubeTexture(i, 0);
Этот вариант те же минусы что и первый, но не имеет "лишнего" класса, зато в документе больше методов (6 вместо 2)

Вариант 3
Код:
template<class T>
using Mipmaps = QVector<T>; // тут, на самом деле, целый класс-обертка со своими методами (int mipmapCount(), T mimpap(int index), QSize size(int index))
using ImageMipmaps = Mimpaps<Image>;
using CubeTextureMipmap = Mimpaps<CubeTexture>;
using VolumeTextureMipmap = Mimpaps<VolumeTexture>;
using ImageDocument = union { QImage, QVector<QImage>, ImageMipmaps, QVector<ImageMipmaps>, CubeTexture, QVector<CubeTexture>, ... } // Variant для 3*2*2 = 12 типов

// reading
auto doc = readFromFile();
if (doc.type() & Type::VolumeTexture) {
    if (doc.type() & Type::Mipmaps) {
        auto texture = doc.toVolumeTextureMipmaps().mipmap(0);
    } else {
        auto texture = doc.toVolumeTexture();
    }
}
Тут, вроде бы, накосячить сложно. Однако вот этот вариант на 12 типов меня смущает. Да и юзать это становится менее удобно, хотя всяких неявных конвертаций (массив -> его первый элемент, мимпапа -> её  первый элемент) можно добавить для удобства.

Сорян за простыни кода, надеюсь кто-нибудь осилит:)
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #1 : Ноябрь 30, 2016, 21:01 »

По мне, так удобней, что бы документ хранил от одной до N картинок, а у картинки может быть от 1 до K фреймов (например).
Код
C++ (Qt)
QImage i1 = ...;
QImage i2 = ...;
 
Image img;
img.addFrame( i1 );
img.addFrame( i2 );
 
ImageDocument doc;
doc.addImage( img );
 
// ---------------------
 
ImageDocument doc = readFromFile();
for( auto img : doc )
{
   qDebug() << img.frames();
   QImage i = img[ 0 ];
}
 
 
 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #2 : Ноябрь 30, 2016, 22:32 »

Идея в целом понятна, но она не отвечает на вопрос, на какой уровень всунуть вариант.
Типа такого?
Код:
QImage i1 = ...;
CubeTexture i2 = ...;
 
Image img;
img.addFrame( i1 );
img.addFrame( i2 );
...
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #3 : Ноябрь 30, 2016, 22:58 »

А можно чуть подробней, что такое кубическая и объемная текстура.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #4 : Ноябрь 30, 2016, 23:11 »

Конечно. Объемная текстура - это как QImage только с 3мя измерениями (width, heigth, depth) вместо 2х (width, height). В файле обычно хранится в виде массива (опять!) двумерных текстур одного размера.
Код:
class VolumeTexture
{
public:
    VolumeTexture();
    VolumeTexture(int width, int heigth, int depth = 1);

    QImage slice(int index); // returns QImage(width, height)
    void setSlice(int index, const QImage &image);
};

Кубическая текстура - это тоже "трехмерная" текстура, но с пустотой внутри, у неё есть только внешние грани. Представляется в виде 6 плоских изображений.
Код:
class CubeTexture
{
public:
    CubeTexture();
    CubeTexture(int size);

    enum Side {
        PositiveX = 0x1,
        NegativeX = 0x2,
        PositiveY = 0x3,
        NegativeY = 0x4,
        PositiveZ = 0x5,
        NegativeZ = 0x6,
    };

    QImage side(Side side); // returns QImage(size, size)
    void setSide(Side side, const QImage &image);
};

Для каждой из них в файле может быть набор мипмап, то есть текстур меньшего размера, чтобы не скейлить в рантайме.

Вот пример структуры самого сложного файла (отсюда)
Цитировать
For Each Mipmap (Smallest to Largest)
    For Each Frame (First to Last)
        For Each Face (First to Last)
            For Each Z Slice (Min to Max; Varies with Mipmap)
                VTF High Resolution Image Data
На практике Face и Slice взаимоисключающие (если FacesCount > 1 то SlicesCount == 1 и наоборот)

То есть, обобщая (уровни Mipmaps и Frames могут быть наоборот вложены)
Код:
For Each Mipmap (Smallest to Largest)
    For Each Frame (First to Last)
        QImage OR CubeTexture OR VolumeTexture
« Последнее редактирование: Ноябрь 30, 2016, 23:40 от Авварон » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Декабрь 01, 2016, 08:44 »

Рисуем общую структуру которая может иметь все-все-все, напр
Код
C++ (Qt)
struct CImageDoc {
 int GetNumFrames( void ) const;    // { return impl->GetNumFrames(); }
 int GetNumMips( void ) const;
 CImageDoc * GetParent( void ); // может и это
 ...
 ...
// data
 CImpl * impl;
};
Когда приходит конкретный формат - не пытаемся его как-то уложить в варианты, пусть он будет такой класс как есть, но добавляем "обеспечение" для всех методов CImageDoc

[OFF]
Кубическая текстура - это тоже "трехмерная" текстура, но с пустотой внутри, у неё есть только внешние грани. Представляется в виде 6 плоских изображений.
Ну вряд ли такую текстуру можно назвать "трехмерной", это один из вариантов карты отражения или окружения [/OFF]
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #6 : Декабрь 01, 2016, 12:10 »

Рисуем общую структуру которая может иметь все-все-все, напр
Код
C++ (Qt)
struct CImageDoc {
 int GetNumFrames( void ) const;    // { return impl->GetNumFrames(); }
 int GetNumMips( void ) const;
 CImageDoc * GetParent( void ); // может и это
 ...
 ...
// data
 CImpl * impl;
};
Когда приходит конкретный формат - не пытаемся его как-то уложить в варианты, пусть он будет такой класс как есть, но добавляем "обеспечение" для всех методов CImageDoc
А вот это не очень понял. Куда добавляем? Через наследование от общей базы, (CImageDoc) что ли?

[OFF]
Кубическая текстура - это тоже "трехмерная" текстура, но с пустотой внутри, у неё есть только внешние грани. Представляется в виде 6 плоских изображений.
Ну вряд ли такую текстуру можно назвать "трехмерной", это один из вариантов карты отражения или окружения [/OFF]
Потому я и взял слово трехмерная в кавычки:)
Кстати хорошо, что вы заглянули, вы мне и ответите на вопрос - а бывают ли "паралелепипедные" кубические текстуры (с разной длиной граней?)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Декабрь 01, 2016, 15:35 »

А вот это не очень понял. Куда добавляем? Через наследование от общей базы, (CImageDoc) что ли?
Нет, через связку CImpl. Создаете "нулевой" базовый CImpl который на все возвращает нули. Для каждого конкретного формата создаете наследника CImpl и делаете указатель на класс формата его членом, ну и через виртуалы CImpl делегируете ф-ционал формата в CImageDoc. 

а бывают ли "паралелепипедные" кубические текстуры (с разной длиной граней?)
Длину граней легко задать матрицей текстуры, а бывают ли кубики с 6 имеджами разного размера - нет, такого не встречал. В последнее время обычно все 6 сторон хранятся в 1 картинке (vert/horz cross). Ну и вообще "кубики" бывают разные (может быть просто 1 имедж без затей).

Что действительно хотелось бы иметь "ис каропки" - поддержку .exr и .hdr
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #8 : Декабрь 01, 2016, 16:32 »

Нет, через связку CImpl. Создаете "нулевой" базовый CImpl который на все возвращает нули. Для каждого конкретного формата создаете наследника CImpl и делаете указатель на класс формата его членом, ну и через виртуалы CImpl делегируете ф-ционал формата в CImageDoc. 

А, ну мы получаем всё те же 12 CImpl - их не очень удобно использовать при создании файла.

Длину граней легко задать матрицей текстуры, а бывают ли кубики с 6 имеджами разного размера - нет, такого не встречал. В последнее время обычно все 6 сторон хранятся в 1 картинке (vert/horz cross). Ну и вообще "кубики" бывают разные (может быть просто 1 имедж без затей).

Вот поэтому я и хожу отдельный класс CubeTexture который бы позволял создавать его из/конвертиторовать его в проекции (вертикальный крест, горизонтальный и тп). Это уже написано, кстати.

Что действительно хотелось бы иметь "ис каропки" - поддержку .exr и .hdr

Погуглил, это же просто текстуры? Это можно сделать и на текущих имадж форматах. Если дадите примеров картиночек (вроде там вообще 1 вариант?), могу написать и законтрибутить (если с лицензией всё ок).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Декабрь 01, 2016, 17:02 »

А, ну мы получаем всё те же 12 CImpl - их не очень удобно использовать при создании файла.
Пусть 12, но работаем с однообразным CImageDoc к которому привели слабо-связные классы, за счет этого многое схлопывается

Погуглил, это же просто текстуры? Это можно сделать и на текущих имадж форматах.
Та куда там, Qt не умеет их ни хранить, ни даже отображать (здесь это разные вещи). Это форматы float на канал, применимость - ну уж точно больше чем у "VolumeTexture"
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #10 : Декабрь 01, 2016, 18:55 »

Та куда там, Qt не умеет их ни хранить, ни даже отображать (здесь это разные вещи). Это форматы float на канал, применимость - ну уж точно больше чем у "VolumeTexture"

Хотя да, это потребует перепиливания QImage. Сейчас это можно сделать только с потерей точности.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Декабрь 02, 2016, 07:51 »

Хотя да, это потребует перепиливания QImage. Сейчас это можно сделать только с потерей точности.
Не думаю что "тролли" будут сильно возражать, скорее наоборот - этого явно не хватает, а юзается давно, хотя бы поиграться с exposure/logarithm впечатляет. Возможен и упрощенный вариант - имедж грузится как обычный QImage::ARGB_32 с потерей точности, НО по ходу дела создается буфер хранящий half или ergb, на практике вполне достаточно.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #12 : Декабрь 02, 2016, 11:28 »

Не думаю что "тролли" будут сильно возражать, скорее наоборот - этого явно не хватает, а юзается давно, хотя бы поиграться с exposure/logarithm впечатляет. Возможен и упрощенный вариант - имедж грузится как обычный QImage::ARGB_32 с потерей точности, НО по ходу дела создается буфер хранящий half или ergb, на практике вполне достаточно.

Можно посмотреть, если это не сломает бинарную совместимость, то можно добавить не дожидаясь Qt6.
В целом, не вижу проблем - добавить геттеров для QRgbF(float, float, float) да добавить энум.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.106 секунд. Запросов: 22.