func renderMenu(g *game.Game, fudge float32) { ease := func(start, change float32) float32 { return easeOutCubic(g.StateProgress(fudge), start, change) } alpha := float32(1) switch g.State { case game.GameInitial, game.GamePaused: alpha = ease(0, 1) case game.GamePlaying, game.GameExiting: alpha = ease(1, -1) } // Don't render the menu if it is invisible. if alpha == 0 { return } gl.UniformMatrix4fv(projectionViewMatrixUniform, 1, false, &orthoProjectionViewMatrix[0]) gl.Uniform1f(grayscaleUniform, 0) gl.Uniform1f(brightnessUniform, 0) gl.Uniform1f(alphaUniform, alpha) gl.Uniform1f(mixAmountUniform, 0) menu := g.Menu titleText := menuTitleText[menu.ID] totalHeight := titleText.height * 2 for _, item := range menu.Items { totalHeight += float32(menuItemFontSize) * 2 if !item.SingleChoice() { totalHeight += float32(menuItemFontSize) * 2 } } currentY := (float32(winHeight) + totalHeight) / 2 centerX := func(txt *renderableText) float32 { return (float32(winWidth) - txt.width) / 2 } renderText := func(text *renderableText) { currentY -= text.height text.render(centerX(text), currentY) currentY -= text.height // add spacing for next item } // TODO(btmura): split these out into separate functions renderSlider := func(item *game.MenuItem) { val := strconv.Itoa(item.Slider.Value) var valWidth, valHeight float32 for _, rune := range val { text := menuRuneText[rune] valWidth += text.width if text.height > valHeight { valHeight = text.height } } currentY -= valHeight x := (float32(winWidth) - valWidth) / 2 for _, rune := range val { text := menuRuneText[rune] text.render(x, currentY) x += text.width } currentY -= valHeight } renderMenuItem := func(index int, item *game.MenuItem) { var brightness float32 if menu.FocusedIndex == index { switch { case menu.Selected: brightness = pulse(g.GlobalPulse+fudge, 1, 1, 1) case item.SingleChoice(): brightness = pulse(g.GlobalPulse+fudge, 1, 0.3, 0.06) default: brightness = 1 } } gl.Uniform1f(brightnessUniform, brightness) renderText(menuItemText[item.ID]) switch { case item.Selector != nil: renderText(menuChoiceText[item.Selector.Value()]) case item.Slider != nil: renderSlider(item) } } renderText(titleText) for i, item := range menu.Items { renderMenuItem(i, item) } }
func renderBoard(g *game.Game, fudge float32) bool { if g.Board == nil { return false } b := g.Board metrics := newMetrics(g, fudge) gl.UniformMatrix4fv(projectionViewMatrixUniform, 1, false, &perspectiveProjectionViewMatrix[0]) gl.Uniform3fv(mixColorUniform, 1, &blackColor[0]) globalGrayscale := float32(1) globalDarkness := float32(0.8) var boardDarkness float32 gameEase := func(start, change float32) float32 { return easeOutCubic(g.StateProgress(fudge), start, change) } boardEase := func(start, change float32) float32 { return easeOutCubic(b.StateProgress(fudge), start, change) } switch g.State { case game.GamePlaying: globalGrayscale = gameEase(1, -1) globalDarkness = gameEase(0.8, -0.8) case game.GamePaused: globalGrayscale = gameEase(0, 1) globalDarkness = gameEase(0, 0.8) case game.GameExiting: globalGrayscale = 1 globalDarkness = gameEase(0.8, 1) } switch b.State { case game.BoardEntering: boardDarkness = boardEase(1, -1) case game.BoardExiting: boardDarkness = boardEase(0, 1) } finalDarkness := globalDarkness if finalDarkness < boardDarkness { finalDarkness = boardDarkness } gl.Uniform1f(mixAmountUniform, finalDarkness) gl.Uniform1i(textureUniform, int32(boardTexture)-1) for i := 0; i <= 2; i++ { gl.Uniform1f(grayscaleUniform, globalGrayscale) gl.Uniform1f(brightnessUniform, 0) gl.Uniform1f(alphaUniform, 1) if i == 0 { renderSelector(metrics) } for y, r := range b.Rings { for x, c := range r.Cells { switch i { case 0: // draw opaque objects switch c.Block.State { case game.BlockStatic, game.BlockSwappingFromLeft, game.BlockSwappingFromRight, game.BlockDroppingFromAbove, game.BlockFlashing: renderCellBlock(metrics, c, x, y) case game.BlockCracking, game.BlockCracked: renderCellFragments(metrics, c, x, y) } case 1: // draw transparent objects switch c.Block.State { case game.BlockExploding: renderCellFragments(metrics, c, x, y) } renderMarker(metrics, c.Marker, x, y) } } } } // Render the spare rings. // Set brightness to zero for all spare rings. gl.Uniform1f(brightnessUniform, 0) for y, r := range b.SpareRings { // Set grayscale value. First spare rings becomes colored. Rest are gray. grayscale := float32(1) if y == 0 { grayscale = easeInExpo(b.RiseProgress(fudge), 1, -1) } if grayscale < globalGrayscale { grayscale = globalGrayscale } gl.Uniform1f(grayscaleUniform, grayscale) // Set alpha value. Last spare ring fades in. Rest are opaque. alpha := float32(1) if y == len(b.SpareRings)-1 { alpha = easeInExpo(b.RiseProgress(fudge), 0, 1) } gl.Uniform1f(alphaUniform, alpha) // Render the spare rings below the normal rings. for x, c := range r.Cells { renderCellBlock(metrics, c, x, y+b.RingCount) } } return true }