mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
wallpaper: support different fill modes
This commit is contained in:
@@ -64,6 +64,7 @@ Singleton {
|
|||||||
property bool useFahrenheit: false
|
property bool useFahrenheit: false
|
||||||
property bool nightModeEnabled: false
|
property bool nightModeEnabled: false
|
||||||
property int animationSpeed: SettingsData.AnimationSpeed.Short
|
property int animationSpeed: SettingsData.AnimationSpeed.Short
|
||||||
|
property string wallpaperFillMode: "Fill"
|
||||||
|
|
||||||
property bool showLauncherButton: true
|
property bool showLauncherButton: true
|
||||||
property bool showWorkspaceSwitcher: true
|
property bool showWorkspaceSwitcher: true
|
||||||
@@ -486,6 +487,7 @@ Singleton {
|
|||||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
||||||
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
|
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
|
||||||
|
wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill"
|
||||||
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : SettingsData.AnimationSpeed.Short
|
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : SettingsData.AnimationSpeed.Short
|
||||||
acMonitorTimeout = settings.acMonitorTimeout !== undefined ? settings.acMonitorTimeout : 0
|
acMonitorTimeout = settings.acMonitorTimeout !== undefined ? settings.acMonitorTimeout : 0
|
||||||
acLockTimeout = settings.acLockTimeout !== undefined ? settings.acLockTimeout : 0
|
acLockTimeout = settings.acLockTimeout !== undefined ? settings.acLockTimeout : 0
|
||||||
@@ -648,6 +650,7 @@ Singleton {
|
|||||||
"hideBrightnessSlider": hideBrightnessSlider,
|
"hideBrightnessSlider": hideBrightnessSlider,
|
||||||
"widgetBackgroundColor": widgetBackgroundColor,
|
"widgetBackgroundColor": widgetBackgroundColor,
|
||||||
"surfaceBase": surfaceBase,
|
"surfaceBase": surfaceBase,
|
||||||
|
"wallpaperFillMode": wallpaperFillMode,
|
||||||
"notificationTimeoutLow": notificationTimeoutLow,
|
"notificationTimeoutLow": notificationTimeoutLow,
|
||||||
"notificationTimeoutNormal": notificationTimeoutNormal,
|
"notificationTimeoutNormal": notificationTimeoutNormal,
|
||||||
"notificationTimeoutCritical": notificationTimeoutCritical,
|
"notificationTimeoutCritical": notificationTimeoutCritical,
|
||||||
@@ -722,7 +725,7 @@ Singleton {
|
|||||||
"dankBarGothCornersEnabled", "dankBarBorderEnabled", "dankBarBorderColor",
|
"dankBarGothCornersEnabled", "dankBarBorderEnabled", "dankBarBorderColor",
|
||||||
"dankBarBorderOpacity", "dankBarBorderThickness", "popupGapsAuto", "popupGapsManual",
|
"dankBarBorderOpacity", "dankBarBorderThickness", "popupGapsAuto", "popupGapsManual",
|
||||||
"dankBarPosition", "lockScreenShowPowerActions", "enableFprint", "maxFprintTries",
|
"dankBarPosition", "lockScreenShowPowerActions", "enableFprint", "maxFprintTries",
|
||||||
"hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase",
|
"hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase", "wallpaperFillMode",
|
||||||
"notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical",
|
"notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical",
|
||||||
"notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm",
|
"notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm",
|
||||||
"customPowerActionLock", "customPowerActionLogout", "customPowerActionSuspend",
|
"customPowerActionLock", "customPowerActionLogout", "customPowerActionSuspend",
|
||||||
@@ -1055,6 +1058,11 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWallpaperFillMode(mode) {
|
||||||
|
wallpaperFillMode = mode
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
function setShowLauncherButton(enabled) {
|
function setShowLauncherButton(enabled) {
|
||||||
showLauncherButton = enabled
|
showLauncherButton = enabled
|
||||||
saveSettings()
|
saveSettings()
|
||||||
|
|||||||
@@ -410,6 +410,56 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: fillModeGroup.height
|
||||||
|
visible: {
|
||||||
|
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
|
||||||
|
return currentWallpaper !== "" && !currentWallpaper.startsWith("#")
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButtonGroup {
|
||||||
|
id: fillModeGroup
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
model: ["Stretch", "Fit", "Fill", "Tile", "Tile V", "Tile H", "Pad"]
|
||||||
|
selectionMode: "single"
|
||||||
|
buttonHeight: 28
|
||||||
|
minButtonWidth: 48
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
checkIconSize: 0
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
|
checkEnabled: false
|
||||||
|
currentIndex: {
|
||||||
|
const modes = ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
||||||
|
return modes.indexOf(SettingsData.wallpaperFillMode)
|
||||||
|
}
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (selected) {
|
||||||
|
const modes = ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
||||||
|
SettingsData.setWallpaperFillMode(modes[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onWallpaperFillModeChanged() {
|
||||||
|
const modes = ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
||||||
|
fillModeGroup.currentIndex = modes.indexOf(SettingsData.wallpaperFillMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: personalizationTab
|
||||||
|
function onSelectedMonitorNameChanged() {
|
||||||
|
Qt.callLater(() => {
|
||||||
|
const modes = ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
||||||
|
fillModeGroup.currentIndex = modes.indexOf(SettingsData.wallpaperFillMode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Per-Mode Wallpaper Section - Full Width
|
// Per-Mode Wallpaper Section - Full Width
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ Variants {
|
|||||||
property bool isColorSource: source.startsWith("#")
|
property bool isColorSource: source.startsWith("#")
|
||||||
property string transitionType: SessionData.wallpaperTransition
|
property string transitionType: SessionData.wallpaperTransition
|
||||||
property string actualTransitionType: transitionType
|
property string actualTransitionType: transitionType
|
||||||
|
property bool isInitialized: false
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SessionData
|
target: SessionData
|
||||||
@@ -71,7 +72,7 @@ Variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
property real transitionProgress: 0
|
property real transitionProgress: 0
|
||||||
property real fillMode: 1.0
|
property real shaderFillMode: getFillMode(SettingsData.wallpaperFillMode)
|
||||||
property vector4d fillColor: Qt.vector4d(0, 0, 0, 1)
|
property vector4d fillColor: Qt.vector4d(0, 0, 0, 1)
|
||||||
property real edgeSmoothness: 0.1
|
property real edgeSmoothness: 0.1
|
||||||
|
|
||||||
@@ -86,11 +87,34 @@ Variants {
|
|||||||
property bool hasCurrent: currentWallpaper.status === Image.Ready && !!currentWallpaper.source
|
property bool hasCurrent: currentWallpaper.status === Image.Ready && !!currentWallpaper.source
|
||||||
property bool booting: !hasCurrent && nextWallpaper.status === Image.Ready
|
property bool booting: !hasCurrent && nextWallpaper.status === Image.Ready
|
||||||
|
|
||||||
|
function getFillMode(modeName) {
|
||||||
|
switch(modeName) {
|
||||||
|
case "Stretch": return Image.Stretch
|
||||||
|
case "Fit":
|
||||||
|
case "PreserveAspectFit": return Image.PreserveAspectFit
|
||||||
|
case "Fill":
|
||||||
|
case "PreserveAspectCrop": return Image.PreserveAspectCrop
|
||||||
|
case "Tile": return Image.Tile
|
||||||
|
case "TileVertically": return Image.TileVertically
|
||||||
|
case "TileHorizontally": return Image.TileHorizontally
|
||||||
|
case "Pad": return Image.Pad
|
||||||
|
default: return Image.PreserveAspectCrop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WallpaperEngineProc {
|
WallpaperEngineProc {
|
||||||
id: weProc
|
id: weProc
|
||||||
monitor: modelData.name
|
monitor: modelData.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (source) {
|
||||||
|
const formattedSource = source.startsWith("file://") ? source : "file://" + source
|
||||||
|
setWallpaperImmediate(formattedSource)
|
||||||
|
}
|
||||||
|
isInitialized = true
|
||||||
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
weProc.stop()
|
weProc.stop()
|
||||||
}
|
}
|
||||||
@@ -109,9 +133,9 @@ Variants {
|
|||||||
} else if (isColor) {
|
} else if (isColor) {
|
||||||
setWallpaperImmediate("")
|
setWallpaperImmediate("")
|
||||||
} else {
|
} else {
|
||||||
// Always set immediately if there's no current wallpaper (startup)
|
if (!isInitialized || !currentWallpaper.source) {
|
||||||
if (!currentWallpaper.source) {
|
|
||||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source)
|
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source)
|
||||||
|
isInitialized = true
|
||||||
} else {
|
} else {
|
||||||
changeWallpaper(source.startsWith("file://") ? source : "file://" + source)
|
changeWallpaper(source.startsWith("file://") ? source : "file://" + source)
|
||||||
}
|
}
|
||||||
@@ -211,7 +235,7 @@ Variants {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: true
|
cache: true
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
@@ -223,7 +247,7 @@ Variants {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: true
|
cache: true
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status !== Image.Ready)
|
if (status !== Image.Ready)
|
||||||
@@ -275,7 +299,7 @@ Variants {
|
|||||||
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
|
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
|
||||||
property variant source2: nextWallpaper
|
property variant source2: nextWallpaper
|
||||||
property real progress: root.transitionProgress
|
property real progress: root.transitionProgress
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -296,7 +320,7 @@ Variants {
|
|||||||
property real progress: root.transitionProgress
|
property real progress: root.transitionProgress
|
||||||
property real smoothness: root.edgeSmoothness
|
property real smoothness: root.edgeSmoothness
|
||||||
property real direction: root.wipeDirection
|
property real direction: root.wipeDirection
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -319,7 +343,7 @@ Variants {
|
|||||||
property real aspectRatio: root.width / root.height
|
property real aspectRatio: root.width / root.height
|
||||||
property real centerX: root.discCenterX
|
property real centerX: root.discCenterX
|
||||||
property real centerY: root.discCenterY
|
property real centerY: root.discCenterY
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -342,7 +366,7 @@ Variants {
|
|||||||
property real aspectRatio: root.width / root.height
|
property real aspectRatio: root.width / root.height
|
||||||
property real stripeCount: root.stripesCount
|
property real stripeCount: root.stripesCount
|
||||||
property real angle: root.stripesAngle
|
property real angle: root.stripesAngle
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -365,7 +389,7 @@ Variants {
|
|||||||
property real centerX: 0.5
|
property real centerX: 0.5
|
||||||
property real centerY: 0.5
|
property real centerY: 0.5
|
||||||
property real aspectRatio: root.width / root.height
|
property real aspectRatio: root.width / root.height
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -385,7 +409,7 @@ Variants {
|
|||||||
property variant source2: nextWallpaper
|
property variant source2: nextWallpaper
|
||||||
property real progress: root.transitionProgress
|
property real progress: root.transitionProgress
|
||||||
property real smoothness: root.edgeSmoothness
|
property real smoothness: root.edgeSmoothness
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
@@ -411,7 +435,7 @@ Variants {
|
|||||||
property real aspectRatio: root.width / root.height
|
property real aspectRatio: root.width / root.height
|
||||||
property real centerX: root.discCenterX
|
property real centerX: root.discCenterX
|
||||||
property real centerY: root.discCenterY
|
property real centerY: root.discCenterY
|
||||||
property real fillMode: root.fillMode
|
property real fillMode: root.shaderFillMode
|
||||||
property vector4d fillColor: root.fillColor
|
property vector4d fillColor: root.fillColor
|
||||||
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
|
||||||
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
|
||||||
|
|||||||
@@ -16,67 +16,69 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
||||||
float aspectRatio; // Width / Height of the screen
|
float aspectRatio; // Width / Height of the screen
|
||||||
|
|
||||||
// Fill mode parameters
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float fillMode; // 0=no(center), 1=crop(fill), 2=fit(contain), 3=stretch
|
float imageWidth1;
|
||||||
float imageWidth1; // Width of source1 image
|
float imageHeight1;
|
||||||
float imageHeight1; // Height of source1 image
|
float imageWidth2;
|
||||||
float imageWidth2; // Width of source2 image
|
float imageHeight2;
|
||||||
float imageHeight2; // Height of source2 image
|
float screenWidth;
|
||||||
float screenWidth; // Screen width
|
float screenHeight;
|
||||||
float screenHeight; // Screen height
|
vec4 fillColor;
|
||||||
vec4 fillColor; // Fill color for empty areas (default: black)
|
|
||||||
} ubuf;
|
} ubuf;
|
||||||
|
|
||||||
// Calculate UV coordinates based on fill mode
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
float imageAspect = imgWidth / imgHeight;
|
|
||||||
float screenAspect = ubuf.screenWidth / ubuf.screenHeight;
|
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
// Mode 0: no (center) - No resize, center image at original size
|
transformedUV = uv;
|
||||||
// Convert UV to pixel coordinates, offset, then back to UV in image space
|
}
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
// Mode 1: crop (fill/cover) - Fill screen, crop excess (default)
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 2.5) {
|
else if (ubuf.fillMode < 3.5) {
|
||||||
// Mode 2: fit (contain) - Fit inside screen, maintain aspect ratio
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
}
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
else if (ubuf.fillMode < 4.5) {
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
// Convert screen UV to pixel coordinates
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
// Adjust for offset and scale
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
// Convert back to UV coordinates in image space
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
// Mode 3: stretch - Use original UV (stretches to fit)
|
|
||||||
// No transformation needed for stretch mode
|
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample texture with fill mode and handle out-of-bounds
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
|
|
||||||
// Check if UV is out of bounds
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
return ubuf.fillColor;
|
return ubuf.fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture(tex, transformedUV);
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float progress;
|
float progress;
|
||||||
|
|
||||||
// Fill mode parameters
|
// Fill mode parameters
|
||||||
float fillMode; // 0=no(center), 1=crop(fill), 2=fit(contain), 3=stretch
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float imageWidth1; // Width of source1 image
|
float imageWidth1; // Width of source1 image
|
||||||
float imageHeight1; // Height of source1 image
|
float imageHeight1; // Height of source1 image
|
||||||
float imageWidth2; // Width of source2 image
|
float imageWidth2; // Width of source2 image
|
||||||
@@ -23,56 +23,59 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
vec4 fillColor; // Fill color for empty areas (default: black)
|
vec4 fillColor; // Fill color for empty areas (default: black)
|
||||||
} ubuf;
|
} ubuf;
|
||||||
|
|
||||||
// Calculate UV coordinates based on fill mode
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
float imageAspect = imgWidth / imgHeight;
|
|
||||||
float screenAspect = ubuf.screenWidth / ubuf.screenHeight;
|
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
// Mode 0: no (center) - No resize, center image at original size
|
transformedUV = uv;
|
||||||
// Convert UV to pixel coordinates, offset, then back to UV in image space
|
}
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
// Mode 1: crop (fill/cover) - Fill screen, crop excess (default)
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 2.5) {
|
else if (ubuf.fillMode < 3.5) {
|
||||||
// Mode 2: fit (contain) - Fit inside screen, maintain aspect ratio
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
}
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
else if (ubuf.fillMode < 4.5) {
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
// Convert screen UV to pixel coordinates
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
// Adjust for offset and scale
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
// Convert back to UV coordinates in image space
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
// Mode 3: stretch - Use original UV (stretches to fit)
|
|
||||||
// No transformation needed for stretch mode
|
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample texture with fill mode and handle out-of-bounds
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
|
|
||||||
// Check if UV is out of bounds
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
return ubuf.fillColor;
|
return ubuf.fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture(tex, transformedUV);
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float smoothness;
|
float smoothness;
|
||||||
float aspectRatio;
|
float aspectRatio;
|
||||||
|
|
||||||
float fillMode;
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float imageWidth1;
|
float imageWidth1;
|
||||||
float imageHeight1;
|
float imageHeight1;
|
||||||
float imageWidth2;
|
float imageWidth2;
|
||||||
@@ -28,35 +28,58 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
transformedUV = uv;
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 2.5) {
|
else if (ubuf.fillMode < 3.5) {
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
}
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(scaledImageSize)) * 0.5;
|
else if (ubuf.fillMode < 4.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 tuv = calculateUV(uv, imgWidth, imgHeight);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
if (tuv.x < 0.0 || tuv.x > 1.0 || tuv.y < 0.0 || tuv.y > 1.0) {
|
|
||||||
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
return ubuf.fillColor;
|
return ubuf.fillColor;
|
||||||
}
|
}
|
||||||
return texture(tex, tuv);
|
|
||||||
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float smoothness; // controls starting block size (0..1)
|
float smoothness; // controls starting block size (0..1)
|
||||||
float aspectRatio; // (unused)
|
float aspectRatio; // (unused)
|
||||||
|
|
||||||
// Fill mode parameters
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float fillMode; // 0=no(center), 1=crop, 2=fit, 3=stretch
|
|
||||||
float imageWidth1;
|
float imageWidth1;
|
||||||
float imageHeight1;
|
float imageHeight1;
|
||||||
float imageWidth2;
|
float imageWidth2;
|
||||||
@@ -29,17 +28,11 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
transformedUV = uv;
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
}
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
else if (ubuf.fillMode < 1.5) {
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
} else if (ubuf.fillMode < 1.5) {
|
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
|
||||||
} else if (ubuf.fillMode < 2.5) {
|
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
@@ -47,13 +40,46 @@ vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
|||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 3.5) {
|
||||||
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 4.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float w, float h) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 tuv = calculateUV(uv, w, h);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
if (tuv.x < 0.0 || tuv.x > 1.0 || tuv.y < 0.0 || tuv.y > 1.0) return ubuf.fillColor;
|
|
||||||
return texture(tex, tuv);
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
|
return ubuf.fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 quantizeUV(vec2 uv, float cellPx) {
|
vec2 quantizeUV(vec2 uv, float cellPx) {
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float smoothness; // 0..1 (edge softness)
|
float smoothness; // 0..1 (edge softness)
|
||||||
float aspectRatio; // width / height
|
float aspectRatio; // width / height
|
||||||
|
|
||||||
// Fill mode parameters
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float fillMode; // 0=no(center), 1=crop(fill), 2=fit(contain), 3=stretch
|
|
||||||
float imageWidth1;
|
float imageWidth1;
|
||||||
float imageHeight1;
|
float imageHeight1;
|
||||||
float imageWidth2;
|
float imageWidth2;
|
||||||
@@ -31,18 +30,9 @@ vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
|||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
transformedUV = uv;
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
|
||||||
}
|
|
||||||
else if (ubuf.fillMode < 2.5) {
|
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
@@ -50,15 +40,46 @@ vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
|||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
// else: stretch
|
else if (ubuf.fillMode < 2.5) {
|
||||||
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 3.5) {
|
||||||
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 4.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float w, float h) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 tuv = calculateUV(uv, w, h);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
if (tuv.x < 0.0 || tuv.x > 1.0 || tuv.y < 0.0 || tuv.y > 1.0) return ubuf.fillColor;
|
|
||||||
return texture(tex, tuv);
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
|
return ubuf.fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|||||||
@@ -16,67 +16,69 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
||||||
float aspectRatio; // Width / Height of the screen
|
float aspectRatio; // Width / Height of the screen
|
||||||
|
|
||||||
// Fill mode parameters
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float fillMode; // 0=no(center), 1=crop(fill), 2=fit(contain), 3=stretch
|
float imageWidth1;
|
||||||
float imageWidth1; // Width of source1 image
|
float imageHeight1;
|
||||||
float imageHeight1; // Height of source1 image
|
float imageWidth2;
|
||||||
float imageWidth2; // Width of source2 image
|
float imageHeight2;
|
||||||
float imageHeight2; // Height of source2 image
|
float screenWidth;
|
||||||
float screenWidth; // Screen width
|
float screenHeight;
|
||||||
float screenHeight; // Screen height
|
vec4 fillColor;
|
||||||
vec4 fillColor; // Fill color for empty areas (default: black)
|
|
||||||
} ubuf;
|
} ubuf;
|
||||||
|
|
||||||
// Calculate UV coordinates based on fill mode
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
float imageAspect = imgWidth / imgHeight;
|
|
||||||
float screenAspect = ubuf.screenWidth / ubuf.screenHeight;
|
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
// Mode 0: no (center) - No resize, center image at original size
|
transformedUV = uv;
|
||||||
// Convert UV to pixel coordinates, offset, then back to UV in image space
|
}
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
// Mode 1: crop (fill/cover) - Fill screen, crop excess (default)
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 2.5) {
|
else if (ubuf.fillMode < 3.5) {
|
||||||
// Mode 2: fit (contain) - Fit inside screen, maintain aspect ratio
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
}
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
else if (ubuf.fillMode < 4.5) {
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
// Convert screen UV to pixel coordinates
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
// Adjust for offset and scale
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
// Convert back to UV coordinates in image space
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
// Mode 3: stretch - Use original UV (stretches to fit)
|
|
||||||
// No transformation needed for stretch mode
|
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample texture with fill mode and handle out-of-bounds
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
|
|
||||||
// Check if UV is out of bounds
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
return ubuf.fillColor;
|
return ubuf.fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture(tex, transformedUV);
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,67 +14,69 @@ layout(std140, binding = 0) uniform buf {
|
|||||||
float direction; // 0=left, 1=right, 2=up, 3=down
|
float direction; // 0=left, 1=right, 2=up, 3=down
|
||||||
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
float smoothness; // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
|
||||||
|
|
||||||
// Fill mode parameters
|
float fillMode; // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
|
||||||
float fillMode; // 0=no(center), 1=crop(fill), 2=fit(contain), 3=stretch
|
float imageWidth1;
|
||||||
float imageWidth1; // Width of source1 image
|
float imageHeight1;
|
||||||
float imageHeight1; // Height of source1 image
|
float imageWidth2;
|
||||||
float imageWidth2; // Width of source2 image
|
float imageHeight2;
|
||||||
float imageHeight2; // Height of source2 image
|
float screenWidth;
|
||||||
float screenWidth; // Screen width
|
float screenHeight;
|
||||||
float screenHeight; // Screen height
|
vec4 fillColor;
|
||||||
vec4 fillColor; // Fill color for empty areas (default: black)
|
|
||||||
} ubuf;
|
} ubuf;
|
||||||
|
|
||||||
// Calculate UV coordinates based on fill mode
|
|
||||||
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
|
||||||
float imageAspect = imgWidth / imgHeight;
|
|
||||||
float screenAspect = ubuf.screenWidth / ubuf.screenHeight;
|
|
||||||
vec2 transformedUV = uv;
|
vec2 transformedUV = uv;
|
||||||
|
|
||||||
if (ubuf.fillMode < 0.5) {
|
if (ubuf.fillMode < 0.5) {
|
||||||
// Mode 0: no (center) - No resize, center image at original size
|
transformedUV = uv;
|
||||||
// Convert UV to pixel coordinates, offset, then back to UV in image space
|
}
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
|
||||||
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
|
||||||
vec2 imagePixel = screenPixel - imageOffset;
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
|
||||||
}
|
|
||||||
else if (ubuf.fillMode < 1.5) {
|
else if (ubuf.fillMode < 1.5) {
|
||||||
// Mode 1: crop (fill/cover) - Fill screen, crop excess (default)
|
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
|
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
||||||
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
|
vec2 imagePixel = (screenPixel - offset) / scale;
|
||||||
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
|
}
|
||||||
|
else if (ubuf.fillMode < 2.5) {
|
||||||
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
||||||
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
|
||||||
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
|
||||||
}
|
}
|
||||||
else if (ubuf.fillMode < 2.5) {
|
else if (ubuf.fillMode < 3.5) {
|
||||||
// Mode 2: fit (contain) - Fit inside screen, maintain aspect ratio
|
transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
|
||||||
float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
|
}
|
||||||
vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
|
else if (ubuf.fillMode < 4.5) {
|
||||||
vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(uv.x, fract(tileUV.y));
|
||||||
// Convert screen UV to pixel coordinates
|
}
|
||||||
|
else if (ubuf.fillMode < 5.5) {
|
||||||
|
vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
|
||||||
|
transformedUV = vec2(fract(tileUV.x), uv.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
|
||||||
// Adjust for offset and scale
|
vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
|
||||||
vec2 imagePixel = (screenPixel - offset) / scale;
|
vec2 imagePixel = screenPixel - imageOffset;
|
||||||
// Convert back to UV coordinates in image space
|
|
||||||
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
transformedUV = imagePixel / vec2(imgWidth, imgHeight);
|
||||||
}
|
}
|
||||||
// Mode 3: stretch - Use original UV (stretches to fit)
|
|
||||||
// No transformation needed for stretch mode
|
|
||||||
|
|
||||||
return transformedUV;
|
return transformedUV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample texture with fill mode and handle out-of-bounds
|
|
||||||
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
|
||||||
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);
|
||||||
|
|
||||||
// Check if UV is out of bounds
|
if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
|
||||||
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
return texture(tex, transformedUV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
|
||||||
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
transformedUV.y < 0.0 || transformedUV.y > 1.0) {
|
||||||
return ubuf.fillColor;
|
return ubuf.fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture(tex, transformedUV);
|
return texture(tex, transformedUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user