瀏覽代碼

gui renderer dev...

leonsal 8 年之前
父節點
當前提交
039b084143
共有 2 個文件被更改,包括 126 次插入79 次删除
  1. 3 6
      gui/panel.go
  2. 123 73
      renderer/renderer.go

+ 3 - 6
gui/panel.go

@@ -576,16 +576,13 @@ func (p *Panel) Intersects(other *Panel) bool {
 	if p.ContainsPosition(pospix.X, pospix.Y) {
 		return true
 	}
-	if p.ContainsPosition(pospix.X+other.width, pospix.Y) {
+	if p.ContainsPosition(pospix.X+other.width-1, pospix.Y) {
 		return true
 	}
-	if p.ContainsPosition(pospix.X+other.width, pospix.Y) {
+	if p.ContainsPosition(pospix.X, pospix.Y+other.height-1) {
 		return true
 	}
-	if p.ContainsPosition(pospix.X, pospix.Y+other.height) {
-		return true
-	}
-	if p.ContainsPosition(pospix.X+other.width, pospix.Y+other.height) {
+	if p.ContainsPosition(pospix.X+other.width-1, pospix.Y+other.height-1) {
 		return true
 	}
 	return false

+ 123 - 73
renderer/renderer.go

@@ -16,21 +16,23 @@ import (
 // Renderer renders a 3D scene and or a 2D GUI over the 3D scene
 // on the current window.
 type Renderer struct {
-	gs            *gls.GLS
-	shaman        Shaman                     // Internal shader manager
-	scene         core.INode                 // Node containing 3D scene to render
-	gui           gui.IPanel                 // Panel containing GUI to render
-	panel3D       gui.IPanel                 // Panel which contains the 3D scene
-	ambLights     []*light.Ambient           // Array of ambient lights for last scene
-	dirLights     []*light.Directional       // Array of directional lights for last scene
-	pointLights   []*light.Point             // Array of point
-	spotLights    []*light.Spot              // Array of spot lights for the scene
-	others        []core.INode               // Other nodes (audio, players, etc)
-	grmats        []*graphic.GraphicMaterial // Array of all graphic materials for scene
-	rinfo         core.RenderInfo            // Preallocated Render info
-	specs         ShaderSpecs                // Preallocated Shader specs
-	screenCleared bool
-	needSwap      bool
+	gs          *gls.GLS
+	shaman      Shaman                     // Internal shader manager
+	scene       core.INode                 // Node containing 3D scene to render
+	panelGui    gui.IPanel                 // Panel containing GUI to render
+	panel3D     gui.IPanel                 // Panel which contains the 3D scene
+	ambLights   []*light.Ambient           // Array of ambient lights for last scene
+	dirLights   []*light.Directional       // Array of directional lights for last scene
+	pointLights []*light.Point             // Array of point
+	spotLights  []*light.Spot              // Array of spot lights for the scene
+	others      []core.INode               // Other nodes (audio, players, etc)
+	grmats      []*graphic.GraphicMaterial // Array of all graphic materials for scene
+	rinfo       core.RenderInfo            // Preallocated Render info
+	specs       ShaderSpecs                // Preallocated Shader specs
+	redrawGui   bool
+	needSwap    bool
+	panList     []gui.IPanel
+	panRendered int
 }
 
 // NewRenderer creates and returns a pointer to a new Renderer
@@ -46,7 +48,7 @@ func NewRenderer(gs *gls.GLS) *Renderer {
 	r.spotLights = make([]*light.Spot, 0)
 	r.others = make([]core.INode, 0)
 	r.grmats = make([]*graphic.GraphicMaterial, 0)
-
+	r.panList = make([]gui.IPanel, 0)
 	return r
 }
 
@@ -75,10 +77,13 @@ func (r *Renderer) AddProgram(name, vertex, frag string, others ...string) {
 // If set to nil, no Gui will be rendered
 func (r *Renderer) SetGui(gui gui.IPanel) {
 
-	r.gui = gui
+	r.panelGui = gui
 }
 
 // SetGuiPanel3D sets the gui panel inside which the 3D scene is shown.
+// This informs the renderer that the Gui elements over this panel
+// must be redrawn even if they didn't change.
+// This panel panel must not be renderable, otherwise it will cover the 3D scene.
 func (r *Renderer) SetGuiPanel3D(panel3D gui.IPanel) {
 
 	r.panel3D = panel3D
@@ -99,7 +104,7 @@ func (r *Renderer) NeedSwap() bool {
 // Render renders the previously set Scene and Gui using the specified camera
 func (r *Renderer) Render(icam camera.ICamera) error {
 
-	r.screenCleared = false
+	r.redrawGui = false
 	r.needSwap = false
 
 	// Renders the 3D scene
@@ -110,7 +115,7 @@ func (r *Renderer) Render(icam camera.ICamera) error {
 		}
 	}
 	// Renders the Gui over the 3D scene
-	if r.gui != nil {
+	if r.panelGui != nil {
 		err := r.renderGui(icam)
 		if err != nil {
 			return err
@@ -208,6 +213,9 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 	// If there is graphic material to render
 	if len(r.grmats) > 0 {
+		log.Error("graphics:%v", len(r.grmats))
+		// If the 3D scene to draw is to be confined to user specified panel
+		// sets scissor to avoid erasing gui elements outside of this panel
 		if r.panel3D != nil {
 			pos := r.panel3D.GetPanel().Pospix()
 			width, height := r.panel3D.GetPanel().Size()
@@ -216,7 +224,7 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 			r.gs.Scissor(int32(pos.X), viewheight-int32(pos.Y)-int32(height), uint32(width), uint32(height))
 		} else {
 			r.gs.Disable(gls.SCISSOR_TEST)
-			r.screenCleared = true
+			r.redrawGui = true
 		}
 		// Clears the area inside the current scissor
 		r.gs.Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT)
@@ -225,7 +233,6 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 	// For each *GraphicMaterial
 	for _, grmat := range r.grmats {
-		//log.Debug("grmat:%v", grmat)
 		mat := grmat.GetMaterial().GetMaterial()
 
 		// Sets the shader specs for this material and sets shader program
@@ -262,104 +269,145 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 func (r *Renderer) renderGui(icam camera.ICamera) error {
 
 	// Updates panels bounds and relative positions
-	parent := r.gui.GetPanel()
+	parent := r.panelGui.GetPanel()
 	parent.UpdateMatrixWorld()
 
-	// Builds list of panel's graphic materials to render
-	// If all the screen has been cleared by the 3D scene,
-	// no need to check panels.  All must be redrawn.
-	r.grmats = r.grmats[0:0]
-	checkChanged := !r.screenCleared
-	r.buildPanelList(parent, checkChanged)
+	// Clears list of panels to render
+	r.panList = r.panList[0:0]
+	r.panRendered = 0
+	// Redraw all GUI elements if necessary by appending the GUI panel to the render list
+	if r.redrawGui || r.checkPanelUnbounded(r.panelGui) {
+		r.panList = append(r.panList, r.panelGui)
+	} else {
+		r.buildPanelList(r.panelGui, true)
+	}
 
 	// If there are panels to render, disable the scissor test
 	// which could have been set by the 3D scene renderer and
 	// then clear the depth buffer, so the panels will be rendered
 	// over the 3D scene.
-	if len(r.grmats) > 0 {
-		log.Error("render list:%v", len(r.grmats))
+	if len(r.panList) > 0 {
 		r.gs.Disable(gls.SCISSOR_TEST)
 		r.gs.Clear(gls.DEPTH_BUFFER_BIT)
 		r.needSwap = true
 	}
 
-	// For each *GraphicMaterial
-	for _, grmat := range r.grmats {
-		// Sets shader program for this material
-		mat := grmat.GetMaterial().GetMaterial()
-		r.specs.Name = mat.Shader()
-		r.specs.ShaderUnique = mat.ShaderUnique()
-		_, err := r.shaman.SetProgram(&r.specs)
+	// Render panels
+	for i := 0; i < len(r.panList); i++ {
+		err := r.renderPanel(r.panList[i])
 		if err != nil {
 			return err
 		}
-		// Render this graphic material
-		grmat.Render(r.gs, &r.rinfo)
+	}
+	if r.panRendered > 0 {
+		log.Error("panels rendered:%v", r.panRendered)
 	}
 	return nil
 }
 
 // buildPanelList builds list of panel materials that must be rendered.
-// If checkChanged is false the specified panel and all its children
-// recursively  will be appended to the list inconditionally.
-// Otherwise the following criteria is used:
-// - If the panel is changed, itself and all its children recursively
-//   are appended to list
-// - If any the panel immediate children is changed the panel itself
-//   and the immediate children are appended to the list
-func (r *Renderer) buildPanelList(ipan gui.IPanel, checkChanged bool) {
+func (r *Renderer) buildPanelList(ipan gui.IPanel, check3D bool) {
 
+	// If panel is not visible, ignore it and all its children
 	pan := ipan.GetPanel()
-	// If panel is not visible, ignore
 	if !pan.Visible() {
 		return
 	}
-	// If no check or if any of this panel immediate children changed,
-	// inserts this panel if renderable and all its visible/renderable children
-	if !checkChanged || r.checkPanelOver3D(ipan) || r.checkPanelChildren(ipan) || r.checkPanelUnbounded(ipan) {
-		if pan.Renderable() {
-			materials := pan.GetGraphic().Materials()
-			r.grmats = append(r.grmats, &materials[0])
-		}
-		for _, ichild := range pan.Children() {
-			r.buildPanelList(ichild.(gui.IPanel), false)
+
+	// If this panel is not the main GUI panel checks if its over 3D.
+	// If it is appends to the render list and we are done.
+	// Otherwise do not check over 3D for its children because if the
+	// parent is not over 3D than the children are also not over 3D.
+	// The exception to this case is when the panel is unbounded,
+	// which is verified in the next check.
+	if ipan != r.panelGui {
+		if check3D && r.checkPanelOver3D(ipan) {
+			r.panList = append(r.panList, ipan)
+			return
+		} else {
+			check3D = false
 		}
-		pan.SetChanged(false)
+	}
+
+	// If panel is unbounded and is over 3D, appends to the render list
+	if !pan.Bounded() && r.checkPanelOver3D(ipan) {
+		r.panList = append(r.panList, ipan)
+		return
+	}
+	// If any of this panel immediate children changed, appends to the render list
+	if r.checkPanelChildren(ipan) {
+		r.panList = append(r.panList, ipan)
 		return
 	}
-	// If this panel is renderable and changed, inserts this panel
+	// If this panel is renderable and changed, appends to the render list
 	if pan.Renderable() && pan.Changed() {
-		materials := pan.GetGraphic().Materials()
-		r.grmats = append(r.grmats, &materials[0])
+		r.panList = append(r.panList, ipan)
+		log.Error("panel changed")
+		return
 	}
 	// Checks this panel children
 	for _, ichild := range pan.Children() {
-		r.buildPanelList(ichild.(gui.IPanel), true)
+		r.buildPanelList(ichild.(gui.IPanel), check3D)
+	}
+}
+
+// renderPanel renders the specified panel and all its children
+// and then sets the panel as not changed.
+func (r *Renderer) renderPanel(ipan gui.IPanel) error {
+
+	// If panel not visible, ignore it and all its children
+	pan := ipan.GetPanel()
+	if !pan.Visible() {
+		return nil
+	}
+	// If panel is renderable, renders it
+	if pan.Renderable() {
+		// Sets shader program for the panel's material
+		grmat := pan.GetGraphic().Materials()[0]
+		mat := grmat.GetMaterial().GetMaterial()
+		r.specs.Name = mat.Shader()
+		r.specs.ShaderUnique = mat.ShaderUnique()
+		_, err := r.shaman.SetProgram(&r.specs)
+		if err != nil {
+			return err
+		}
+		// Render this panel's graphic material
+		grmat.Render(r.gs, &r.rinfo)
+		pan.SetChanged(false)
+		r.panRendered++
+	}
+	// Renders this panel children
+	for i := 0; i < len(pan.Children()); i++ {
+		err := r.renderPanel(pan.Children()[i].(gui.IPanel))
+		if err != nil {
+			return err
+		}
 	}
-	pan.SetChanged(false)
+	return nil
 }
 
 // checkPanelOver3D checks if the specified panel is over
 // the area where the 3D scene will be rendered.
 func (r *Renderer) checkPanelOver3D(ipan gui.IPanel) bool {
 
-	if r.panel3D == nil {
+	if r.panel3D == nil || len(r.panel3D.GetPanel().Children()) == 0 {
 		return false
 	}
-	pan := r.gui.GetPanel()
-	if !pan.Visible() || !pan.Renderable() {
+	pan := ipan.GetPanel()
+	if !pan.Visible() {
 		return false
 	}
-	res := pan.Intersects(r.panel3D.GetPanel())
-	if res {
-		log.Error("panel over 3D:%v %v %v / %v %v %v", pan.Pospix(), pan.Width(), pan.Height(),
-			r.panel3D.GetPanel().Pospix(), r.panel3D.GetPanel().Width(), r.panel3D.GetPanel().Height())
+	if r.panel3D.GetPanel().Intersects(pan) {
+		log.Error("panel..: %v %v %v", pan.Pospix(), pan.Width(), pan.Height())
+		panel3D := r.panel3D.GetPanel()
+		log.Error("panel3D: %v %v %v", panel3D.Pospix(), panel3D.Width(), panel3D.Height())
+		return true
 	}
-	return res
+	return false
 }
 
-// checkPanelUnbounded checks if any of the specified panel children has
-// changed and it is not bounded
+// checkPanelUnbounded checks if the specified panel or any
+// of its children has changed and it is unbounded
 func (r *Renderer) checkPanelUnbounded(ipan gui.IPanel) bool {
 
 	pan := ipan.GetPanel()
@@ -367,6 +415,7 @@ func (r *Renderer) checkPanelUnbounded(ipan gui.IPanel) bool {
 		return false
 	}
 	if pan.Changed() && !pan.Bounded() {
+		log.Error("panel unbounded changed")
 		return true
 	}
 	for _, ichild := range pan.Children() {
@@ -387,6 +436,7 @@ func (r *Renderer) checkPanelChildren(ipan gui.IPanel) bool {
 			continue
 		}
 		if child.Changed() {
+			log.Error("panel children changed")
 			return true
 		}
 	}