Improved shader channels

This commit is contained in:
Digital Artifex
2025-11-07 08:03:20 -05:00
parent 812288fe52
commit dc0439b008
2 changed files with 356 additions and 186 deletions

View File

@@ -304,20 +304,162 @@ Rectangle
console.log('Uknown channel type 3 ' + typeof json.channel3) console.log('Uknown channel type 3 ' + typeof json.channel3)
} }
channel.frameBufferChannel = json.frame_buffer_channel !== undefined ? json.frame_buffer_channel : -1 /*
channel.type = json.type !== undefined ? json.type : typeDefault Channel Type
channel.visible = false
channel.iMouse = Qt.binding(() => { return mainItem.iMouse; }) parse this one first so we can handle defaults, but not ignore overrides
channel.iTime = Qt.binding(() => { return mainItem.iTime; }) */
channel.iResolutionScale = json.resolution_scale ? json.resolution_scale : 1.0 if(typeof json.type === "number")
{
channel.type = json.type
}
else if(typeof json.type === "string")
{
switch(json.type.toLowerCase())
{
case "image":
channel.type = ShaderChannel.ImageChannel
break;
case "audio":
channel.type = ShaderChannel.AudioChannel
break;
case "video":
channel.type = ShaderChannel.VideoChannel
break;
case "cubemap":
channel.type = ShaderChannel.ImageChannel
break;
case "shader":
channel.type = ShaderChannel.ShaderChannel
break;
case "scene":
channel.type = ShaderChannel.SceneChannel
break;
default:
channel.type = ShaderChannel.ImageChannel
break;
}
}
channel.frameBufferChannel = typeof json.frame_buffer_channel === "number" ? json.frame_buffer_channel : -1
channel.iTimeScale = typeof json.time_scale === "number" ? json.time_scale : 1.0
channel.iResolutionScale = typeof json.resolution_scale === "number" ? json.resolution_scale : 1.0
channel.iResolution = Qt.binding(() => { return json.resolution_x ? Qt.vector3d(json.resolution_x, json.resolution_y, 1.0) : Qt.vector3d(mainItem.iResolution.x,mainItem.iResolution.y,1.0); }) channel.iResolution = Qt.binding(() => { return json.resolution_x ? Qt.vector3d(json.resolution_x, json.resolution_y, 1.0) : Qt.vector3d(mainItem.iResolution.x,mainItem.iResolution.y,1.0); })
channel.mouseBias = json.mouse_scale ? json.mouse_scale : 1.0 channel.mouseBias = json.mouse_scale ? json.mouse_scale : 1.0
channel.iTimeScale = json.time_scale ? json.time_scale : 1.0
channel.iTimeDelta = Qt.binding(() => { return mainItem.iTimeDelta; })
channel.width = Qt.binding(() => channel.iResolution.x) channel.width = Qt.binding(() => channel.iResolution.x)
channel.height = Qt.binding(() => channel.iResolution.y) channel.height = Qt.binding(() => channel.iResolution.y)
channel.materialTexture = json.materialTexture !== undefined ? getFilePath(json.materialTexture) : "" channel.materialTexture = typeof json.materialTexture === "string" ? getFilePath(json.materialTexture) : ""
channel.materialShader = json.materialShader !== undefined ? getFilePath(json.materialShader) : "" channel.materialShader = typeof json.materialShader === "string" ? getFilePath(json.materialShader) : ""
channel.mipmap = typeof json.mipmap === "boolean" ? json.mipmap : true
channel.blending = typeof json.blending === "boolean" ? json.blending : true
channel.samples = typeof json.samples === "number" ? json.samples : 1
channel.invert = typeof json.invert === "boolean" ? json.invert : false
if(typeof json.source === "string")
{
channel.source = getFilePath(json.source)
}
else
{
channel.source = ""
}
/*
Source Format
*/
var format = ShaderEffectSource.RGB8A
if(typeof json.format === "string")
{
switch(json.format.toLowerCase())
{
case "rgb8a":
format = ShaderEffectSource.RGB8A
break;
case "rgb16f":
format = ShaderEffectSource.RGB16F
break;
case "rgb32f":
format = ShaderEffectSource.RGB32F
break;
default:
format = ShaderEffectSource.RGB8A
break;
}
console.log("Set format mode to " + format)
}
channel.format = format
/*
Source Wrap Mode
*/
var wrapMode = ShaderEffectSource.Repeat
if(typeof json.wrap_mode === "string")
{
switch(json.wrap_mode.toLowerCase())
{
case "clamptoedge":
wrapMode = ShaderEffectSource.ClampToEdge
break;
case "repeathorizontally":
wrapMode = ShaderEffectSource.RepeatHorizontally
break;
case "repeatvertically":
wrapMode = ShaderEffectSource.RepeatVertically
break;
case "repeat":
wrapMode = ShaderEffectSource.Repeat
break;
default:
wrapMode = ShaderEffectSource.Repeat
break;
}
console.log("Set wrap mode to " + wrapMode)
}
channel.wrapMode = wrapMode
/*
Source Mirroring Mode
*/
var mirrorMode = ShaderEffectSource.NoMirroring
if(typeof json.texture_mirroring === "string")
{
switch(json.texture_mirroring.toLowerCase())
{
case "nomirroring":
mirrorMode = ShaderEffectSource.NoMirroring
break;
case "mirrorhorizontally":
mirrorMode = ShaderEffectSource.MirrorHorizontally
break;
case "mirrorvertically":
mirrorMode = ShaderEffectSource.MirrorVertically
break;
default:
mirrorMode = ShaderEffectSource.NoMirroring
break;
}
console.log("Set mirror mode to " + mirrorMode)
}
channel.textureMirroring = mirrorMode
/*
Non-configurable bindings
*/
channel.iMouse = Qt.binding(() => { return mainItem.iMouse; })
channel.iTime = Qt.binding(() => { return mainItem.iTime; })
channel.iTimeDelta = Qt.binding(() => { return mainItem.iTimeDelta; })
channel.iFrameRate = Qt.binding(() => { return mainItem.iFrameRate; })
channel.iFrame = Qt.binding(() => { return mainItem.iFrame; })
channel.visible = false
channel.iChannelTime = Qt.binding(() => { channel.iChannelTime = Qt.binding(() => {
return [ return [
@@ -328,13 +470,6 @@ Rectangle
]; ];
}); });
channel.iFrameRate = Qt.binding(() => { return mainItem.iFrameRate; })
channel.iFrame = mainItem.iFrame
channel.invert = json.invert ? json.invert : false
var source = getFilePath(json.source)
channel.source = source
if(autodestroy) if(autodestroy)
data.channels.push(channel) data.channels.push(channel)
} }

