diff --git a/README.md b/README.md index 94010f1..ee9d0f4 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,11 @@ class selection to 8 classes as NWN:EE allows. Feat selection with handy fuzzy searching. -![stats](screenshots/creature-view-feats.png) +![feats](screenshots/creature-view-feats.png) + +### Creature View - Inventory + +![inventory](screenshots/creature-inventory-view-2024-11-04.png) ### Dialog View diff --git a/screenshots/creature-inventory-view-2024-11-04.png b/screenshots/creature-inventory-view-2024-11-04.png new file mode 100644 index 0000000..6405ff5 Binary files /dev/null and b/screenshots/creature-inventory-view-2024-11-04.png differ diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 32bb772..2e04e91 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -31,6 +31,8 @@ add_library(arclight-widgets STATIC TlkSelector/tlkselector.ui util/restypeicons.cpp + util/items.cpp + checkboxdelegate.h checkboxdelegate.cpp arealistview.h diff --git a/src/widgets/CreatureView/CMakeLists.txt b/src/widgets/CreatureView/CMakeLists.txt index dc81081..46e8d31 100644 --- a/src/widgets/CreatureView/CMakeLists.txt +++ b/src/widgets/CreatureView/CMakeLists.txt @@ -2,26 +2,32 @@ find_package(Qt6 REQUIRED COMPONENTS Widgets) find_package(Qt6 REQUIRED COMPONENTS OpenGL OpenGLWidgets) add_library(CreatureView STATIC + creatureappearanceview.cpp + creatureappearanceview.h + creatureappearanceview.ui + creatureequipview.cpp + creatureequipview.h + creatureequipview.ui creaturefeatselector.cpp creaturefeatselector.h creaturefeatselector.ui - creaturefeatselectormodel.h creaturefeatselectormodel.cpp creaturefeatselectormodel.h + creaturefeatselectormodel.h + creatureinventorypanel.cpp + creatureinventorypanel.h + creatureinventorypanel.ui + creatureinventoryview.cpp + creatureinventoryview.h + creatureinventoryview.ui + creaturestatsview.cpp + creaturestatsview.h + creaturestatsview.ui creatureview.cpp creatureview.h creatureview.ui - creaturestatsview.h - creaturestatsview.cpp - creaturestatsview.ui - creatureappearanceview.h - creatureappearanceview.cpp - creatureappearanceview.ui - creatureequipview.h - creatureequipview.cpp - creatureequipview.ui - inventoryslot.h inventoryslot.cpp + inventoryslot.h resources.qrc ) @@ -49,6 +55,6 @@ target_link_libraries(CreatureView PRIVATE Qt6::OpenGL Qt6::OpenGLWidgets nw - renderer + renderer VariableTableView ) diff --git a/src/widgets/CreatureView/CreatureInventoryView.ui b/src/widgets/CreatureView/CreatureInventoryView.ui new file mode 100644 index 0000000..99353cd --- /dev/null +++ b/src/widgets/CreatureView/CreatureInventoryView.ui @@ -0,0 +1,19 @@ + + + Form + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/src/widgets/CreatureView/creatureequipview.ui b/src/widgets/CreatureView/creatureequipview.ui index 1245dd7..1d04d6d 100644 --- a/src/widgets/CreatureView/creatureequipview.ui +++ b/src/widgets/CreatureView/creatureequipview.ui @@ -6,8 +6,8 @@ 0 0 - 733 - 370 + 705 + 316 @@ -21,26 +21,114 @@ - + + + + 0 + 0 + + Equipment - + + + + + + 0 + + + 0 + + + 5 + + + 0 + + + + + + 0 + 0 + + + + + 64 + 240 + + + + + 64 + 240 + + + + + + + + + + :/resources/images/inv_slot_right.png + + + false + + + Qt::AlignmentFlag::AlignCenter + + + + + + - + - + 0 0 - - Standard - - + + + 5 + + + 0 + + + 5 + + + 0 + - - + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + 0 @@ -48,13 +136,13 @@ 0 - 5 + 0 0 - + 0 @@ -64,23 +152,20 @@ 64 - 240 + 120 64 - 240 + 122 - - - - :/resources/images/inv_slot_right.png + :/resources/images/inv_slot_armor.png false @@ -94,105 +179,300 @@ - + 0 0 - + - 5 + 0 0 - 5 + 0 0 - - - - 0 - 0 - + + + + 32 + 64 + + + + + 32 + 64 + + + + + + + :/resources/images/inv_slot_arrow.png + + false + + + + + - 0 - 0 + 32 + 32 - 16777215 - 16777215 + 32 + 32 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 64 - 120 - - - - - 64 - 122 - - - - - - - :/resources/images/inv_slot_armor.png - - - false - - - Qt::AlignmentFlag::AlignCenter - - - - + + + + + :/resources/images/inv_slot_sling.png + + + false + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 32 + 64 + + + + + 32 + 64 + + + + + + + :/resources/images/inv_slot_bolts.png + + + false + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + + + + 0 + 0 + + + + + 5 + + + 0 + + + 5 + + + 0 + + + + + + 0 + 0 + + + + + 64 + 128 + + + + + 64 + 128 + + + + + + + :/resources/images/inv_slot_left.png + + + false + + + + + + + + 0 + 0 + + + + + 64 + 32 + + + + + 64 + 32 + + + + + + + :/resources/images/inv_slot_belt.png + + + false + + + + + + + + + + + 0 + 0 + + + + + 5 + + + 0 + + + 5 + + + 0 + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + + + :/resources/images/inv_slot_helm.png + + + false + + + + + + + + 64 + 32 + + + + + 64 + 32 + + + + + + + :/resources/images/inv_slot_gloves.png + + + false + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + - + 0 0 - + 0 @@ -206,32 +486,13 @@ 0 - - - - 32 - 64 - - - - - 32 - 64 - - - - - - - :/resources/images/inv_slot_arrow.png - - - false + + + + 64 + 64 + - - - - 32 @@ -248,73 +509,49 @@ - :/resources/images/inv_slot_sling.png + :/resources/images/inv_slot_ring.png false - - Qt::AlignmentFlag::AlignCenter - - + + + + 64 + 64 + + 32 - 64 + 32 32 - 64 + 32 - :/resources/images/inv_slot_bolts.png + :/resources/images/inv_slot_ring.png false - - Qt::AlignmentFlag::AlignCenter - - - - - - - - - 0 - 0 - - - - - 5 - - - 0 - - - 5 - - - 0 - - + 0 @@ -323,52 +560,21 @@ - 64 - 128 - - - - - 64 - 128 - - - - - - - :/resources/images/inv_slot_left.png - - - false - - - - - - - - 0 - 0 - - - - - 64 - 32 + 32 + 64 - 64 - 32 + 32 + 64 - :/resources/images/inv_slot_belt.png + :/resources/images/inv_slot_amulet.png false @@ -378,29 +584,136 @@ + + + + + + + + 0 + 0 + + + + + 5 + + + 0 + + + 0 + + + 0 + - + 0 0 - - - 5 - - - 0 - - - 5 - - - 0 - + + + 64 + 120 + + + + + 64 + 120 + + + + + + + false + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 32 + 32 + + + + + 64 + 64 + + + + + 64 + 64 + + + + + + + :/resources/images/inv_slot_boots.png + + + false + + + + + + + + + + + + + + 0 + 0 + + + + Creature Items + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + - + + + + 0 + 0 + + 64 @@ -417,205 +730,52 @@ - :/resources/images/inv_slot_helm.png - - - false + :/resources/images/inv_slot_cre_1.png - + + + + 0 + 0 + + 64 - 32 + 64 64 - 32 + 64 - :/resources/images/inv_slot_gloves.png - - - false + :/resources/images/inv_slot_cre_2.png - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 64 - 64 - - - - - 32 - 32 - - - - - 32 - 32 - - - - - - - :/resources/images/inv_slot_ring.png - - - false - - - - - - - - 64 - 64 - - - - - 32 - 32 - - - - - 32 - 32 - - - - - - - :/resources/images/inv_slot_ring.png - - - false - - - - - - - - - - - 0 - 0 - - - - - 32 - 64 - - - - - 32 - 64 - - - - - - - :/resources/images/inv_slot_amulet.png - - - false - - - - - - - + 0 0 - - - 5 - - - 0 - - - 0 - - - 0 - + - + 0 @@ -625,32 +785,29 @@ 64 - 120 + 64 64 - 120 + 64 - - false - - - Qt::AlignmentFlag::AlignCenter + + :/resources/images/inv_slot_cre_3.png - + - 32 - 32 + 0 + 0 @@ -669,174 +826,8 @@ - :/resources/images/inv_slot_boots.png - - - false - - - - - - - - - - - - - - 0 - 0 - - - - Creature - - - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - - 64 - 64 - - - - - 64 - 64 - - - - - - - :/resources/images/inv_slot_cre_1.png - - - - - - - - 0 - 0 - - - - - 64 - 64 - - - - - 64 - 64 - - - - - - - :/resources/images/inv_slot_cre_2.png - - - - - - - - - - - 0 - 0 - + :/resources/images/inv_slot_cre_skin.png - - - - - - 0 - 0 - - - - - 64 - 64 - - - - - 64 - 64 - - - - - - - :/resources/images/inv_slot_cre_3.png - - - - - - - - 0 - 0 - - - - - 64 - 64 - - - - - 64 - 64 - - - - - - - :/resources/images/inv_slot_cre_skin.png - - - - diff --git a/src/widgets/CreatureView/creatureinventorypanel.cpp b/src/widgets/CreatureView/creatureinventorypanel.cpp new file mode 100644 index 0000000..8adf711 --- /dev/null +++ b/src/widgets/CreatureView/creatureinventorypanel.cpp @@ -0,0 +1,20 @@ +#include "creatureinventorypanel.h" +#include "ui_creatureinventorypanel.h" + +CreatureInventoryPanel::CreatureInventoryPanel(QWidget* parent) + : QWidget(parent) + , ui(new Ui::CreatureInventoryPanel) +{ + ui->setupUi(this); +} + +CreatureInventoryPanel::~CreatureInventoryPanel() +{ + delete ui; +} + +void CreatureInventoryPanel::setCreature(nw::Creature* creature) +{ + ui->equips->setCreature(creature); + ui->inventory->setCreature(creature); +} diff --git a/src/widgets/CreatureView/creatureinventorypanel.h b/src/widgets/CreatureView/creatureinventorypanel.h new file mode 100644 index 0000000..06e90f5 --- /dev/null +++ b/src/widgets/CreatureView/creatureinventorypanel.h @@ -0,0 +1,27 @@ +#ifndef CREATUREINVENTORYPANEL_H +#define CREATUREINVENTORYPANEL_H + +#include + +namespace nw { +struct Creature; +} + +namespace Ui { +class CreatureInventoryPanel; +} + +class CreatureInventoryPanel : public QWidget { + Q_OBJECT + +public: + explicit CreatureInventoryPanel(QWidget* parent = nullptr); + ~CreatureInventoryPanel(); + + void setCreature(nw::Creature* creature); + +private: + Ui::CreatureInventoryPanel* ui; +}; + +#endif // CREATUREINVENTORYPANEL_H diff --git a/src/widgets/CreatureView/creatureinventorypanel.ui b/src/widgets/CreatureView/creatureinventorypanel.ui new file mode 100644 index 0000000..1a3dfc4 --- /dev/null +++ b/src/widgets/CreatureView/creatureinventorypanel.ui @@ -0,0 +1,97 @@ + + + CreatureInventoryPanel + + + + 0 + 0 + 918 + 722 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + CreatureEquipView + QWidget +
creatureequipview.h
+ 1 +
+ + CreatureInventoryView + QWidget +
creatureinventoryview.h
+ 1 +
+
+ + +
diff --git a/src/widgets/CreatureView/creatureinventoryview.cpp b/src/widgets/CreatureView/creatureinventoryview.cpp new file mode 100644 index 0000000..2ef397f --- /dev/null +++ b/src/widgets/CreatureView/creatureinventoryview.cpp @@ -0,0 +1,170 @@ +#include "creatureinventoryview.h" +#include "ui_creatureinventoryview.h" + +#include "../util/items.h" + +#include "ZFontIcon/ZFontIcon.h" +#include "ZFontIcon/ZFont_fa6.h" + +#include +#include + +// == InventoryItemDelegate =================================================== +// ============================================================================ + +InventoryItemDelegate::InventoryItemDelegate(QObject* parent) + : QStyledItemDelegate(parent) +{ +} + +void InventoryItemDelegate::initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const +{ + QStyledItemDelegate::initStyleOption(option, index); + option->displayAlignment = Qt::AlignCenter; +} + +void InventoryItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + if (index.column() == 0) { + QPixmap pixmap = index.data(Qt::DecorationRole).value(); + if (!pixmap.isNull()) { + if (pixmap.height() > 128) { + pixmap = pixmap.scaled(QSize(64, 128), Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + int x = option.rect.x() + (option.rect.width() - pixmap.width()) / 2; + int y = option.rect.y() + (option.rect.height() - pixmap.height()) / 2; + painter->drawPixmap(x, y, pixmap); + return; + } + } + + QStyledItemDelegate::paint(painter, option, index); +} + +QSize InventoryItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + if (index.column() == 0) { + QPixmap pixmap = index.data(Qt::DecorationRole).value(); + int height = qMin(pixmap.height(), 128); + + QFontMetrics fontMetrics(option.font); + int text = fontMetrics.height(); + + int row = qMax(height, text) + 8; + return QSize(option.rect.width(), row); + } + return QStyledItemDelegate::sizeHint(option, index); +} + +// == InventoryModel ========================================================== +// ============================================================================ + +InventoryModel::InventoryModel(nw::Creature* creature, QObject* parent) + : QAbstractTableModel(parent) + , creature_{creature} +{ +} + +QVariant InventoryModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: + return "Icon"; + case 1: + return "Name"; + case 2: + return "Stack Size"; + default: + return QVariant(); + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + +int InventoryModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return creature_ ? static_cast(creature_->inventory.items.size()) : 0; +} + +int InventoryModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return 3; +} + +QVariant InventoryModel::data(const QModelIndex& index, int role) const +{ + if (!creature_) { return QVariant(); } + if (!index.isValid() || index.row() >= static_cast(creature_->inventory.items.size())) { + return QVariant(); + } + + const auto item = creature_->inventory.items[index.row()].item.as(); + + switch (index.column()) { + case 0: + if (role == Qt::DecorationRole) { + return item_to_image(item, creature_->gender == 1); + } + break; + case 1: + if (role == Qt::DisplayRole) { + return QString::fromStdString(nw::kernel::strings().get(item->common.name)); + } + break; + case 2: + if (role == Qt::DisplayRole) { + return item->stacksize; + } + break; + } + return QVariant(); +} + +Qt::ItemFlags InventoryModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = QAbstractTableModel::flags(index); + return flags; +} + +void InventoryModel::addItem(nw::Item* item) +{ + // beginInsertRows(QModelIndex(), items.size(), items.size()); + // items.append({image, name, stackSize, stackable}); + // endInsertRows(); +} + +// == CreatureInventoryView =================================================== +// ============================================================================ + +CreatureInventoryView::CreatureInventoryView(QWidget* parent) + : QWidget(parent) + , ui(new Ui::CreatureInventoryView) +{ + ui->setupUi(this); + ui->add->setIcon(ZFontIcon::icon(Fa6::FAMILY, Fa6::fa_plus, Qt::green)); + ui->remove->setIcon(ZFontIcon::icon(Fa6::FAMILY, Fa6::fa_minus, Qt::red)); +} + +CreatureInventoryView::~CreatureInventoryView() +{ + delete ui; +} + +void CreatureInventoryView::setCreature(nw::Creature* creature) +{ + creature_ = creature; + model_ = new InventoryModel(creature_, this); + ui->inventoryView->setModel(model_); + ui->inventoryView->setItemDelegate(new InventoryItemDelegate(this)); + ui->inventoryView->setColumnWidth(0, 64); + ui->inventoryView->setColumnWidth(2, 80); + + ui->inventoryView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + ui->inventoryView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + ui->inventoryView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); + ui->inventoryView->resizeRowsToContents(); + ui->inventoryView->setSelectionBehavior(QAbstractItemView::SelectRows); +} diff --git a/src/widgets/CreatureView/creatureinventoryview.h b/src/widgets/CreatureView/creatureinventoryview.h new file mode 100644 index 0000000..476757e --- /dev/null +++ b/src/widgets/CreatureView/creatureinventoryview.h @@ -0,0 +1,70 @@ +#ifndef CREATUREINVENTORYVIEW_H +#define CREATUREINVENTORYVIEW_H + +#include +#include +#include +#include +#include +#include + +namespace nw { +struct Creature; +struct Item; +} + +// == InventoryItemDelegate =================================================== +// ============================================================================ + +constexpr int StackableRole = Qt::UserRole + 1; + +class InventoryItemDelegate : public QStyledItemDelegate { +public: + InventoryItemDelegate(QObject* parent = nullptr); + + void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override; + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; +}; + +// == InventoryModel ========================================================== +// ============================================================================ + +class InventoryModel : public QAbstractTableModel { + Q_OBJECT + +public: + InventoryModel(nw::Creature* creature, QObject* parent = nullptr); + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + + void addItem(nw::Item* item); + +private: + nw::Creature* creature_; +}; + +namespace Ui { +class CreatureInventoryView; +} + +class CreatureInventoryView : public QWidget { + Q_OBJECT + +public: + explicit CreatureInventoryView(QWidget* parent = nullptr); + ~CreatureInventoryView(); + + void setCreature(nw::Creature* creature); + +private: + Ui::CreatureInventoryView* ui; + nw::Creature* creature_ = nullptr; + InventoryModel* model_ = nullptr; +}; + +#endif // CREATUREINVENTORYVIEW_H diff --git a/src/widgets/CreatureView/creatureinventoryview.ui b/src/widgets/CreatureView/creatureinventoryview.ui new file mode 100644 index 0000000..7920859 --- /dev/null +++ b/src/widgets/CreatureView/creatureinventoryview.ui @@ -0,0 +1,85 @@ + + + CreatureInventoryView + + + + 0 + 0 + 1038 + 626 + + + + Form + + + + + + Inventory + + + + + + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Add Item + + + + + + + + + + Remove Item + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + diff --git a/src/widgets/CreatureView/creatureview.cpp b/src/widgets/CreatureView/creatureview.cpp index 2aaddd1..5b5dc06 100644 --- a/src/widgets/CreatureView/creatureview.cpp +++ b/src/widgets/CreatureView/creatureview.cpp @@ -1,4 +1,5 @@ #include "creatureview.h" +#include "creatureinventorypanel.h" #include "ui_creatureview.h" #include "VariableTableView/vartabledialog.h" @@ -36,9 +37,10 @@ CreatureView::CreatureView(nw::Creature* creature, QWidget* parent) auto appearance = new CreatureAppearanceView(creature, this); ui->tabWidget->addTab(appearance, "Appearance"); connect(appearance, &CreatureAppearanceView::dataChanged, this, &CreatureView::onDataChanged); - auto equips = new CreatureEquipView(this); - equips->setCreature(creature); - ui->tabWidget->addTab(equips, "Inventory"); + + auto inv = new CreatureInventoryPanel(this); + inv->setCreature(creature); + ui->tabWidget->addTab(inv, "Inventory"); ui->portraitEdit->setIcon(ZFontIcon::icon(Fa6::FAMILY, Fa6::fa_ellipsis)); diff --git a/src/widgets/CreatureView/inventoryslot.cpp b/src/widgets/CreatureView/inventoryslot.cpp index 9f338d8..2cbdd67 100644 --- a/src/widgets/CreatureView/inventoryslot.cpp +++ b/src/widgets/CreatureView/inventoryslot.cpp @@ -1,89 +1,12 @@ #include "inventoryslot.h" -#include "nw/formats/Image.hpp" +#include "../util/items.h" + #include "nw/kernel/Strings.hpp" -#include "nw/kernel/TwoDACache.hpp" #include "nw/objects/Item.hpp" #include -QImage item_to_image(const nw::Item* item, bool female) -{ - auto* bi2da = nw::kernel::twodas().get("baseitems"); - auto int_type = bi2da->get(*item->baseitem, "ModelType"); - nw::ItemModelType type; - - if (int_type) { - type = static_cast(*int_type); - } else { - return QImage(); - } - - if (type == nw::ItemModelType::simple || type == nw::ItemModelType::layered) { - auto icon = item->get_icon_by_part(); - if (!icon.valid()) { return QImage{}; } - QImage image(icon.release(), icon.width(), icon.height(), icon.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, - [](void* bytes) { if (bytes) { free(bytes); } }); - return image.mirrored(); - } else if (type == nw::ItemModelType::composite) { - auto img1 = item->get_icon_by_part(nw::ItemModelParts::model1); - if (!img1.valid()) { return QImage{}; } - QImage bottom(img1.release(), img1.width(), img1.height(), img1.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, - [](void* bytes) { if (bytes) { free(bytes); } }); - if (!img1.is_bio_dds()) { bottom.mirror(); } - - auto img2 = item->get_icon_by_part(nw::ItemModelParts::model2); - if (!img2.valid()) { return QImage{}; } - QImage middle(img2.release(), img2.width(), img2.height(), img2.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, - [](void* bytes) { if (bytes) { free(bytes); } }); - if (!img2.is_bio_dds()) { middle.mirror(); } - - auto img3 = item->get_icon_by_part(nw::ItemModelParts::model3); - if (!img3.valid()) { return QImage{}; } - QImage top(img3.release(), img3.width(), img3.height(), img3.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, - [](void* bytes) { if (bytes) { free(bytes); } }); - if (!img3.is_bio_dds()) { top.mirror(); } - - QPainter painter(&bottom); - painter.drawImage(0, 0, middle); - painter.drawImage(0, 0, top); - painter.end(); - return bottom.mirrored(); - - } else if (type == nw::ItemModelType::armor) { - QImage base; - - for (auto part : { - nw::ItemModelParts::armor_pelvis, - nw::ItemModelParts::armor_belt, - nw::ItemModelParts::armor_torso, - nw::ItemModelParts::armor_lshoul, - nw::ItemModelParts::armor_rshoul, - nw::ItemModelParts::armor_robe}) { - - if (item->model_parts[part] == 0) { continue; } - auto texture = item->get_icon_by_part(part, female); - - if (texture.valid()) { - QImage image(texture.release(), texture.width(), texture.height(), texture.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, - [](void* bytes) { if (bytes) { free(bytes); } }); - if (base.isNull()) { - base = image; - } else { - QPainter painter(&base); - painter.drawImage(0, 0, image); - } - } - } - - if (!base.isNull()) { - return base.mirrored(); - } - } - - return QImage(); -} - InventorySlot::InventorySlot(QWidget* parent) : QLabel(parent) { diff --git a/src/widgets/util/items.cpp b/src/widgets/util/items.cpp new file mode 100644 index 0000000..7128c76 --- /dev/null +++ b/src/widgets/util/items.cpp @@ -0,0 +1,86 @@ +#include "items.h" + +#include "nw/formats/Image.hpp" +#include "nw/kernel/Strings.hpp" +#include "nw/kernel/TwoDACache.hpp" +#include "nw/objects/Item.hpp" + +#include +#include + +QImage item_to_image(const nw::Item* item, bool female) +{ + auto* bi2da = nw::kernel::twodas().get("baseitems"); + auto int_type = bi2da->get(*item->baseitem, "ModelType"); + nw::ItemModelType type; + + if (int_type) { + type = static_cast(*int_type); + } else { + return QImage(); + } + + if (type == nw::ItemModelType::simple || type == nw::ItemModelType::layered) { + auto icon = item->get_icon_by_part(); + if (!icon.valid()) { return QImage{}; } + QImage image(icon.release(), icon.width(), icon.height(), icon.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, + [](void* bytes) { if (bytes) { free(bytes); } }); + return image.mirrored(); + } else if (type == nw::ItemModelType::composite) { + auto img1 = item->get_icon_by_part(nw::ItemModelParts::model1); + if (!img1.valid()) { return QImage{}; } + QImage bottom(img1.release(), img1.width(), img1.height(), img1.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, + [](void* bytes) { if (bytes) { free(bytes); } }); + if (!img1.is_bio_dds()) { bottom.mirror(); } + + auto img2 = item->get_icon_by_part(nw::ItemModelParts::model2); + if (!img2.valid()) { return QImage{}; } + QImage middle(img2.release(), img2.width(), img2.height(), img2.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, + [](void* bytes) { if (bytes) { free(bytes); } }); + if (!img2.is_bio_dds()) { middle.mirror(); } + + auto img3 = item->get_icon_by_part(nw::ItemModelParts::model3); + if (!img3.valid()) { return QImage{}; } + QImage top(img3.release(), img3.width(), img3.height(), img3.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, + [](void* bytes) { if (bytes) { free(bytes); } }); + if (!img3.is_bio_dds()) { top.mirror(); } + + QPainter painter(&bottom); + painter.drawImage(0, 0, middle); + painter.drawImage(0, 0, top); + painter.end(); + return bottom.mirrored(); + + } else if (type == nw::ItemModelType::armor) { + QImage base; + + for (auto part : { + nw::ItemModelParts::armor_pelvis, + nw::ItemModelParts::armor_belt, + nw::ItemModelParts::armor_torso, + nw::ItemModelParts::armor_lshoul, + nw::ItemModelParts::armor_rshoul, + nw::ItemModelParts::armor_robe}) { + + if (item->model_parts[part] == 0) { continue; } + auto texture = item->get_icon_by_part(part, female); + + if (texture.valid()) { + QImage image(texture.release(), texture.width(), texture.height(), texture.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888, + [](void* bytes) { if (bytes) { free(bytes); } }); + if (base.isNull()) { + base = image; + } else { + QPainter painter(&base); + painter.drawImage(0, 0, image); + } + } + } + + if (!base.isNull()) { + return base.mirrored(); + } + } + + return QImage(); +} diff --git a/src/widgets/util/items.h b/src/widgets/util/items.h new file mode 100644 index 0000000..e0bd594 --- /dev/null +++ b/src/widgets/util/items.h @@ -0,0 +1,9 @@ +#pragma once + +namespace nw { +struct Item; +} + +class QImage; + +QImage item_to_image(const nw::Item* item, bool female);