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 }
func Init() error { if err := gl.Init(); err != nil { return err } log.Printf("OpenGL version: %s", gl.GoStr(gl.GetString(gl.VERSION))) vs, err := asset.String("shader.vert") if err != nil { return err } fs, err := asset.String("shader.frag") if err != nil { return err } program, err := createProgram(vs, fs) if err != nil { return err } gl.UseProgram(program) var shaderErr error uniform := func(name string) int32 { var loc int32 loc, shaderErr = getUniformLocation(program, name) return loc } projectionViewMatrixUniform = uniform("u_projectionViewMatrix") modelMatrixUniform = uniform("u_modelMatrix") normalMatrixUniform = uniform("u_normalMatrix") ambientLightColorUniform = uniform("u_ambientLightColor") directionalLightColorUniform = uniform("u_directionalLightColor") directionalVectorUniform = uniform("u_directionalVector") textureUniform = uniform("u_texture") grayscaleUniform = uniform("u_grayscale") brightnessUniform = uniform("u_brightness") alphaUniform = uniform("u_alpha") mixColorUniform = uniform("u_mixColor") mixAmountUniform = uniform("u_mixAmount") if shaderErr != nil { return shaderErr } vm := newViewMatrix(cameraPosition, targetPosition, up) nm := vm.inverse().transpose() gl.UniformMatrix4fv(normalMatrixUniform, 1, false, &nm[0]) gl.Uniform3fv(ambientLightColorUniform, 1, &ambientLightColor[0]) gl.Uniform3fv(directionalLightColorUniform, 1, &directionalLightColor[0]) gl.Uniform3fv(directionalVectorUniform, 1, &directionalVector[0]) SizeCallback = func(width, height int) { if winWidth == width && winHeight == height { return } log.Printf("window size changed (%dx%d -> %dx%d)", int(winWidth), int(winHeight), width, height) gl.Viewport(0, 0, int32(width), int32(height)) // Calculate new perspective projection view matrix. winWidth, winHeight = width, height fw, fh := float32(width), float32(height) aspect := fw / fh fovRadians := float32(math.Pi) / 3 perspectiveProjectionViewMatrix = vm.mult(newPerspectiveMatrix(fovRadians, aspect, 1, 2000)) // Calculate new ortho projection view matrix. orthoProjectionViewMatrix = newOrthoMatrix(fw, fh, fw /* use width as depth */) } if err := initMeshes(); err != nil { return err } if err := initTextures(); err != nil { return err } gl.Enable(gl.CULL_FACE) gl.CullFace(gl.BACK) gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.ClearColor(0, 0, 0, 0) return nil }