zworld/engine/render/graph/pre_node.go
2024-01-14 22:56:06 +08:00

101 lines
2.3 KiB
Go

package graph
import (
"errors"
"github.com/vkngwrapper/core/v2/core1_0"
"zworld/engine/object"
"zworld/engine/object/camera"
"zworld/engine/renderapi"
"zworld/engine/renderapi/color"
"zworld/engine/renderapi/command"
"zworld/engine/renderapi/swapchain"
"zworld/engine/renderapi/vulkan"
"zworld/plugins/math/mat4"
)
var ErrRecreate = errors.New("recreate renderer")
type PreDrawable interface {
object.Component
PreDraw(renderapi.Args, object.Object) error
}
type preNode struct {
*node
target vulkan.Target
cameraQuery *object.Query[*camera.Camera]
predrawQuery *object.Query[PreDrawable]
}
func newPreNode(app vulkan.App, target vulkan.Target) *preNode {
return &preNode{
node: newNode(app, "Pre", nil),
target: target,
cameraQuery: object.NewQuery[*camera.Camera](),
predrawQuery: object.NewQuery[PreDrawable](),
}
}
func (n *preNode) Prepare(scene object.Object, time, delta float32) (*renderapi.Args, *swapchain.Context, error) {
screen := renderapi.Screen{
Width: n.target.Width(),
Height: n.target.Height(),
Scale: n.target.Scale(),
}
// aquire next frame
context, err := n.target.Aquire()
if err != nil {
return nil, nil, ErrRecreate
}
// ensure the default white texture is always available
n.app.Textures().Fetch(color.White)
// cache ticks
n.app.Meshes().Tick()
n.app.Textures().Tick()
// create render arguments
args := renderapi.Args{}
// find the first active camera
if camera, exists := n.cameraQuery.Reset().First(scene); exists {
args = camera.RenderArgs(screen)
} else {
args.Viewport = screen
}
// fill in time & swapchain context
args.Frame = context.Index
args.Time = time
args.Delta = delta
args.Transform = mat4.Ident()
// execute pre-draw pass
objects := n.predrawQuery.Reset().Collect(scene)
for _, object := range objects {
object.PreDraw(args.Apply(object.Transform().Matrix()), scene)
}
// fire off render start signals
var waits []command.Wait
if context.ImageAvailable != nil {
waits = []command.Wait{
{
Semaphore: context.ImageAvailable,
Mask: core1_0.PipelineStageColorAttachmentOutput,
},
}
}
worker := n.app.Worker(context.Index)
worker.Submit(command.SubmitInfo{
Marker: n.Name(),
Wait: waits,
Signal: n.signals(context.Index),
})
return &args, context, nil
}