// Implements gfx.Renderer interface. func (r *Renderer) Draw(rect image.Rectangle, o *gfx.Object, c *gfx.Camera) { if o == nil { // Can't draw. return } lock := func() { o.Lock() if c != nil { c.Lock() } } unlock := func() { o.Unlock() if c != nil { c.Unlock() } } // Lock the object until we are completely done drawing it. lock() var ( shaderLoaded chan *gfx.Shader meshesLoaded []chan *gfx.Mesh texturesLoaded []chan *gfx.Texture ) // Begin loading shaders. for _, shader := range o.Shaders { if shader == nil { // Can't draw. unlock() return } shader.RLock() shaderNeedLoad := !shader.Loaded shaderCantDraw := !shader.CanDraw() shader.RUnlock() if shaderCantDraw { // Can't draw. unlock() return } if shaderNeedLoad { shaderLoaded = make(chan *gfx.Shader, 1) r.LoadShader(shader, shaderLoaded) } } for _, m := range o.Meshes { if m == nil { // Can't draw. unlock() return } m.RLock() meshNeedLoad := !m.Loaded || m.HasChanged() meshCantDraw := !m.CanDraw() m.RUnlock() if meshCantDraw { // Can't draw. unlock() return } if meshNeedLoad { ch := make(chan *gfx.Mesh, 1) r.LoadMesh(m, ch) meshesLoaded = append(meshesLoaded, ch) } } // Begin loading textures. for _, texSet := range o.Textures { for _, tex := range texSet { if tex == nil { // Can't draw. unlock() return } tex.RLock() texNeedLoad := !tex.Loaded texCantDraw := !tex.CanDraw() tex.RUnlock() if texCantDraw { // Can't draw. unlock() return } if texNeedLoad { ch := make(chan *gfx.Texture, 1) r.LoadTexture(tex, ch) texturesLoaded = append(texturesLoaded, ch) } } } // Wait for shader, meshes, and textures to finish loading. if shaderLoaded != nil { <-shaderLoaded } for _, load := range meshesLoaded { <-load } for _, load := range texturesLoaded { <-load } // Check if the now-loaded shaders might have errors. for _, shader := range o.Shaders { shader.RLock() shaderCantDraw := !shader.CanDraw() shader.RUnlock() if shaderCantDraw { // Can't draw. unlock() return } } // Must set at least an empty native object before Draw() returns. o.NativeObject = nativeObject{} // Ask the render loop to perform drawing. r.RenderExec <- func() bool { // Set global GL state. r.setGlobalState() // Update the scissor region (effects drawing). r.stateScissor(rect) // Use the object's state. r.useState(o, c) for meshIndex, mesh := range o.Meshes { shader := o.Shaders[meshIndex] var ns *nativeShader if shader.NativeShader != nil { ns = shader.NativeShader.(*nativeShader) } // Use the shader. r.useShader(ns, meshIndex, o) // Draw the mesh. r.drawMesh(ns, mesh) } // Clear the object's state. r.clearState(o) // Unlock the object now that we are done drawing it. unlock() // Yield for occlusion query results, if any are available. r.queryYield() return false } }