diff --git a/languages/dust3d_zh_CN.ts b/languages/dust3d_zh_CN.ts
index 3d4309c9..a7e9e5aa 100644
--- a/languages/dust3d_zh_CN.ts
+++ b/languages/dust3d_zh_CN.ts
@@ -791,6 +791,10 @@ Tips:
透明度
+
+
+ 平铺缩放
+
PoseEditWidget
diff --git a/resources/material-demo-model.ds3 b/resources/material-demo-model.ds3
index be193198..23a04e6d 100644
Binary files a/resources/material-demo-model.ds3 and b/resources/material-demo-model.ds3 differ
diff --git a/src/document.cpp b/src/document.cpp
index a2328ec2..8fee7d76 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -1192,6 +1192,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId
maps.push_back(textureMap);
}
std::map layerAttributes;
+ if (!qFuzzyCompare((float)layer.tileScale, (float)1.0))
+ layerAttributes["tileScale"] = QString::number(layer.tileScale);
layers.push_back({layerAttributes, maps});
}
snapshot->materials.push_back(std::make_pair(material, layers));
@@ -1300,6 +1302,9 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
oldNewIdMap[QUuid(valueOfKeyInMapOrEmpty(materialAttributes, "id"))] = newMaterialId;
for (const auto &layerIt: materialIt.second) {
MaterialLayer layer;
+ auto findTileScale = layerIt.first.find("tileScale");
+ if (findTileScale != layerIt.first.end())
+ layer.tileScale = findTileScale->second.toFloat();
for (const auto &mapItem: layerIt.second) {
auto textureTypeString = valueOfKeyInMapOrEmpty(mapItem, "for");
auto textureType = TextureTypeFromString(textureTypeString.toUtf8().constData());
diff --git a/src/document.h b/src/document.h
index ca571602..07c2c1d3 100644
--- a/src/document.h
+++ b/src/document.h
@@ -336,6 +336,7 @@ class MaterialLayer
{
public:
std::vector maps;
+ float tileScale = 1.0;
};
class Material
diff --git a/src/material.cpp b/src/material.cpp
index dfb0fdf93..612e2eb7 100644
--- a/src/material.cpp
+++ b/src/material.cpp
@@ -2,7 +2,10 @@
#include "imageforever.h"
#include "util.h"
-void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures)
+void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot,
+ const QUuid &materialId,
+ MaterialTextures &materialTextures,
+ float &tileScale)
{
QString materialIdString = materialId.toString();
for (const auto &materialItem: snapshot.materials) {
@@ -10,6 +13,9 @@ void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUui
continue;
for (const auto &layer: materialItem.second) {
//FIXME: Only support one layer currently
+ auto findTileScale = layer.first.find("tileScale");
+ if (findTileScale != layer.first.end())
+ tileScale = findTileScale->second.toFloat();
for (const auto &mapItem: layer.second) {
auto textureType = TextureTypeFromString(valueOfKeyInMapOrEmpty(mapItem, "for").toUtf8().constData());
if (textureType != TextureType::None) {
diff --git a/src/material.h b/src/material.h
index 08f2d13b..bbbfca97 100644
--- a/src/material.h
+++ b/src/material.h
@@ -10,6 +10,9 @@ struct MaterialTextures
const QImage *textureImages[(int)TextureType::Count - 1] = {nullptr};
};
-void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot, const QUuid &materialId, MaterialTextures &materialTextures);
+void initializeMaterialTexturesFromSnapshot(const Snapshot &snapshot,
+ const QUuid &materialId,
+ MaterialTextures &materialTextures,
+ float &tileScale);
#endif
diff --git a/src/materialeditwidget.cpp b/src/materialeditwidget.cpp
index 17597edb..2655ff34 100644
--- a/src/materialeditwidget.cpp
+++ b/src/materialeditwidget.cpp
@@ -121,6 +121,30 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent
QPushButton *saveButton = new QPushButton(tr("Save"));
connect(saveButton, &QPushButton::clicked, this, &MaterialEditWidget::save);
saveButton->setDefault(true);
+
+ FloatNumberWidget *tileScaleWidget = new FloatNumberWidget;
+ tileScaleWidget->setItemName(tr("Tile Scale"));
+ tileScaleWidget->setRange(0.01, 1.0);
+ tileScaleWidget->setValue(m_layers[0].tileScale);
+
+ m_tileScaleSlider = tileScaleWidget;
+
+ connect(tileScaleWidget, &FloatNumberWidget::valueChanged, [=](float value) {
+ m_layers[0].tileScale = value;
+ emit layersAdjusted();
+ });
+
+ QPushButton *tileScaleEraser = new QPushButton(QChar(fa::eraser));
+ Theme::initAwesomeToolButton(tileScaleEraser);
+
+ connect(tileScaleEraser, &QPushButton::clicked, [=]() {
+ tileScaleWidget->setValue(1.0);
+ });
+
+ QHBoxLayout *tileScaleLayout = new QHBoxLayout;
+ tileScaleLayout->addWidget(tileScaleEraser);
+ tileScaleLayout->addWidget(tileScaleWidget);
+ tileScaleLayout->addStretch();
QHBoxLayout *baseInfoLayout = new QHBoxLayout;
baseInfoLayout->addWidget(new QLabel(tr("Name")));
@@ -132,6 +156,7 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent
mainLayout->addLayout(paramtersLayout);
mainLayout->addStretch();
mainLayout->addWidget(Theme::createHorizontalLineWidget());
+ mainLayout->addLayout(tileScaleLayout);
mainLayout->addLayout(baseInfoLayout);
setLayout(mainLayout);
@@ -273,6 +298,7 @@ void MaterialEditWidget::setEditMaterialLayers(std::vector layers
}
if (!layers.empty()) {
for (const auto &layer: layers) {
+ m_layers[0].tileScale = layer.tileScale;
for (const auto &mapItem: layer.maps) {
int index = (int)mapItem.forWhat - 1;
if (index >= 0 && index < (int)TextureType::Count - 1) {
@@ -280,6 +306,7 @@ void MaterialEditWidget::setEditMaterialLayers(std::vector layers
}
}
}
+ m_tileScaleSlider->setValue(m_layers[0].tileScale);
}
for (int i = 1; i < (int)TextureType::Count; i++) {
updateMapButtonBackground(m_textureMapButtons[i - 1], ImageForever::get(m_layers[0].maps[i - 1].imageId));
diff --git a/src/materialeditwidget.h b/src/materialeditwidget.h
index 3543e402..7f757bf6 100644
--- a/src/materialeditwidget.h
+++ b/src/materialeditwidget.h
@@ -8,6 +8,7 @@
#include "modelwidget.h"
#include "materialpreviewsgenerator.h"
#include "imagepreviewwidget.h"
+#include "floatnumberwidget.h"
enum class PopupWidgetType
{
@@ -47,6 +48,7 @@ private:
const Document *m_document = nullptr;
MaterialPreviewsGenerator *m_materialPreviewsGenerator = nullptr;
ModelWidget *m_previewWidget = nullptr;
+ FloatNumberWidget *m_tileScaleSlider = nullptr;
bool m_isPreviewDirty = false;
bool m_closed = false;
QUuid m_materialId;
diff --git a/src/materialpreviewsgenerator.cpp b/src/materialpreviewsgenerator.cpp
index d592132a..585c7e31 100644
--- a/src/materialpreviewsgenerator.cpp
+++ b/src/materialpreviewsgenerator.cpp
@@ -82,15 +82,15 @@ void MaterialPreviewsGenerator::generate()
continue;
for (const auto &partId: partIds) {
if (TextureType::BaseColor == mapItem.forWhat)
- textureGenerator->addPartColorMap(partId, image);
+ textureGenerator->addPartColorMap(partId, image, layer.tileScale);
else if (TextureType::Normal == mapItem.forWhat)
- textureGenerator->addPartNormalMap(partId, image);
+ textureGenerator->addPartNormalMap(partId, image, layer.tileScale);
else if (TextureType::Metalness == mapItem.forWhat)
- textureGenerator->addPartMetalnessMap(partId, image);
+ textureGenerator->addPartMetalnessMap(partId, image, layer.tileScale);
else if (TextureType::Roughness == mapItem.forWhat)
- textureGenerator->addPartRoughnessMap(partId, image);
+ textureGenerator->addPartRoughnessMap(partId, image, layer.tileScale);
else if (TextureType::AmbientOcclusion == mapItem.forWhat)
- textureGenerator->addPartAmbientOcclusionMap(partId, image);
+ textureGenerator->addPartAmbientOcclusionMap(partId, image, layer.tileScale);
}
}
}
diff --git a/src/texturegenerator.cpp b/src/texturegenerator.cpp
index 666c1004..192c2534 100644
--- a/src/texturegenerator.cpp
+++ b/src/texturegenerator.cpp
@@ -123,39 +123,39 @@ MeshLoader *TextureGenerator::takeResultMesh()
return resultMesh;
}
-void TextureGenerator::addPartColorMap(QUuid partId, const QImage *image)
+void TextureGenerator::addPartColorMap(QUuid partId, const QImage *image, float tileScale)
{
if (nullptr == image)
return;
- m_partColorTextureMap[partId] = *image;
+ m_partColorTextureMap[partId] = std::make_pair(*image, tileScale);
}
-void TextureGenerator::addPartNormalMap(QUuid partId, const QImage *image)
+void TextureGenerator::addPartNormalMap(QUuid partId, const QImage *image, float tileScale)
{
if (nullptr == image)
return;
- m_partNormalTextureMap[partId] = *image;
+ m_partNormalTextureMap[partId] = std::make_pair(*image, tileScale);
}
-void TextureGenerator::addPartMetalnessMap(QUuid partId, const QImage *image)
+void TextureGenerator::addPartMetalnessMap(QUuid partId, const QImage *image, float tileScale)
{
if (nullptr == image)
return;
- m_partMetalnessTextureMap[partId] = *image;
+ m_partMetalnessTextureMap[partId] = std::make_pair(*image, tileScale);
}
-void TextureGenerator::addPartRoughnessMap(QUuid partId, const QImage *image)
+void TextureGenerator::addPartRoughnessMap(QUuid partId, const QImage *image, float tileScale)
{
if (nullptr == image)
return;
- m_partRoughnessTextureMap[partId] = *image;
+ m_partRoughnessTextureMap[partId] = std::make_pair(*image, tileScale);
}
-void TextureGenerator::addPartAmbientOcclusionMap(QUuid partId, const QImage *image)
+void TextureGenerator::addPartAmbientOcclusionMap(QUuid partId, const QImage *image, float tileScale)
{
if (nullptr == image)
return;
- m_partAmbientOcclusionTextureMap[partId] = *image;
+ m_partAmbientOcclusionTextureMap[partId] = std::make_pair(*image, tileScale);
}
QPainterPath TextureGenerator::expandedPainterPath(const QPainterPath &painterPath, int expandSize)
@@ -188,19 +188,20 @@ void TextureGenerator::prepare()
auto findUpdatedMaterialIdResult = updatedMaterialIdMap.find(bmeshNode.mirrorFromPartId.isNull() ? bmeshNode.partId : bmeshNode.mirrorFromPartId);
if (findUpdatedMaterialIdResult != updatedMaterialIdMap.end())
materialId = findUpdatedMaterialIdResult->second;
- initializeMaterialTexturesFromSnapshot(*m_snapshot, materialId, materialTextures);
+ float tileScale = 1.0;
+ initializeMaterialTexturesFromSnapshot(*m_snapshot, materialId, materialTextures, tileScale);
const QImage *image = materialTextures.textureImages[i];
if (nullptr != image) {
if (TextureType::BaseColor == forWhat)
- addPartColorMap(bmeshNode.partId, image);
+ addPartColorMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Normal == forWhat)
- addPartNormalMap(bmeshNode.partId, image);
+ addPartNormalMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Metalness == forWhat)
- addPartMetalnessMap(bmeshNode.partId, image);
+ addPartMetalnessMap(bmeshNode.partId, image, tileScale);
else if (TextureType::Roughness == forWhat)
- addPartRoughnessMap(bmeshNode.partId, image);
+ addPartRoughnessMap(bmeshNode.partId, image, tileScale);
else if (TextureType::AmbientOcclusion == forWhat)
- addPartAmbientOcclusionMap(bmeshNode.partId, image);
+ addPartAmbientOcclusionMap(bmeshNode.partId, image, tileScale);
}
}
}
@@ -395,13 +396,18 @@ void TextureGenerator::generate()
drawGradient(oppositeSource.first, std::get<0>(opposite->second), std::get<1>(opposite->second), std::get<2>(opposite->second), source.first);
}
- auto drawTexture = [&](const std::map &map, QPainter &painter) {
+ auto drawTexture = [&](const std::map> &map, QPainter &painter) {
for (const auto &it: partUvRects) {
const auto &partId = it.first;
const auto &rects = it.second;
auto findTextureResult = map.find(partId);
if (findTextureResult != map.end()) {
- const auto &image = findTextureResult->second;
+ float tileScale = findTextureResult->second.second;
+ const auto &image = findTextureResult->second.first;
+ auto newSize = image.size() * tileScale;
+ QImage scaledImage = image.scaled(newSize);
+ auto pixmap = QPixmap::fromImage(scaledImage);
+ QPixmap rotatedPixmap;
for (const auto &rect: rects) {
QRectF translatedRect = {
rect.left() * TextureGenerator::m_textureSize,
@@ -409,7 +415,19 @@ void TextureGenerator::generate()
rect.width() * TextureGenerator::m_textureSize,
rect.height() * TextureGenerator::m_textureSize
};
- painter.drawImage(translatedRect, image, QRectF(0, 0, image.width(), image.height()));
+ if (translatedRect.width() < translatedRect.height()) {
+ if (rotatedPixmap.isNull()) {
+ QPoint center = scaledImage.rect().center();
+ QMatrix matrix;
+ matrix.translate(center.x(), center.y());
+ matrix.rotate(90);
+ auto rotatedImage = scaledImage.transformed(matrix);
+ rotatedPixmap = QPixmap::fromImage(rotatedImage);
+ }
+ painter.drawTiledPixmap(translatedRect, rotatedPixmap);
+ } else {
+ painter.drawTiledPixmap(translatedRect, pixmap);
+ }
}
}
}
diff --git a/src/texturegenerator.h b/src/texturegenerator.h
index be819770..9d1210da 100644
--- a/src/texturegenerator.h
+++ b/src/texturegenerator.h
@@ -25,11 +25,11 @@ public:
QImage *takeResultTextureAmbientOcclusionImage();
Outcome *takeOutcome();
MeshLoader *takeResultMesh();
- void addPartColorMap(QUuid partId, const QImage *image);
- void addPartNormalMap(QUuid partId, const QImage *image);
- void addPartMetalnessMap(QUuid partId, const QImage *image);
- void addPartRoughnessMap(QUuid partId, const QImage *image);
- void addPartAmbientOcclusionMap(QUuid partId, const QImage *image);
+ void addPartColorMap(QUuid partId, const QImage *image, float tileScale);
+ void addPartNormalMap(QUuid partId, const QImage *image, float tileScale);
+ void addPartMetalnessMap(QUuid partId, const QImage *image, float tileScale);
+ void addPartRoughnessMap(QUuid partId, const QImage *image, float tileScale);
+ void addPartAmbientOcclusionMap(QUuid partId, const QImage *image, float tileScale);
void generate();
signals:
void finished();
@@ -53,11 +53,11 @@ private:
QImage *m_resultTextureMetalnessImage;
QImage *m_resultTextureAmbientOcclusionImage;
MeshLoader *m_resultMesh;
- std::map m_partColorTextureMap;
- std::map m_partNormalTextureMap;
- std::map m_partMetalnessTextureMap;
- std::map m_partRoughnessTextureMap;
- std::map m_partAmbientOcclusionTextureMap;
+ std::map> m_partColorTextureMap;
+ std::map> m_partNormalTextureMap;
+ std::map> m_partMetalnessTextureMap;
+ std::map> m_partRoughnessTextureMap;
+ std::map> m_partAmbientOcclusionTextureMap;
Snapshot *m_snapshot;
};
diff --git a/src/theme.cpp b/src/theme.cpp
index 4cdaf45f..ce8f131f 100644
--- a/src/theme.cpp
+++ b/src/theme.cpp
@@ -57,10 +57,10 @@ void Theme::initAwsomeBaseSizes()
Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67);
Theme::partPreviewImageSize = (Theme::miniIconSize * 3);
Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 3.7;
- Theme::materialPreviewImageSize = Theme::sidebarPreferredWidth * 0.4;
- Theme::cutFacePreviewImageSize = Theme::materialPreviewImageSize;
- Theme::posePreviewImageSize = Theme::materialPreviewImageSize;
- Theme::motionPreviewImageSize = Theme::materialPreviewImageSize;
+ Theme::posePreviewImageSize = Theme::sidebarPreferredWidth * 0.4;
+ Theme::materialPreviewImageSize = Theme::posePreviewImageSize;
+ Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize;
+ Theme::motionPreviewImageSize = Theme::posePreviewImageSize;
Theme::normalButtonSize = Theme::toolIconSize * 2;
}