function GameRenderer(state, camera) { this.state = state; this.camera = camera; this.shadowVBO = null; } GameRenderer.prototype.render = function(gl) { var savedMatrix; gl.modelviewMatrix.loadIdentity(); this.camera.apply(gl.modelviewMatrix); this.state.level.draw(gl); this.state.player.draw(gl); this.drawPlayerShadow(gl); } GameRenderer.prototype.drawPlayerShadow = function(gl) { var closestPlatform = null; var playerPosition = this.state.player.position; const playerRadius = this.state.player.radius; if (this.shadowVBO == null) { this.shadowVBO = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.shadowVBO); gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([-0.25,0.01,0.0, 0.0,0.01,0.25, 0.25,0.01,0.0, 0.0,0.01,-0.25]), gl.STATIC_DRAW); this.shadowEBO = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.shadowEBO); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray([0, 1, 2, 2, 3, 0]), gl.STATIC_DRAW); this.indexCount = 6; } for (var platformIndex = 0; platformIndex < this.state.level.platforms.length; platformIndex++) { var platform = this.state.level.platforms[platformIndex]; if (playerPosition.x > platform.left - playerRadius && playerPosition.x < platform.right + playerRadius && playerPosition.z > platform.back - playerRadius && playerPosition.z < platform.front + playerRadius && playerPosition.y >= platform.y && (closestPlatform == null || closestPlatform.y < platform.y)) { closestPlatform = platform; } } for (var trampolineIndex = 0; trampolineIndex < this.state.level.trampolines.length; trampolineIndex++) { var trampoline = this.state.level.trampolines[trampolineIndex]; if (playerPosition.x > trampoline.left - playerRadius && playerPosition.x < trampoline.right + playerRadius && playerPosition.z > trampoline.back - playerRadius && playerPosition.z < trampoline.front + playerRadius && playerPosition.y >= trampoline.y && (closestPlatform == null || closestPlatform.y < trampoline.y)) { closestPlatform = trampoline; } } if (closestPlatform != null) { var savedMatrix; gl.enableVertexAttribArray(0); gl.bindBuffer(gl.ARRAY_BUFFER, this.shadowVBO); gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.shadowEBO); savedMatrix = gl.modelviewMatrix.copy(); gl.modelviewMatrix.translate(this.state.player.position.x, closestPlatform.y, this.state.player.position.z); gl.uniform4f(gl.getUniformLocation(gl.program, "constantColor"), 0.0, 0.0, 0.0, 1.0); gl.uniformMatrix4fv(gl.getUniformLocation(gl.program, "uPMatrix"), false, new WebGLFloatArray(gl.projectionMatrix.m)); gl.uniformMatrix4fv(gl.getUniformLocation(gl.program, "uMVMatrix"), false, new WebGLFloatArray(gl.modelviewMatrix.m)); gl.drawElements(gl.TRIANGLES, this.indexCount, gl.UNSIGNED_SHORT, 0); gl.modelviewMatrix = savedMatrix; } }