fix
This commit is contained in:
148
compositor.cm
148
compositor.cm
@@ -25,21 +25,53 @@ compositor.compile = function(config) {
|
||||
if (config.clear)
|
||||
ctx.passes.push({type: 'clear', target: 'screen', color: config.clear})
|
||||
|
||||
// Process each layer
|
||||
var layers = config.layers || []
|
||||
for (var i = 0; i < layers.length; i++)
|
||||
compile_layer(layers[i], ctx, group_effects)
|
||||
// Process each plane (supports both 'planes' and legacy 'layers' key)
|
||||
var planes = config.planes || config.layers || []
|
||||
for (var i = 0; i < planes.length; i++) {
|
||||
var plane = planes[i]
|
||||
var type = plane.type || 'film2d'
|
||||
if (type == 'imgui') {
|
||||
compile_imgui_layer(plane, ctx)
|
||||
} else {
|
||||
compile_plane(plane, ctx, group_effects)
|
||||
}
|
||||
}
|
||||
|
||||
return {passes: ctx.passes, targets: ctx.targets, screen_size: ctx.screen_size}
|
||||
}
|
||||
|
||||
function compile_layer(layer, ctx, group_effects) {
|
||||
var group = layer.group
|
||||
var res = layer.resolution || ctx.screen_size
|
||||
var camera = layer.camera
|
||||
function compile_imgui_layer(layer, ctx) {
|
||||
ctx.passes.push({
|
||||
type: 'imgui',
|
||||
target: 'screen',
|
||||
draw: layer.draw
|
||||
})
|
||||
}
|
||||
|
||||
function compile_plane(plane_config, ctx, group_effects) {
|
||||
var plane_name = plane_config.plane || plane_config.name
|
||||
var res = plane_config.resolution || ctx.screen_size
|
||||
var camera = plane_config.camera
|
||||
var layer_sort = plane_config.layer_sort || {} // layer -> 'y' or 'explicit'
|
||||
|
||||
// Get all sprites in this group
|
||||
var all_sprites = film2d.query({group: group})
|
||||
// Build set of groups used as masks (these should not be drawn directly)
|
||||
var mask_groups = {}
|
||||
for (var gname in group_effects) {
|
||||
var effects = group_effects[gname].effects || []
|
||||
for (var e = 0; e < effects.length; e++) {
|
||||
if (effects[e].type == 'mask' && effects[e].mask_group)
|
||||
mask_groups[effects[e].mask_group] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Get all sprites in this plane
|
||||
var all_sprites = film2d.query({plane: plane_name})
|
||||
|
||||
// Add manual drawables
|
||||
if (plane_config.drawables) {
|
||||
for (var i = 0; i < plane_config.drawables.length; i++)
|
||||
all_sprites.push(plane_config.drawables[i])
|
||||
}
|
||||
|
||||
// Find which sprites belong to groups with effects
|
||||
var effect_groups = {} // group_name -> {sprites: [], effects: []}
|
||||
@@ -47,10 +79,20 @@ function compile_layer(layer, ctx, group_effects) {
|
||||
|
||||
for (var i = 0; i < all_sprites.length; i++) {
|
||||
var s = all_sprites[i]
|
||||
var assigned = false
|
||||
|
||||
// Check if sprite belongs to any effect group
|
||||
var sprite_groups = s.groups || []
|
||||
var assigned = false
|
||||
var is_mask_only = sprite_groups.length > 0
|
||||
|
||||
// First pass: check if sprite has any non-mask group
|
||||
for (var g = 0; g < sprite_groups.length; g++) {
|
||||
var gname = sprite_groups[g]
|
||||
if (!mask_groups[gname]) {
|
||||
is_mask_only = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: assign to effect groups
|
||||
for (var g = 0; g < sprite_groups.length; g++) {
|
||||
var gname = sprite_groups[g]
|
||||
if (group_effects[gname]) {
|
||||
@@ -62,15 +104,16 @@ function compile_layer(layer, ctx, group_effects) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!assigned) base_sprites.push(s)
|
||||
// Add to base sprites if not assigned to effect group and not mask-only
|
||||
if (!assigned && !is_mask_only) base_sprites.push(s)
|
||||
}
|
||||
|
||||
// Allocate layer target
|
||||
var layer_target = ctx.alloc(res.width, res.height, layer.name)
|
||||
// Allocate plane target
|
||||
var plane_target = ctx.alloc(res.width, res.height, plane_config.name)
|
||||
|
||||
// Clear layer
|
||||
if (layer.clear)
|
||||
ctx.passes.push({type: 'clear', target: layer_target, color: layer.clear})
|
||||
// Clear plane
|
||||
if (plane_config.clear)
|
||||
ctx.passes.push({type: 'clear', target: plane_target, color: plane_config.clear})
|
||||
|
||||
// Render each effect group to temp target, apply effects, composite back
|
||||
for (var gname in effect_groups) {
|
||||
@@ -87,6 +130,7 @@ function compile_layer(layer, ctx, group_effects) {
|
||||
camera: camera,
|
||||
target: group_target,
|
||||
target_size: res,
|
||||
layer_sort: layer_sort,
|
||||
clear: {r: 0, g: 0, b: 0, a: 0}
|
||||
})
|
||||
|
||||
@@ -94,14 +138,14 @@ function compile_layer(layer, ctx, group_effects) {
|
||||
var current = group_target
|
||||
for (var e = 0; e < eg.effects.length; e++) {
|
||||
var effect = eg.effects[e]
|
||||
current = apply_effect(effect, current, res, gname, group_effects)
|
||||
current = apply_effect(ctx, effect, current, res, camera, gname, plane_name, group_effects)
|
||||
}
|
||||
|
||||
// Composite result to layer
|
||||
// Composite result to plane
|
||||
ctx.passes.push({
|
||||
type: 'composite',
|
||||
source: current,
|
||||
dest: layer_target,
|
||||
dest: plane_target,
|
||||
source_size: res,
|
||||
dest_size: res,
|
||||
blend: 'over'
|
||||
@@ -115,32 +159,33 @@ function compile_layer(layer, ctx, group_effects) {
|
||||
renderer: 'film2d',
|
||||
drawables: base_sprites,
|
||||
camera: camera,
|
||||
target: layer_target,
|
||||
target: plane_target,
|
||||
target_size: res,
|
||||
layer_sort: layer_sort,
|
||||
clear: null // Don't clear, blend on top
|
||||
})
|
||||
}
|
||||
|
||||
// Composite layer to screen
|
||||
// Composite plane to screen
|
||||
ctx.passes.push({
|
||||
type: 'blit_to_screen',
|
||||
source: layer_target,
|
||||
source: plane_target,
|
||||
source_size: res,
|
||||
dest_size: ctx.screen_size,
|
||||
presentation: layer.presentation || 'stretch'
|
||||
presentation: plane_config.presentation || 'stretch'
|
||||
})
|
||||
}
|
||||
|
||||
function apply_effect(effect, input, size, hint, group_effects) {
|
||||
var output = alloc(size.width, size.height, hint + '_' + effect.type)
|
||||
function apply_effect(ctx, effect, input, size, camera, hint, current_plane, group_effects) {
|
||||
var output = ctx.alloc(size.width, size.height, hint + '_' + effect.type)
|
||||
|
||||
if (effect.type == 'bloom') {
|
||||
var bright = alloc(size.width, size.height, hint + '_bright')
|
||||
var blur1 = alloc(size.width, size.height, hint + '_blur1')
|
||||
var blur2 = alloc(size.width, size.height, hint + '_blur2')
|
||||
var bright = ctx.alloc(size.width, size.height, hint + '_bright')
|
||||
var blur1 = ctx.alloc(size.width, size.height, hint + '_blur1')
|
||||
var blur2 = ctx.alloc(size.width, size.height, hint + '_blur2')
|
||||
|
||||
// Threshold
|
||||
passes.push({
|
||||
ctx.passes.push({
|
||||
type: 'shader_pass',
|
||||
shader: 'threshold',
|
||||
input: input,
|
||||
@@ -152,34 +197,35 @@ function apply_effect(effect, input, size, hint, group_effects) {
|
||||
var blur_passes = effect.blur_passes || 2
|
||||
var blur_in = bright
|
||||
for (var p = 0; p < blur_passes; p++) {
|
||||
passes.push({type: 'shader_pass', shader: 'blur', input: blur_in, output: blur1, uniforms: {direction: {x: 1, y: 0}, texel_size: {x: 1/size.width, y: 1/size.height}}})
|
||||
passes.push({type: 'shader_pass', shader: 'blur', input: blur1, output: blur2, uniforms: {direction: {x: 0, y: 1}, texel_size: {x: 1/size.width, y: 1/size.height}}})
|
||||
ctx.passes.push({type: 'shader_pass', shader: 'blur', input: blur_in, output: blur1, uniforms: {direction: {x: 1, y: 0}, texel_size: {x: 1/size.width, y: 1/size.height}}})
|
||||
ctx.passes.push({type: 'shader_pass', shader: 'blur', input: blur1, output: blur2, uniforms: {direction: {x: 0, y: 1}, texel_size: {x: 1/size.width, y: 1/size.height}}})
|
||||
blur_in = blur2
|
||||
}
|
||||
|
||||
// Composite bloom
|
||||
passes.push({type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'})
|
||||
ctx.passes.push({type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'})
|
||||
|
||||
} else if (effect.type == 'mask') {
|
||||
var mask_group = effect.mask_group
|
||||
var mask_sprites = film2d.query({group: mask_group})
|
||||
// Query masks within the same plane to avoid cross-plane mask issues
|
||||
var mask_sprites = film2d.query({group: mask_group, plane: current_plane})
|
||||
|
||||
if (mask_sprites.length > 0) {
|
||||
var mask_target = alloc(size.width, size.height, hint + '_mask')
|
||||
var mask_target = ctx.alloc(size.width, size.height, hint + '_mask')
|
||||
|
||||
// Render mask
|
||||
passes.push({
|
||||
ctx.passes.push({
|
||||
type: 'render',
|
||||
renderer: 'film2d',
|
||||
drawables: mask_sprites,
|
||||
camera: null, // Same camera as parent? Need to pass this
|
||||
camera: camera,
|
||||
target: mask_target,
|
||||
target_size: size,
|
||||
clear: {r: 0, g: 0, b: 0, a: 0}
|
||||
})
|
||||
|
||||
// Apply mask
|
||||
passes.push({
|
||||
ctx.passes.push({
|
||||
type: 'apply_mask',
|
||||
content: input,
|
||||
mask: mask_target,
|
||||
@@ -189,11 +235,11 @@ function apply_effect(effect, input, size, hint, group_effects) {
|
||||
})
|
||||
} else {
|
||||
// No mask sprites, pass through
|
||||
passes.push({type: 'blit', source: input, dest: output})
|
||||
ctx.passes.push({type: 'blit', source: input, dest: output})
|
||||
}
|
||||
} else {
|
||||
// Unknown effect, pass through
|
||||
passes.push({type: 'blit', source: input, dest: output})
|
||||
ctx.passes.push({type: 'blit', source: input, dest: output})
|
||||
}
|
||||
|
||||
return output
|
||||
@@ -230,6 +276,7 @@ compositor.execute = function(plan) {
|
||||
camera: pass.camera,
|
||||
target: resolve(pass.target),
|
||||
target_size: pass.target_size,
|
||||
layer_sort: pass.layer_sort || {},
|
||||
clear: pass.clear
|
||||
}, backend)
|
||||
for (var c = 0; c < result.commands.length; c++)
|
||||
@@ -280,10 +327,25 @@ compositor.execute = function(plan) {
|
||||
dst_rect: rect,
|
||||
filter: pass.presentation == 'integer_scale' ? 'nearest' : 'linear'
|
||||
})
|
||||
} else if (pass.type == 'blit') {
|
||||
var src = resolve(pass.source)
|
||||
var dst = resolve(pass.dest)
|
||||
commands.push({
|
||||
cmd: 'blit',
|
||||
texture: src,
|
||||
target: dst,
|
||||
dst_rect: {x: 0, y: 0, width: dst.width, height: dst.height}
|
||||
})
|
||||
} else if (pass.type == 'imgui') {
|
||||
commands.push({
|
||||
cmd: 'imgui',
|
||||
target: resolve(pass.target),
|
||||
draw: pass.draw
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {commands: commands}
|
||||
return {commands: commands, plan: plan}
|
||||
}
|
||||
|
||||
function _calc_presentation(src, dst, mode) {
|
||||
|
||||
Reference in New Issue
Block a user