コード例 #1
0
ファイル: draw.go プロジェクト: pombredanne/rand
// 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
	}
}