View File

@@ -70,37 +70,16 @@ Item
property var iDate property var iDate
property real iTimeScale: 1 // This is used to scale the time for the shader, allowing for slow motion or fast forward effects per channel property real iTimeScale: 1 // This is used to scale the time for the shader, allowing for slow motion or fast forward effects per channel
property int frameBufferChannel: -1 property int frameBufferChannel: -1
property bool blending: false property bool blending: true
property string materialTexture:"" property string materialTexture:""
property string materialShader:"" property string materialShader:""
property bool mipmap: false
property int samples: 1
property var textureMirroring: ShaderEffectSource.NoMirroring
property var wrapMode: ShaderEffectSource.ClampToEdge
property var format: ShaderEffectSource.RGB8A
property var windowModel property var windowModel
property bool invert: false
// bind to ShaderEffectSource.live to prevent data being updated causing a refresh between intended frames. I think this may be why
// the shaders are using so many resources. This is likely to cause issues of its own since we have no way of knowing the progress
// of the current capture, but we'll cross that bridge later
property bool active: true
// this seems to work better than doubling the timer frequency and setting active/inactive states,
// but god damn does it feel hacky. Try to find a better way to actually limit framerate
onIFrameChanged: () =>
{
// this method of frame limiting breaks video playback
// even when the video is the source of an item being limited
// in this way
if(type === ShaderChannel.ShaderChannel)
{
active = true;
active = false;
return;
}
if(active === false)
active = true;
}
property bool invert
property var iChannelResolution: [Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1), Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1), Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1)] property var iChannelResolution: [Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1), Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1), Qt.vector3d(channel.iResolution.x * iResolutionScale, channel.iResolution.y * iResolutionScale, 1)]
@@ -282,60 +261,63 @@ Item
{ {
if(!videoComponent.loaded) if(!videoComponent.loaded)
return; return;
delayedStartTimer.start()
autoStart()
//delayedStartTimer.start()
} }
onMediaStatusChanged: // onMediaStatusChanged:
{ // {
switch(mediaStatus) // switch(mediaStatus)
{ // {
case MediaPlayer.NoMedia: // case MediaPlayer.NoMedia:
console.log("No media loaded") // console.log("No media loaded")
break; // break;
case MediaPlayer.LoadingMedia: // case MediaPlayer.LoadingMedia:
console.log("Video loading") // console.log("Video loading")
break; // break;
case MediaPlayer.LoadedMedia: // case MediaPlayer.LoadedMedia:
console.log("Video Loaded") // console.log("Video Loaded")
break; // break;
case MediaPlayer.BufferingMedia: // case MediaPlayer.BufferingMedia:
console.log("Video buffering") // console.log("Video buffering")
break; // break;
case MediaPlayer.StalledMedia: // case MediaPlayer.StalledMedia:
console.log("Video stalled") // console.log("Video stalled")
break; // break;
case MediaPlayer.BufferedMedia: // case MediaPlayer.BufferedMedia:
console.log("Video buffered") // console.log("Video buffered")
break; // break;
case MediaPlayer.EndOfMedia: // case MediaPlayer.EndOfMedia:
console.log("Video EOF") // console.log("Video EOF")
break; // break;
case MediaPlayer.InvalidMedia: // case MediaPlayer.InvalidMedia:
console.log("Video invalid") // console.log("Video invalid")
break; // break;
} // }
} // }
onPlaybackStateChanged: // onPlaybackStateChanged:
{ // {
switch(playbackState) // switch(playbackState)
{ // {
case MediaPlayer.PlayingState: // case MediaPlayer.PlayingState:
console.log("Video playback started") // console.log("Video playback started")
break; // break;
case MediaPlayer.PausedState: // case MediaPlayer.PausedState:
console.log("Video playback paused") // console.log("Video playback paused")
break; // break;
case MediaPlayer.StoppedState: // case MediaPlayer.StoppedState:
console.log("Video playback stopped") // console.log("Video playback stopped")
break; // break;
} // }
} // }
Component.onCompleted: Component.onCompleted:
{ {
videoComponent.loaded = true videoComponent.loaded = true
delayedStartTimer.start()
autoStart()
} }
function autoStart() function autoStart()
@@ -353,14 +335,6 @@ Item
} }
} }
Timer
{
id: delayedStartTimer
interval: 500
repeat: false
onTriggered: mediaPlayer.autoStart()
}
function start() { mediaPlayer.play() } function start() { mediaPlayer.play() }
function stop() { mediaPlayer.stop() } function stop() { mediaPlayer.stop() }
function seek(position) { mediaPlayer.setPosition(position); } function seek(position) { mediaPlayer.setPosition(position); }
@@ -382,134 +356,172 @@ Item
ShaderEffectSource ShaderEffectSource
{ {
id: channelSource0 id: channelSource0
sourceItem: channel.iChannel0 ? channel.iChannel0 : null live: false
live: Qt.binding(() => { return isLive(); })
smooth: true smooth: true
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0) recursive: false
wrapMode: Qt.binding(() => {
if(channel.iChannel0 === undefined || channel.iChannel0.type === ShaderChannel.Audio)
return ShaderEffectSource.ClampToEdge;
else
return ShaderEffectSource.Repeat;
})
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
textureMirroring: ShaderEffectSource.NoMirroring
recursive: true
mipmap: true
hideSource: true hideSource: true
width: channel.iResolution.x width: channel.iResolution.x
height: channel.iResolution.y height: channel.iResolution.y
visible: false visible: false
format: ShaderEffectSource.RGBA8
samples: 1
function isLive() format: channel.iChannel0 ? channel.iChannel0.format : ShaderEffectSource.RGB8A
sourceItem: channel.iChannel0 ? channel.iChannel0 : null
textureMirroring: channel.iChannel0 ? channel.iChannel0.textureMirroring : ShaderEffectSource.NoMirroring
wrapMode: channel.iChannel0 ? channel.iChannel0.wrapMode : ShaderEffectSource.Repeat
mipmap: channel.iChannel0 ? channel.iChannel0.mipmap : true
samples: channel.iChannel0 ? channel.iChannel0.samples : 1
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
Connections
{ {
if(channel.iChannel0 === undefined) target: channel.iChannel0
return false; function onTypeChanged()
{
if(channel.iChannel0.type === ShaderChannel.AudioChannel)
{
//channelSource0.wrapMode = ShaderEffectSource.ClampToEdge
channelSource0.live = true
}
else
{
//channelSource0.wrapMode = ShaderEffectSource.Repeat
channelSource0.live = false
}
return channel.iChannel0.type != ShaderChannel.VideoChannel && channel.active; // if(!channelSource0.live)
// channelSource0.scheduleUpdate()
}
} }
} }
ShaderEffectSource ShaderEffectSource
{ {
id: channelSource1 id: channelSource1
sourceItem: channel.iChannel1 ? channel.iChannel1 : null live: false
live: Qt.binding(() => { return isLive(); })
smooth: false smooth: false
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0) recursive: false
wrapMode: Qt.binding(() => {
if(channel.iChannel1 === undefined || channel.iChannel1.type === ShaderChannel.Audio)
return ShaderEffectSource.ClampToEdge;
else
return ShaderEffectSource.Repeat;
})
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
textureMirroring: ShaderEffectSource.NoMirroring
recursive: true
mipmap: true
hideSource: true hideSource: true
width: channel.iResolution.x width: channel.iResolution.x
height: channel.iResolution.y height: channel.iResolution.y
visible: false visible: false
format: ShaderEffectSource.RGBA8
samples: 1
function isLive() format: channel.iChannel1 ? channel.iChannel1.format : ShaderEffectSource.RGB8A
sourceItem: channel.iChannel1 ? channel.iChannel1 : null
textureMirroring: channel.iChannel1 ? channel.iChannel1.textureMirroring : ShaderEffectSource.NoMirroring
wrapMode: channel.iChannel1 ? channel.iChannel1.wrapMode : ShaderEffectSource.Repeat
mipmap: channel.iChannel1 ? channel.iChannel1.mipmap : true
samples: channel.iChannel1 ? channel.iChannel1.samples : 1
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
Connections
{ {
return true; target: channel.iChannel1
function onTypeChanged()
{
if(channel.iChannel1.type === ShaderChannel.AudioChannel)
{
//channelSource1.wrapMode = ShaderEffectSource.ClampToEdge
channelSource1.live = true
}
else
{
//channelSource1.wrapMode = ShaderEffectSource.Repeat
channelSource1.live = false
}
if(channel.iChannel1 === undefined) // if(!channelSource1.live)
return false; // channelSource1.scheduleUpdate()
}
return channel.iChannel1.type != ShaderChannel.VideoChannel && channel.active;
} }
} }
ShaderEffectSource ShaderEffectSource
{ {
id: channelSource2 id: channelSource2
sourceItem: channel.iChannel2 ? channel.iChannel2 : null live: false
live: Qt.binding(() => { return isLive(); })
smooth: false smooth: false
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
wrapMode: Qt.binding(() => {
if(channel.iChannel2 === undefined || channel.iChannel2.type === ShaderChannel.Audio)
return ShaderEffectSource.ClampToEdge;
else
return ShaderEffectSource.Repeat;
})
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
textureMirroring: ShaderEffectSource.NoMirroring
recursive: true recursive: true
mipmap: true
hideSource: true hideSource: true
width: channel.iResolution.x width: channel.iResolution.x
height: channel.iResolution.y height: channel.iResolution.y
visible: false visible: false
format: ShaderEffectSource.RGBA8
samples: 1
function isLive() format: channel.iChannel2 ? channel.iChannel2.format : ShaderEffectSource.RGB8A
sourceItem: channel.iChannel2 ? channel.iChannel2 : null
textureMirroring: channel.iChannel2 ? channel.iChannel2.textureMirroring : ShaderEffectSource.NoMirroring
wrapMode: channel.iChannel2 ? channel.iChannel2.wrapMode : ShaderEffectSource.Repeat
mipmap: channel.iChannel2 ? channel.iChannel2.mipmap : true
samples: channel.iChannel2 ? channel.iChannel2.samples : 1
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
Connections
{ {
if(channel.iChannel2 === undefined) target: channel.iChannel2
return false; function onTypeChanged()
{
if(channel.iChannel2.type === ShaderChannel.AudioChannel)
{
//channelSource2.wrapMode = ShaderEffectSource.ClampToEdge
channelSource2.live = true
}
else
{
//channelSource2.wrapMode = ShaderEffectSource.Repeat
channelSource2.live = false
}
return channel.iChannel2.type != ShaderChannel.VideoChannel && channel.active; // if(!channelSource2.live)
// channelSource2.scheduleUpdate()
}
} }
} }
ShaderEffectSource ShaderEffectSource
{ {
id: channelSource3 id: channelSource3
sourceItem: channel.iChannel3 ? channel.iChannel3 : null live: false
live: Qt.binding(() => { return isLive(); })
smooth: false smooth: false
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
wrapMode: Qt.binding(() => {
if(channel.iChannel1 === undefined || channel.iChannel1.type === ShaderChannel.Audio)
return ShaderEffectSource.ClampToEdge;
else
return ShaderEffectSource.Repeat;
})
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
textureMirroring: ShaderEffectSource.NoMirroring
recursive: true recursive: true
mipmap: true
hideSource: true hideSource: true
width: channel.iResolution.x width: channel.iResolution.x
height: channel.iResolution.y height: channel.iResolution.y
visible: false visible: false
format: ShaderEffectSource.RGBA8
samples: 1
function isLive() format: channel.iChannel3 ? channel.iChannel1.format : ShaderEffectSource.RGB8A
sourceItem: channel.iChannel3 ? channel.iChannel3 : null
textureMirroring: channel.iChannel3 ? channel.iChannel3.textureMirroring : ShaderEffectSource.NoMirroring
wrapMode: channel.iChannel3 ? channel.iChannel3.wrapMode : ShaderEffectSource.Repeat
mipmap: channel.iChannel3 ? channel.iChannel3.mipmap : true
samples: channel.iChannel3 ? channel.iChannel3.samples : 1
sourceRect: sourceItem ? Qt.rect(0,0, sourceItem.width, sourceItem.height) : Qt.rect(0,0,0,0)
textureSize: Qt.size(channel.iResolution.x, channel.iResolution.y)
Connections
{ {
if(channel.iChannel3 === undefined) target: channel.iChannel3
return false; function onTypeChanged()
{
if(channel.iChannel3.type === ShaderChannel.AudioChannel)
{
//channelSource3.wrapMode = ShaderEffectSource.ClampToEdge
channelSource3.live = true
}
else
{
//channelSource3.wrapMode = ShaderEffectSource.Repeat
channelSource3.live = false
}
return channel.iChannel3.type != ShaderChannel.VideoChannel && channel.active; if(!channelSource3.live)
channelSource3.scheduleUpdate()
}
} }
} }
@@ -517,19 +529,19 @@ Item
ShaderEffectSource ShaderEffectSource
{ {
id: frameBufferSource id: frameBufferSource
sourceItem: channel.frameBufferChannel === -1 ? null : channelShaderContent sourceItem: channel.frameBufferChannel === -1 ? null : channelShaderOutput
sourceRect: Qt.rect(0,0, channelShaderContent.width, channelShaderContent.height) sourceRect: Qt.rect(0,0, channelShaderOutput.width, channelShaderOutput.height)
wrapMode: ShaderEffectSource.Repeat wrapMode: ShaderEffectSource.ClampToEdge
live: channel.active live: false
mipmap: true mipmap: true
recursive: true recursive: true
textureSize: Qt.size(channelShaderContent.width, channelShaderContent.height) textureSize: Qt.size(channelShaderOutput.width, channelShaderOutput.height)
visible: false visible: false
textureMirroring: ShaderEffectSource.NoMirroring textureMirroring: ShaderEffectSource.NoMirroring
width: channel.iResolution.x width: channel.iResolution.x
height: channel.iResolution.y height: channel.iResolution.y
format: ShaderEffectSource.RGBA8 format: ShaderEffectSource.RGB8A
samples: 1 samples: 2
} }
// The shader effect that will be used to render the shader // The shader effect that will be used to render the shader
@@ -560,6 +572,29 @@ Item
blending: true blending: true
} }
Connections
{
target: channel
function onIFrameChanged()
{
// skip first frame. frame 0 is a blank screen
if(channel.frameBufferChannel > -1 )//&& channel.iFrame > 1)
frameBufferSource.scheduleUpdate()
if(channel.iChannel0 !== undefined && !channelSource0.live)
channelSource0.scheduleUpdate()
if(channel.iChannel1 !== undefined && !channelSource1.live)
channelSource1.scheduleUpdate()
if(channel.iChannel2 !== undefined && !channelSource2.live)
channelSource2.scheduleUpdate()
if(channel.iChannel3 !== undefined && !channelSource3.live)
channelSource3.scheduleUpdate()
}
}
} }
} }