func (r *Renderer) useState(obj *gfx.Object, c *gfx.Camera) { // Use object state. r.stateColorWrite(obj.WriteRed, obj.WriteGreen, obj.WriteBlue, obj.WriteAlpha) r.stateDithering(obj.Dithering) r.stateStencilTest(obj.StencilTest) r.stateStencilOp(obj.StencilFront, obj.StencilBack) r.stateStencilFunc(obj.StencilFront, obj.StencilBack) r.stateStencilMask(obj.StencilFront.WriteMask, obj.StencilBack.WriteMask) r.stateDepthFunc(obj.DepthCmp) r.stateDepthTest(obj.DepthTest) r.stateDepthWrite(obj.DepthWrite) r.stateFaceCulling(obj.FaceCulling) // Consider rebuilding the object's cached matrices, if needed. nativeObj := obj.NativeObject.(nativeObject) if nativeObj.needRebuild(obj, c) { // Rebuild cached matrices. nativeObj = nativeObj.rebuild(obj, c) } obj.NativeObject = nativeObj // Set alpha mode. r.stateAlphaToCoverage(obj.AlphaMode == gfx.AlphaToCoverage) r.stateBlend(obj.AlphaMode == gfx.AlphaBlend) if obj.AlphaMode == gfx.AlphaBlend { r.stateBlendColor(obj.Blend.Color) r.stateBlendFuncSeparate(obj.Blend) r.stateBlendEquationSeparate(obj.Blend) } // Begin occlusion query. obj.NativeObject = r.beginQuery(obj, nativeObj) }
func (r *Renderer) clearState(obj *gfx.Object) { // End occlusion query. obj.NativeObject = r.endQuery(obj, obj.NativeObject.(nativeObject)) // Use no texture. r.render.BindTexture(gl.TEXTURE_2D, 0) r.render.ActiveTexture(gl.TEXTURE0) }
// 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 } }