101 lines
2.3 KiB
Go
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
|
||
|
|
}
|